OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Moschip MCS814x GPIO support |
||
3 | * |
||
4 | * Copyright (C) 2012, Florian Fainelli <florian@openwrt.org> |
||
5 | * |
||
6 | * Licensed under the GPLv2 |
||
7 | */ |
||
8 | |||
9 | #include <linux/init.h> |
||
10 | #include <linux/module.h> |
||
11 | #include <linux/kernel.h> |
||
12 | #include <linux/slab.h> |
||
13 | #include <linux/platform_device.h> |
||
14 | #include <linux/gpio.h> |
||
15 | #include <linux/io.h> |
||
16 | #include <linux/of.h> |
||
17 | #include <linux/of_address.h> |
||
18 | |||
19 | struct mcs814x_gpio_chip { |
||
20 | void __iomem *regs; |
||
21 | struct gpio_chip chip; |
||
22 | }; |
||
23 | |||
24 | #define GPIO_PIN 0x00 |
||
25 | #define GPIO_DIR 0x04 |
||
26 | |||
27 | #define to_mcs814x_gpio_chip(x) container_of(x, struct mcs814x_gpio_chip, chip) |
||
28 | |||
29 | static int mcs814x_gpio_get(struct gpio_chip *chip, unsigned offset) |
||
30 | { |
||
31 | struct mcs814x_gpio_chip *mcs814x = to_mcs814x_gpio_chip(chip); |
||
32 | |||
33 | return readl_relaxed(mcs814x->regs + GPIO_PIN) & (1 << offset); |
||
34 | } |
||
35 | |||
36 | static void mcs814x_gpio_set(struct gpio_chip *chip, |
||
37 | unsigned offset, int value) |
||
38 | { |
||
39 | struct mcs814x_gpio_chip *mcs814x = to_mcs814x_gpio_chip(chip); |
||
40 | u32 mask; |
||
41 | |||
42 | mask = readl_relaxed(mcs814x->regs + GPIO_PIN); |
||
43 | if (value) |
||
44 | mask |= (1 << offset); |
||
45 | else |
||
46 | mask &= ~(1 << offset); |
||
47 | writel_relaxed(mask, mcs814x->regs + GPIO_PIN); |
||
48 | } |
||
49 | |||
50 | static int mcs814x_gpio_direction_output(struct gpio_chip *chip, |
||
51 | unsigned offset, int value) |
||
52 | { |
||
53 | struct mcs814x_gpio_chip *mcs814x = to_mcs814x_gpio_chip(chip); |
||
54 | u32 mask; |
||
55 | |||
56 | mask = readl_relaxed(mcs814x->regs + GPIO_DIR); |
||
57 | mask &= ~(1 << offset); |
||
58 | writel_relaxed(mask, mcs814x->regs + GPIO_DIR); |
||
59 | |||
60 | return 0; |
||
61 | } |
||
62 | |||
63 | static int mcs814x_gpio_direction_input(struct gpio_chip *chip, |
||
64 | unsigned offset) |
||
65 | { |
||
66 | struct mcs814x_gpio_chip *mcs814x = to_mcs814x_gpio_chip(chip); |
||
67 | u32 mask; |
||
68 | |||
69 | mask = readl_relaxed(mcs814x->regs + GPIO_DIR); |
||
70 | mask |= (1 << offset); |
||
71 | writel_relaxed(mask, mcs814x->regs + GPIO_DIR); |
||
72 | |||
73 | return 0; |
||
74 | } |
||
75 | |||
76 | static int mcs814x_gpio_probe(struct platform_device *pdev) |
||
77 | { |
||
78 | struct resource *res; |
||
79 | struct mcs814x_gpio_chip *mcs814x_chip; |
||
80 | int ret; |
||
81 | const unsigned int *num_gpios; |
||
82 | |||
83 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
||
84 | if (!res) |
||
85 | return -ENODEV; |
||
86 | |||
87 | num_gpios = of_get_property(pdev->dev.of_node, "num-gpios", NULL); |
||
88 | if (!num_gpios) |
||
89 | dev_err(&pdev->dev, "FIXME: no num-gpios property\n"); |
||
90 | |||
91 | mcs814x_chip = kzalloc(sizeof(*mcs814x_chip), GFP_KERNEL); |
||
92 | if (!mcs814x_chip) |
||
93 | return -ENOMEM; |
||
94 | |||
95 | mcs814x_chip->regs = devm_ioremap_resource(&pdev->dev, res); |
||
96 | if (!mcs814x_chip->regs) { |
||
97 | ret = -ENOMEM; |
||
98 | goto out; |
||
99 | } |
||
100 | |||
101 | platform_set_drvdata(pdev, mcs814x_chip); |
||
102 | |||
103 | #ifdef CONFIG_OF_GPIO |
||
104 | mcs814x_chip->chip.of_node = pdev->dev.of_node; |
||
105 | #endif |
||
106 | |||
107 | mcs814x_chip->chip.label = pdev->name; |
||
108 | mcs814x_chip->chip.get = mcs814x_gpio_get; |
||
109 | mcs814x_chip->chip.set = mcs814x_gpio_set; |
||
110 | mcs814x_chip->chip.direction_input = mcs814x_gpio_direction_input; |
||
111 | mcs814x_chip->chip.direction_output = mcs814x_gpio_direction_output; |
||
112 | mcs814x_chip->chip.ngpio = be32_to_cpup(num_gpios); |
||
113 | /* we want dynamic base allocation */ |
||
114 | mcs814x_chip->chip.base = -1; |
||
115 | |||
116 | ret = gpiochip_add(&mcs814x_chip->chip); |
||
117 | if (ret) { |
||
118 | dev_err(&pdev->dev, "failed to register gpiochip\n"); |
||
119 | goto out; |
||
120 | } |
||
121 | |||
122 | return 0; |
||
123 | |||
124 | out: |
||
125 | platform_set_drvdata(pdev, NULL); |
||
126 | kfree(mcs814x_chip); |
||
127 | return ret; |
||
128 | } |
||
129 | |||
130 | static struct of_device_id mcs814x_gpio_ids[] = { |
||
131 | { .compatible = "moschip,mcs814x-gpio" }, |
||
132 | { /* sentinel */ }, |
||
133 | }; |
||
134 | |||
135 | static struct platform_driver mcs814x_gpio_driver = { |
||
136 | .driver = { |
||
137 | .name = "mcs814x-gpio", |
||
138 | .owner = THIS_MODULE, |
||
139 | .of_match_table = mcs814x_gpio_ids, |
||
140 | }, |
||
141 | .probe = mcs814x_gpio_probe, |
||
142 | }; |
||
143 | |||
144 | int __init mcs814x_gpio_init(void) |
||
145 | { |
||
146 | return platform_driver_register(&mcs814x_gpio_driver); |
||
147 | } |
||
148 | postcore_initcall(mcs814x_gpio_init); |