diff options
Diffstat (limited to 'drivers')
64 files changed, 5255 insertions, 2325 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index bf892bd68c1..8ae1f5b1966 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -683,4 +683,17 @@ config GPIO_MSIC | |||
683 | Enable support for GPIO on intel MSIC controllers found in | 683 | Enable support for GPIO on intel MSIC controllers found in |
684 | intel MID devices | 684 | intel MID devices |
685 | 685 | ||
686 | comment "USB GPIO expanders:" | ||
687 | |||
688 | config GPIO_VIPERBOARD | ||
689 | tristate "Viperboard GPIO a & b support" | ||
690 | depends on MFD_VIPERBOARD && USB | ||
691 | help | ||
692 | Say yes here to access the GPIO signals of Nano River | ||
693 | Technologies Viperboard. There are two GPIO chips on the | ||
694 | board: gpioa and gpiob. | ||
695 | See viperboard API specification and Nano | ||
696 | River Tech's viperboard.h for detailed meaning | ||
697 | of the module parameters. | ||
698 | |||
686 | endif | 699 | endif |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 76b34468325..c5aebd008dd 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
@@ -76,6 +76,7 @@ obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o | |||
76 | obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o | 76 | obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o |
77 | obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o | 77 | obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o |
78 | obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o | 78 | obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o |
79 | obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o | ||
79 | obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o | 80 | obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o |
80 | obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o | 81 | obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o |
81 | obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o | 82 | obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o |
diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index a05aacd2777..29b11e9b6a7 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c | |||
@@ -185,7 +185,11 @@ static int da9052_gpio_to_irq(struct gpio_chip *gc, u32 offset) | |||
185 | struct da9052_gpio *gpio = to_da9052_gpio(gc); | 185 | struct da9052_gpio *gpio = to_da9052_gpio(gc); |
186 | struct da9052 *da9052 = gpio->da9052; | 186 | struct da9052 *da9052 = gpio->da9052; |
187 | 187 | ||
188 | return da9052->irq_base + DA9052_IRQ_GPI0 + offset; | 188 | int irq; |
189 | |||
190 | irq = regmap_irq_get_virq(da9052->irq_data, DA9052_IRQ_GPI0 + offset); | ||
191 | |||
192 | return irq; | ||
189 | } | 193 | } |
190 | 194 | ||
191 | static struct gpio_chip reference_gp = { | 195 | static struct gpio_chip reference_gp = { |
diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c index c1b82da5650..29e8e750bd4 100644 --- a/drivers/gpio/gpio-tps6586x.c +++ b/drivers/gpio/gpio-tps6586x.c | |||
@@ -80,6 +80,14 @@ static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset, | |||
80 | val, mask); | 80 | val, mask); |
81 | } | 81 | } |
82 | 82 | ||
83 | static int tps6586x_gpio_to_irq(struct gpio_chip *gc, unsigned offset) | ||
84 | { | ||
85 | struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc); | ||
86 | |||
87 | return tps6586x_irq_get_virq(tps6586x_gpio->parent, | ||
88 | TPS6586X_INT_PLDO_0 + offset); | ||
89 | } | ||
90 | |||
83 | static int tps6586x_gpio_probe(struct platform_device *pdev) | 91 | static int tps6586x_gpio_probe(struct platform_device *pdev) |
84 | { | 92 | { |
85 | struct tps6586x_platform_data *pdata; | 93 | struct tps6586x_platform_data *pdata; |
@@ -106,6 +114,7 @@ static int tps6586x_gpio_probe(struct platform_device *pdev) | |||
106 | tps6586x_gpio->gpio_chip.direction_output = tps6586x_gpio_output; | 114 | tps6586x_gpio->gpio_chip.direction_output = tps6586x_gpio_output; |
107 | tps6586x_gpio->gpio_chip.set = tps6586x_gpio_set; | 115 | tps6586x_gpio->gpio_chip.set = tps6586x_gpio_set; |
108 | tps6586x_gpio->gpio_chip.get = tps6586x_gpio_get; | 116 | tps6586x_gpio->gpio_chip.get = tps6586x_gpio_get; |
117 | tps6586x_gpio->gpio_chip.to_irq = tps6586x_gpio_to_irq; | ||
109 | 118 | ||
110 | #ifdef CONFIG_OF_GPIO | 119 | #ifdef CONFIG_OF_GPIO |
111 | tps6586x_gpio->gpio_chip.of_node = pdev->dev.parent->of_node; | 120 | tps6586x_gpio->gpio_chip.of_node = pdev->dev.parent->of_node; |
diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 00329f2fc05..9572aa137e6 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c | |||
@@ -355,13 +355,13 @@ static struct gpio_chip twl_gpiochip = { | |||
355 | 355 | ||
356 | static int gpio_twl4030_pulls(u32 ups, u32 downs) | 356 | static int gpio_twl4030_pulls(u32 ups, u32 downs) |
357 | { | 357 | { |
358 | u8 message[6]; | 358 | u8 message[5]; |
359 | unsigned i, gpio_bit; | 359 | unsigned i, gpio_bit; |
360 | 360 | ||
361 | /* For most pins, a pulldown was enabled by default. | 361 | /* For most pins, a pulldown was enabled by default. |
362 | * We should have data that's specific to this board. | 362 | * We should have data that's specific to this board. |
363 | */ | 363 | */ |
364 | for (gpio_bit = 1, i = 1; i < 6; i++) { | 364 | for (gpio_bit = 1, i = 0; i < 5; i++) { |
365 | u8 bit_mask; | 365 | u8 bit_mask; |
366 | unsigned j; | 366 | unsigned j; |
367 | 367 | ||
@@ -380,16 +380,16 @@ static int gpio_twl4030_pulls(u32 ups, u32 downs) | |||
380 | 380 | ||
381 | static int gpio_twl4030_debounce(u32 debounce, u8 mmc_cd) | 381 | static int gpio_twl4030_debounce(u32 debounce, u8 mmc_cd) |
382 | { | 382 | { |
383 | u8 message[4]; | 383 | u8 message[3]; |
384 | 384 | ||
385 | /* 30 msec of debouncing is always used for MMC card detect, | 385 | /* 30 msec of debouncing is always used for MMC card detect, |
386 | * and is optional for everything else. | 386 | * and is optional for everything else. |
387 | */ | 387 | */ |
388 | message[1] = (debounce & 0xff) | (mmc_cd & 0x03); | 388 | message[0] = (debounce & 0xff) | (mmc_cd & 0x03); |
389 | debounce >>= 8; | 389 | debounce >>= 8; |
390 | message[2] = (debounce & 0xff); | 390 | message[1] = (debounce & 0xff); |
391 | debounce >>= 8; | 391 | debounce >>= 8; |
392 | message[3] = (debounce & 0x03); | 392 | message[2] = (debounce & 0x03); |
393 | 393 | ||
394 | return twl_i2c_write(TWL4030_MODULE_GPIO, message, | 394 | return twl_i2c_write(TWL4030_MODULE_GPIO, message, |
395 | REG_GPIO_DEBEN1, 3); | 395 | REG_GPIO_DEBEN1, 3); |
diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c new file mode 100644 index 00000000000..13772996cf2 --- /dev/null +++ b/drivers/gpio/gpio-viperboard.c | |||
@@ -0,0 +1,517 @@ | |||
1 | /* | ||
2 | * Nano River Technologies viperboard GPIO lib driver | ||
3 | * | ||
4 | * (C) 2012 by Lemonage GmbH | ||
5 | * Author: Lars Poeschel <poeschel@lemonage.de> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/mutex.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | |||
23 | #include <linux/usb.h> | ||
24 | #include <linux/gpio.h> | ||
25 | |||
26 | #include <linux/mfd/viperboard.h> | ||
27 | |||
28 | #define VPRBRD_GPIOA_CLK_1MHZ 0 | ||
29 | #define VPRBRD_GPIOA_CLK_100KHZ 1 | ||
30 | #define VPRBRD_GPIOA_CLK_10KHZ 2 | ||
31 | #define VPRBRD_GPIOA_CLK_1KHZ 3 | ||
32 | #define VPRBRD_GPIOA_CLK_100HZ 4 | ||
33 | #define VPRBRD_GPIOA_CLK_10HZ 5 | ||
34 | |||
35 | #define VPRBRD_GPIOA_FREQ_DEFAULT 1000 | ||
36 | |||
37 | #define VPRBRD_GPIOA_CMD_CONT 0x00 | ||
38 | #define VPRBRD_GPIOA_CMD_PULSE 0x01 | ||
39 | #define VPRBRD_GPIOA_CMD_PWM 0x02 | ||
40 | #define VPRBRD_GPIOA_CMD_SETOUT 0x03 | ||
41 | #define VPRBRD_GPIOA_CMD_SETIN 0x04 | ||
42 | #define VPRBRD_GPIOA_CMD_SETINT 0x05 | ||
43 | #define VPRBRD_GPIOA_CMD_GETIN 0x06 | ||
44 | |||
45 | #define VPRBRD_GPIOB_CMD_SETDIR 0x00 | ||
46 | #define VPRBRD_GPIOB_CMD_SETVAL 0x01 | ||
47 | |||
48 | struct vprbrd_gpioa_msg { | ||
49 | u8 cmd; | ||
50 | u8 clk; | ||
51 | u8 offset; | ||
52 | u8 t1; | ||
53 | u8 t2; | ||
54 | u8 invert; | ||
55 | u8 pwmlevel; | ||
56 | u8 outval; | ||
57 | u8 risefall; | ||
58 | u8 answer; | ||
59 | u8 __fill; | ||
60 | } __packed; | ||
61 | |||
62 | struct vprbrd_gpiob_msg { | ||
63 | u8 cmd; | ||
64 | u16 val; | ||
65 | u16 mask; | ||
66 | } __packed; | ||
67 | |||
68 | struct vprbrd_gpio { | ||
69 | struct gpio_chip gpioa; /* gpio a related things */ | ||
70 | u32 gpioa_out; | ||
71 | u32 gpioa_val; | ||
72 | struct gpio_chip gpiob; /* gpio b related things */ | ||
73 | u32 gpiob_out; | ||
74 | u32 gpiob_val; | ||
75 | struct vprbrd *vb; | ||
76 | }; | ||
77 | |||
78 | /* gpioa sampling clock module parameter */ | ||
79 | static unsigned char gpioa_clk; | ||
80 | static unsigned int gpioa_freq = VPRBRD_GPIOA_FREQ_DEFAULT; | ||
81 | module_param(gpioa_freq, uint, 0); | ||
82 | MODULE_PARM_DESC(gpioa_freq, | ||
83 | "gpio-a sampling freq in Hz (default is 1000Hz) valid values: 10, 100, 1000, 10000, 100000, 1000000"); | ||
84 | |||
85 | /* ----- begin of gipo a chip -------------------------------------------- */ | ||
86 | |||
87 | static int vprbrd_gpioa_get(struct gpio_chip *chip, | ||
88 | unsigned offset) | ||
89 | { | ||
90 | int ret, answer, error = 0; | ||
91 | struct vprbrd_gpio *gpio = | ||
92 | container_of(chip, struct vprbrd_gpio, gpioa); | ||
93 | struct vprbrd *vb = gpio->vb; | ||
94 | struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf; | ||
95 | |||
96 | /* if io is set to output, just return the saved value */ | ||
97 | if (gpio->gpioa_out & (1 << offset)) | ||
98 | return gpio->gpioa_val & (1 << offset); | ||
99 | |||
100 | mutex_lock(&vb->lock); | ||
101 | |||
102 | gamsg->cmd = VPRBRD_GPIOA_CMD_GETIN; | ||
103 | gamsg->clk = 0x00; | ||
104 | gamsg->offset = offset; | ||
105 | gamsg->t1 = 0x00; | ||
106 | gamsg->t2 = 0x00; | ||
107 | gamsg->invert = 0x00; | ||
108 | gamsg->pwmlevel = 0x00; | ||
109 | gamsg->outval = 0x00; | ||
110 | gamsg->risefall = 0x00; | ||
111 | gamsg->answer = 0x00; | ||
112 | gamsg->__fill = 0x00; | ||
113 | |||
114 | ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0), | ||
115 | VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000, | ||
116 | 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg), | ||
117 | VPRBRD_USB_TIMEOUT_MS); | ||
118 | if (ret != sizeof(struct vprbrd_gpioa_msg)) | ||
119 | error = -EREMOTEIO; | ||
120 | |||
121 | ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0), | ||
122 | VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_IN, 0x0000, | ||
123 | 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg), | ||
124 | VPRBRD_USB_TIMEOUT_MS); | ||
125 | answer = gamsg->answer & 0x01; | ||
126 | |||
127 | mutex_unlock(&vb->lock); | ||
128 | |||
129 | if (ret != sizeof(struct vprbrd_gpioa_msg)) | ||
130 | error = -EREMOTEIO; | ||
131 | |||
132 | if (error) | ||
133 | return error; | ||
134 | |||
135 | return answer; | ||
136 | } | ||
137 | |||
138 | static void vprbrd_gpioa_set(struct gpio_chip *chip, | ||
139 | unsigned offset, int value) | ||
140 | { | ||
141 | int ret; | ||
142 | struct vprbrd_gpio *gpio = | ||
143 | container_of(chip, struct vprbrd_gpio, gpioa); | ||
144 | struct vprbrd *vb = gpio->vb; | ||
145 | struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf; | ||
146 | |||
147 | if (gpio->gpioa_out & (1 << offset)) { | ||
148 | if (value) | ||
149 | gpio->gpioa_val |= (1 << offset); | ||
150 | else | ||
151 | gpio->gpioa_val &= ~(1 << offset); | ||
152 | |||
153 | mutex_lock(&vb->lock); | ||
154 | |||
155 | gamsg->cmd = VPRBRD_GPIOA_CMD_SETOUT; | ||
156 | gamsg->clk = 0x00; | ||
157 | gamsg->offset = offset; | ||
158 | gamsg->t1 = 0x00; | ||
159 | gamsg->t2 = 0x00; | ||
160 | gamsg->invert = 0x00; | ||
161 | gamsg->pwmlevel = 0x00; | ||
162 | gamsg->outval = value; | ||
163 | gamsg->risefall = 0x00; | ||
164 | gamsg->answer = 0x00; | ||
165 | gamsg->__fill = 0x00; | ||
166 | |||
167 | ret = usb_control_msg(vb->usb_dev, | ||
168 | usb_sndctrlpipe(vb->usb_dev, 0), | ||
169 | VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, | ||
170 | 0x0000, 0x0000, gamsg, | ||
171 | sizeof(struct vprbrd_gpioa_msg), VPRBRD_USB_TIMEOUT_MS); | ||
172 | |||
173 | mutex_unlock(&vb->lock); | ||
174 | |||
175 | if (ret != sizeof(struct vprbrd_gpioa_msg)) | ||
176 | dev_err(chip->dev, "usb error setting pin value\n"); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | static int vprbrd_gpioa_direction_input(struct gpio_chip *chip, | ||
181 | unsigned offset) | ||
182 | { | ||
183 | int ret; | ||
184 | struct vprbrd_gpio *gpio = | ||
185 | container_of(chip, struct vprbrd_gpio, gpioa); | ||
186 | struct vprbrd *vb = gpio->vb; | ||
187 | struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf; | ||
188 | |||
189 | gpio->gpioa_out &= ~(1 << offset); | ||
190 | |||
191 | mutex_lock(&vb->lock); | ||
192 | |||
193 | gamsg->cmd = VPRBRD_GPIOA_CMD_SETIN; | ||
194 | gamsg->clk = gpioa_clk; | ||
195 | gamsg->offset = offset; | ||
196 | gamsg->t1 = 0x00; | ||
197 | gamsg->t2 = 0x00; | ||
198 | gamsg->invert = 0x00; | ||
199 | gamsg->pwmlevel = 0x00; | ||
200 | gamsg->outval = 0x00; | ||
201 | gamsg->risefall = 0x00; | ||
202 | gamsg->answer = 0x00; | ||
203 | gamsg->__fill = 0x00; | ||
204 | |||
205 | ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0), | ||
206 | VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000, | ||
207 | 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg), | ||
208 | VPRBRD_USB_TIMEOUT_MS); | ||
209 | |||
210 | mutex_unlock(&vb->lock); | ||
211 | |||
212 | if (ret != sizeof(struct vprbrd_gpioa_msg)) | ||
213 | return -EREMOTEIO; | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static int vprbrd_gpioa_direction_output(struct gpio_chip *chip, | ||
219 | unsigned offset, int value) | ||
220 | { | ||
221 | int ret; | ||
222 | struct vprbrd_gpio *gpio = | ||
223 | container_of(chip, struct vprbrd_gpio, gpioa); | ||
224 | struct vprbrd *vb = gpio->vb; | ||
225 | struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf; | ||
226 | |||
227 | gpio->gpioa_out |= (1 << offset); | ||
228 | if (value) | ||
229 | gpio->gpioa_val |= (1 << offset); | ||
230 | else | ||
231 | gpio->gpioa_val &= ~(1 << offset); | ||
232 | |||
233 | mutex_lock(&vb->lock); | ||
234 | |||
235 | gamsg->cmd = VPRBRD_GPIOA_CMD_SETOUT; | ||
236 | gamsg->clk = 0x00; | ||
237 | gamsg->offset = offset; | ||
238 | gamsg->t1 = 0x00; | ||
239 | gamsg->t2 = 0x00; | ||
240 | gamsg->invert = 0x00; | ||
241 | gamsg->pwmlevel = 0x00; | ||
242 | gamsg->outval = value; | ||
243 | gamsg->risefall = 0x00; | ||
244 | gamsg->answer = 0x00; | ||
245 | gamsg->__fill = 0x00; | ||
246 | |||
247 | ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0), | ||
248 | VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000, | ||
249 | 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg), | ||
250 | VPRBRD_USB_TIMEOUT_MS); | ||
251 | |||
252 | mutex_unlock(&vb->lock); | ||
253 | |||
254 | if (ret != sizeof(struct vprbrd_gpioa_msg)) | ||
255 | return -EREMOTEIO; | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | /* ----- end of gpio a chip ---------------------------------------------- */ | ||
261 | |||
262 | /* ----- begin of gipo b chip -------------------------------------------- */ | ||
263 | |||
264 | static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned offset, | ||
265 | unsigned dir) | ||
266 | { | ||
267 | struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf; | ||
268 | int ret; | ||
269 | |||
270 | gbmsg->cmd = VPRBRD_GPIOB_CMD_SETDIR; | ||
271 | gbmsg->val = cpu_to_be16(dir << offset); | ||
272 | gbmsg->mask = cpu_to_be16(0x0001 << offset); | ||
273 | |||
274 | ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0), | ||
275 | VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_OUT, 0x0000, | ||
276 | 0x0000, gbmsg, sizeof(struct vprbrd_gpiob_msg), | ||
277 | VPRBRD_USB_TIMEOUT_MS); | ||
278 | |||
279 | if (ret != sizeof(struct vprbrd_gpiob_msg)) | ||
280 | return -EREMOTEIO; | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int vprbrd_gpiob_get(struct gpio_chip *chip, | ||
286 | unsigned offset) | ||
287 | { | ||
288 | int ret; | ||
289 | u16 val; | ||
290 | struct vprbrd_gpio *gpio = | ||
291 | container_of(chip, struct vprbrd_gpio, gpiob); | ||
292 | struct vprbrd *vb = gpio->vb; | ||
293 | struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf; | ||
294 | |||
295 | /* if io is set to output, just return the saved value */ | ||
296 | if (gpio->gpiob_out & (1 << offset)) | ||
297 | return gpio->gpiob_val & (1 << offset); | ||
298 | |||
299 | mutex_lock(&vb->lock); | ||
300 | |||
301 | ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0), | ||
302 | VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_IN, 0x0000, | ||
303 | 0x0000, gbmsg, sizeof(struct vprbrd_gpiob_msg), | ||
304 | VPRBRD_USB_TIMEOUT_MS); | ||
305 | val = gbmsg->val; | ||
306 | |||
307 | mutex_unlock(&vb->lock); | ||
308 | |||
309 | if (ret != sizeof(struct vprbrd_gpiob_msg)) | ||
310 | return ret; | ||
311 | |||
312 | /* cache the read values */ | ||
313 | gpio->gpiob_val = be16_to_cpu(val); | ||
314 | |||
315 | return (gpio->gpiob_val >> offset) & 0x1; | ||
316 | } | ||
317 | |||
318 | static void vprbrd_gpiob_set(struct gpio_chip *chip, | ||
319 | unsigned offset, int value) | ||
320 | { | ||
321 | int ret; | ||
322 | struct vprbrd_gpio *gpio = | ||
323 | container_of(chip, struct vprbrd_gpio, gpiob); | ||
324 | struct vprbrd *vb = gpio->vb; | ||
325 | struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf; | ||
326 | |||
327 | if (gpio->gpiob_out & (1 << offset)) { | ||
328 | if (value) | ||
329 | gpio->gpiob_val |= (1 << offset); | ||
330 | else | ||
331 | gpio->gpiob_val &= ~(1 << offset); | ||
332 | |||
333 | mutex_lock(&vb->lock); | ||
334 | |||
335 | gbmsg->cmd = VPRBRD_GPIOB_CMD_SETVAL; | ||
336 | gbmsg->val = cpu_to_be16(value << offset); | ||
337 | gbmsg->mask = cpu_to_be16(0x0001 << offset); | ||
338 | |||
339 | ret = usb_control_msg(vb->usb_dev, | ||
340 | usb_sndctrlpipe(vb->usb_dev, 0), | ||
341 | VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_OUT, | ||
342 | 0x0000, 0x0000, gbmsg, | ||
343 | sizeof(struct vprbrd_gpiob_msg), VPRBRD_USB_TIMEOUT_MS); | ||
344 | |||
345 | mutex_unlock(&vb->lock); | ||
346 | |||
347 | if (ret != sizeof(struct vprbrd_gpiob_msg)) | ||
348 | dev_err(chip->dev, "usb error setting pin value\n"); | ||
349 | } | ||
350 | } | ||
351 | |||
352 | static int vprbrd_gpiob_direction_input(struct gpio_chip *chip, | ||
353 | unsigned offset) | ||
354 | { | ||
355 | int ret; | ||
356 | struct vprbrd_gpio *gpio = | ||
357 | container_of(chip, struct vprbrd_gpio, gpiob); | ||
358 | struct vprbrd *vb = gpio->vb; | ||
359 | |||
360 | gpio->gpiob_out &= ~(1 << offset); | ||
361 | |||
362 | mutex_lock(&vb->lock); | ||
363 | |||
364 | ret = vprbrd_gpiob_setdir(vb, offset, 0); | ||
365 | |||
366 | mutex_unlock(&vb->lock); | ||
367 | |||
368 | if (ret) | ||
369 | dev_err(chip->dev, "usb error setting pin to input\n"); | ||
370 | |||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | static int vprbrd_gpiob_direction_output(struct gpio_chip *chip, | ||
375 | unsigned offset, int value) | ||
376 | { | ||
377 | int ret; | ||
378 | struct vprbrd_gpio *gpio = | ||
379 | container_of(chip, struct vprbrd_gpio, gpiob); | ||
380 | struct vprbrd *vb = gpio->vb; | ||
381 | |||
382 | gpio->gpiob_out |= (1 << offset); | ||
383 | if (value) | ||
384 | gpio->gpiob_val |= (1 << offset); | ||
385 | else | ||
386 | gpio->gpiob_val &= ~(1 << offset); | ||
387 | |||
388 | mutex_lock(&vb->lock); | ||
389 | |||
390 | ret = vprbrd_gpiob_setdir(vb, offset, 1); | ||
391 | if (ret) | ||
392 | dev_err(chip->dev, "usb error setting pin to output\n"); | ||
393 | |||
394 | mutex_unlock(&vb->lock); | ||
395 | |||
396 | vprbrd_gpiob_set(chip, offset, value); | ||
397 | |||
398 | return ret; | ||
399 | } | ||
400 | |||
401 | /* ----- end of gpio b chip ---------------------------------------------- */ | ||
402 | |||
403 | static int __devinit vprbrd_gpio_probe(struct platform_device *pdev) | ||
404 | { | ||
405 | struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent); | ||
406 | struct vprbrd_gpio *vb_gpio; | ||
407 | int ret; | ||
408 | |||
409 | vb_gpio = devm_kzalloc(&pdev->dev, sizeof(*vb_gpio), GFP_KERNEL); | ||
410 | if (vb_gpio == NULL) | ||
411 | return -ENOMEM; | ||
412 | |||
413 | vb_gpio->vb = vb; | ||
414 | /* registering gpio a */ | ||
415 | vb_gpio->gpioa.label = "viperboard gpio a"; | ||
416 | vb_gpio->gpioa.dev = &pdev->dev; | ||
417 | vb_gpio->gpioa.owner = THIS_MODULE; | ||
418 | vb_gpio->gpioa.base = -1; | ||
419 | vb_gpio->gpioa.ngpio = 16; | ||
420 | vb_gpio->gpioa.can_sleep = 1; | ||
421 | vb_gpio->gpioa.set = vprbrd_gpioa_set; | ||
422 | vb_gpio->gpioa.get = vprbrd_gpioa_get; | ||
423 | vb_gpio->gpioa.direction_input = vprbrd_gpioa_direction_input; | ||
424 | vb_gpio->gpioa.direction_output = vprbrd_gpioa_direction_output; | ||
425 | ret = gpiochip_add(&vb_gpio->gpioa); | ||
426 | if (ret < 0) { | ||
427 | dev_err(vb_gpio->gpioa.dev, "could not add gpio a"); | ||
428 | goto err_gpioa; | ||
429 | } | ||
430 | |||
431 | /* registering gpio b */ | ||
432 | vb_gpio->gpiob.label = "viperboard gpio b"; | ||
433 | vb_gpio->gpiob.dev = &pdev->dev; | ||
434 | vb_gpio->gpiob.owner = THIS_MODULE; | ||
435 | vb_gpio->gpiob.base = -1; | ||
436 | vb_gpio->gpiob.ngpio = 16; | ||
437 | vb_gpio->gpiob.can_sleep = 1; | ||
438 | vb_gpio->gpiob.set = vprbrd_gpiob_set; | ||
439 | vb_gpio->gpiob.get = vprbrd_gpiob_get; | ||
440 | vb_gpio->gpiob.direction_input = vprbrd_gpiob_direction_input; | ||
441 | vb_gpio->gpiob.direction_output = vprbrd_gpiob_direction_output; | ||
442 | ret = gpiochip_add(&vb_gpio->gpiob); | ||
443 | if (ret < 0) { | ||
444 | dev_err(vb_gpio->gpiob.dev, "could not add gpio b"); | ||
445 | goto err_gpiob; | ||
446 | } | ||
447 | |||
448 | platform_set_drvdata(pdev, vb_gpio); | ||
449 | |||
450 | return ret; | ||
451 | |||
452 | err_gpiob: | ||
453 | ret = gpiochip_remove(&vb_gpio->gpioa); | ||
454 | |||
455 | err_gpioa: | ||
456 | return ret; | ||
457 | } | ||
458 | |||
459 | static int __devexit vprbrd_gpio_remove(struct platform_device *pdev) | ||
460 | { | ||
461 | struct vprbrd_gpio *vb_gpio = platform_get_drvdata(pdev); | ||
462 | int ret; | ||
463 | |||
464 | ret = gpiochip_remove(&vb_gpio->gpiob); | ||
465 | if (ret == 0) | ||
466 | ret = gpiochip_remove(&vb_gpio->gpioa); | ||
467 | |||
468 | return ret; | ||
469 | } | ||
470 | |||
471 | static struct platform_driver vprbrd_gpio_driver = { | ||
472 | .driver.name = "viperboard-gpio", | ||
473 | .driver.owner = THIS_MODULE, | ||
474 | .probe = vprbrd_gpio_probe, | ||
475 | .remove = __devexit_p(vprbrd_gpio_remove), | ||
476 | }; | ||
477 | |||
478 | static int __init vprbrd_gpio_init(void) | ||
479 | { | ||
480 | switch (gpioa_freq) { | ||
481 | case 1000000: | ||
482 | gpioa_clk = VPRBRD_GPIOA_CLK_1MHZ; | ||
483 | break; | ||
484 | case 100000: | ||
485 | gpioa_clk = VPRBRD_GPIOA_CLK_100KHZ; | ||
486 | break; | ||
487 | case 10000: | ||
488 | gpioa_clk = VPRBRD_GPIOA_CLK_10KHZ; | ||
489 | break; | ||
490 | case 1000: | ||
491 | gpioa_clk = VPRBRD_GPIOA_CLK_1KHZ; | ||
492 | break; | ||
493 | case 100: | ||
494 | gpioa_clk = VPRBRD_GPIOA_CLK_100HZ; | ||
495 | break; | ||
496 | case 10: | ||
497 | gpioa_clk = VPRBRD_GPIOA_CLK_10HZ; | ||
498 | break; | ||
499 | default: | ||
500 | pr_warn("invalid gpioa_freq (%d)\n", gpioa_freq); | ||
501 | gpioa_clk = VPRBRD_GPIOA_CLK_1KHZ; | ||
502 | } | ||
503 | |||
504 | return platform_driver_register(&vprbrd_gpio_driver); | ||
505 | } | ||
506 | subsys_initcall(vprbrd_gpio_init); | ||
507 | |||
508 | static void __exit vprbrd_gpio_exit(void) | ||
509 | { | ||
510 | platform_driver_unregister(&vprbrd_gpio_driver); | ||
511 | } | ||
512 | module_exit(vprbrd_gpio_exit); | ||
513 | |||
514 | MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>"); | ||
515 | MODULE_DESCRIPTION("GPIO driver for Nano River Techs Viperboard"); | ||
516 | MODULE_LICENSE("GPL"); | ||
517 | MODULE_ALIAS("platform:viperboard-gpio"); | ||
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index e9df4612b7e..c7bff51fe52 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
@@ -818,6 +818,16 @@ config I2C_TINY_USB | |||
818 | This driver can also be built as a module. If so, the module | 818 | This driver can also be built as a module. If so, the module |
819 | will be called i2c-tiny-usb. | 819 | will be called i2c-tiny-usb. |
820 | 820 | ||
821 | config I2C_VIPERBOARD | ||
822 | tristate "Viperboard I2C master support" | ||
823 | depends on MFD_VIPERBOARD && USB | ||
824 | help | ||
825 | Say yes here to access the I2C part of the Nano River | ||
826 | Technologies Viperboard as I2C master. | ||
827 | See viperboard API specification and Nano | ||
828 | River Tech's viperboard.h for detailed meaning | ||
829 | of the module parameters. | ||
830 | |||
821 | comment "Other I2C/SMBus bus drivers" | 831 | comment "Other I2C/SMBus bus drivers" |
822 | 832 | ||
823 | config I2C_ACORN | 833 | config I2C_ACORN |
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 395b516ffa0..e5cb209d276 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile | |||
@@ -79,6 +79,7 @@ obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o | |||
79 | obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o | 79 | obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o |
80 | obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o | 80 | obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o |
81 | obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o | 81 | obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o |
82 | obj-$(CONFIG_I2C_VIPERBOARD) += i2c-viperboard.o | ||
82 | 83 | ||
83 | # Other I2C/SMBus bus drivers | 84 | # Other I2C/SMBus bus drivers |
84 | obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o | 85 | obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o |
diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c new file mode 100644 index 00000000000..f5fa20dea90 --- /dev/null +++ b/drivers/i2c/busses/i2c-viperboard.c | |||
@@ -0,0 +1,480 @@ | |||
1 | /* | ||
2 | * Nano River Technologies viperboard i2c master driver | ||
3 | * | ||
4 | * (C) 2012 by Lemonage GmbH | ||
5 | * Author: Lars Poeschel <poeschel@lemonage.de> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/mutex.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | |||
23 | #include <linux/usb.h> | ||
24 | #include <linux/i2c.h> | ||
25 | |||
26 | #include <linux/mfd/viperboard.h> | ||
27 | |||
28 | struct vprbrd_i2c { | ||
29 | struct i2c_adapter i2c; | ||
30 | u8 bus_freq_param; | ||
31 | }; | ||
32 | |||
33 | /* i2c bus frequency module parameter */ | ||
34 | static u8 i2c_bus_param; | ||
35 | static unsigned int i2c_bus_freq = 100; | ||
36 | module_param(i2c_bus_freq, int, 0); | ||
37 | MODULE_PARM_DESC(i2c_bus_freq, | ||
38 | "i2c bus frequency in khz (default is 100) valid values: 10, 100, 200, 400, 1000, 3000, 6000"); | ||
39 | |||
40 | static int vprbrd_i2c_status(struct i2c_adapter *i2c, | ||
41 | struct vprbrd_i2c_status *status, bool prev_error) | ||
42 | { | ||
43 | u16 bytes_xfer; | ||
44 | int ret; | ||
45 | struct vprbrd *vb = (struct vprbrd *)i2c->algo_data; | ||
46 | |||
47 | /* check for protocol error */ | ||
48 | bytes_xfer = sizeof(struct vprbrd_i2c_status); | ||
49 | |||
50 | ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0), | ||
51 | VPRBRD_USB_REQUEST_I2C, VPRBRD_USB_TYPE_IN, 0x0000, 0x0000, | ||
52 | status, bytes_xfer, VPRBRD_USB_TIMEOUT_MS); | ||
53 | |||
54 | if (ret != bytes_xfer) | ||
55 | prev_error = true; | ||
56 | |||
57 | if (prev_error) { | ||
58 | dev_err(&i2c->dev, "failure in usb communication\n"); | ||
59 | return -EREMOTEIO; | ||
60 | } | ||
61 | |||
62 | dev_dbg(&i2c->dev, " status = %d\n", status->status); | ||
63 | if (status->status != 0x00) { | ||
64 | dev_err(&i2c->dev, "failure: i2c protocol error\n"); | ||
65 | return -EPROTO; | ||
66 | } | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | static int vprbrd_i2c_receive(struct usb_device *usb_dev, | ||
71 | struct vprbrd_i2c_read_msg *rmsg, int bytes_xfer) | ||
72 | { | ||
73 | int ret, bytes_actual; | ||
74 | int error = 0; | ||
75 | |||
76 | /* send the read request */ | ||
77 | ret = usb_bulk_msg(usb_dev, | ||
78 | usb_sndbulkpipe(usb_dev, VPRBRD_EP_OUT), rmsg, | ||
79 | sizeof(struct vprbrd_i2c_read_hdr), &bytes_actual, | ||
80 | VPRBRD_USB_TIMEOUT_MS); | ||
81 | |||
82 | if ((ret < 0) | ||
83 | || (bytes_actual != sizeof(struct vprbrd_i2c_read_hdr))) { | ||
84 | dev_err(&usb_dev->dev, "failure transmitting usb\n"); | ||
85 | error = -EREMOTEIO; | ||
86 | } | ||
87 | |||
88 | /* read the actual data */ | ||
89 | ret = usb_bulk_msg(usb_dev, | ||
90 | usb_rcvbulkpipe(usb_dev, VPRBRD_EP_IN), rmsg, | ||
91 | bytes_xfer, &bytes_actual, VPRBRD_USB_TIMEOUT_MS); | ||
92 | |||
93 | if ((ret < 0) || (bytes_xfer != bytes_actual)) { | ||
94 | dev_err(&usb_dev->dev, "failure receiving usb\n"); | ||
95 | error = -EREMOTEIO; | ||
96 | } | ||
97 | return error; | ||
98 | } | ||
99 | |||
100 | static int vprbrd_i2c_addr(struct usb_device *usb_dev, | ||
101 | struct vprbrd_i2c_addr_msg *amsg) | ||
102 | { | ||
103 | int ret, bytes_actual; | ||
104 | |||
105 | ret = usb_bulk_msg(usb_dev, | ||
106 | usb_sndbulkpipe(usb_dev, VPRBRD_EP_OUT), amsg, | ||
107 | sizeof(struct vprbrd_i2c_addr_msg), &bytes_actual, | ||
108 | VPRBRD_USB_TIMEOUT_MS); | ||
109 | |||
110 | if ((ret < 0) || | ||
111 | (sizeof(struct vprbrd_i2c_addr_msg) != bytes_actual)) { | ||
112 | dev_err(&usb_dev->dev, "failure transmitting usb\n"); | ||
113 | return -EREMOTEIO; | ||
114 | } | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static int vprbrd_i2c_read(struct vprbrd *vb, struct i2c_msg *msg) | ||
119 | { | ||
120 | int ret; | ||
121 | u16 remain_len, bytes_xfer, len1, len2, | ||
122 | start = 0x0000; | ||
123 | struct vprbrd_i2c_read_msg *rmsg = | ||
124 | (struct vprbrd_i2c_read_msg *)vb->buf; | ||
125 | |||
126 | remain_len = msg->len; | ||
127 | rmsg->header.cmd = VPRBRD_I2C_CMD_READ; | ||
128 | while (remain_len > 0) { | ||
129 | rmsg->header.addr = cpu_to_le16(start + 0x4000); | ||
130 | if (remain_len <= 255) { | ||
131 | len1 = remain_len; | ||
132 | len2 = 0x00; | ||
133 | rmsg->header.len0 = remain_len; | ||
134 | rmsg->header.len1 = 0x00; | ||
135 | rmsg->header.len2 = 0x00; | ||
136 | rmsg->header.len3 = 0x00; | ||
137 | rmsg->header.len4 = 0x00; | ||
138 | rmsg->header.len5 = 0x00; | ||
139 | remain_len = 0; | ||
140 | } else if (remain_len <= 510) { | ||
141 | len1 = remain_len; | ||
142 | len2 = 0x00; | ||
143 | rmsg->header.len0 = remain_len - 255; | ||
144 | rmsg->header.len1 = 0xff; | ||
145 | rmsg->header.len2 = 0x00; | ||
146 | rmsg->header.len3 = 0x00; | ||
147 | rmsg->header.len4 = 0x00; | ||
148 | rmsg->header.len5 = 0x00; | ||
149 | remain_len = 0; | ||
150 | } else if (remain_len <= 512) { | ||
151 | len1 = remain_len; | ||
152 | len2 = 0x00; | ||
153 | rmsg->header.len0 = remain_len - 510; | ||
154 | rmsg->header.len1 = 0xff; | ||
155 | rmsg->header.len2 = 0xff; | ||
156 | rmsg->header.len3 = 0x00; | ||
157 | rmsg->header.len4 = 0x00; | ||
158 | rmsg->header.len5 = 0x00; | ||
159 | remain_len = 0; | ||
160 | } else if (remain_len <= 767) { | ||
161 | len1 = 512; | ||
162 | len2 = remain_len - 512; | ||
163 | rmsg->header.len0 = 0x02; | ||
164 | rmsg->header.len1 = 0xff; | ||
165 | rmsg->header.len2 = 0xff; | ||
166 | rmsg->header.len3 = remain_len - 512; | ||
167 | rmsg->header.len4 = 0x00; | ||
168 | rmsg->header.len5 = 0x00; | ||
169 | bytes_xfer = remain_len; | ||
170 | remain_len = 0; | ||
171 | } else if (remain_len <= 1022) { | ||
172 | len1 = 512; | ||
173 | len2 = remain_len - 512; | ||
174 | rmsg->header.len0 = 0x02; | ||
175 | rmsg->header.len1 = 0xff; | ||
176 | rmsg->header.len2 = 0xff; | ||
177 | rmsg->header.len3 = remain_len - 767; | ||
178 | rmsg->header.len4 = 0xff; | ||
179 | rmsg->header.len5 = 0x00; | ||
180 | remain_len = 0; | ||
181 | } else if (remain_len <= 1024) { | ||
182 | len1 = 512; | ||
183 | len2 = remain_len - 512; | ||
184 | rmsg->header.len0 = 0x02; | ||
185 | rmsg->header.len1 = 0xff; | ||
186 | rmsg->header.len2 = 0xff; | ||
187 | rmsg->header.len3 = remain_len - 1022; | ||
188 | rmsg->header.len4 = 0xff; | ||
189 | rmsg->header.len5 = 0xff; | ||
190 | remain_len = 0; | ||
191 | } else { | ||
192 | len1 = 512; | ||
193 | len2 = 512; | ||
194 | rmsg->header.len0 = 0x02; | ||
195 | rmsg->header.len1 = 0xff; | ||
196 | rmsg->header.len2 = 0xff; | ||
197 | rmsg->header.len3 = 0x02; | ||
198 | rmsg->header.len4 = 0xff; | ||
199 | rmsg->header.len5 = 0xff; | ||
200 | remain_len -= 1024; | ||
201 | start += 1024; | ||
202 | } | ||
203 | rmsg->header.tf1 = cpu_to_le16(len1); | ||
204 | rmsg->header.tf2 = cpu_to_le16(len2); | ||
205 | |||
206 | /* first read transfer */ | ||
207 | ret = vprbrd_i2c_receive(vb->usb_dev, rmsg, len1); | ||
208 | if (ret < 0) | ||
209 | return ret; | ||
210 | /* copy the received data */ | ||
211 | memcpy(msg->buf + start, rmsg, len1); | ||
212 | |||
213 | /* second read transfer if neccessary */ | ||
214 | if (len2 > 0) { | ||
215 | ret = vprbrd_i2c_receive(vb->usb_dev, rmsg, len2); | ||
216 | if (ret < 0) | ||
217 | return ret; | ||
218 | /* copy the received data */ | ||
219 | memcpy(msg->buf + start + 512, rmsg, len2); | ||
220 | } | ||
221 | } | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int vprbrd_i2c_write(struct vprbrd *vb, struct i2c_msg *msg) | ||
226 | { | ||
227 | int ret, bytes_actual; | ||
228 | u16 remain_len, bytes_xfer, | ||
229 | start = 0x0000; | ||
230 | struct vprbrd_i2c_write_msg *wmsg = | ||
231 | (struct vprbrd_i2c_write_msg *)vb->buf; | ||
232 | |||
233 | remain_len = msg->len; | ||
234 | wmsg->header.cmd = VPRBRD_I2C_CMD_WRITE; | ||
235 | wmsg->header.last = 0x00; | ||
236 | wmsg->header.chan = 0x00; | ||
237 | wmsg->header.spi = 0x0000; | ||
238 | while (remain_len > 0) { | ||
239 | wmsg->header.addr = cpu_to_le16(start + 0x4000); | ||
240 | if (remain_len > 503) { | ||
241 | wmsg->header.len1 = 0xff; | ||
242 | wmsg->header.len2 = 0xf8; | ||
243 | remain_len -= 503; | ||
244 | bytes_xfer = 503 + sizeof(struct vprbrd_i2c_write_hdr); | ||
245 | start += 503; | ||
246 | } else if (remain_len > 255) { | ||
247 | wmsg->header.len1 = 0xff; | ||
248 | wmsg->header.len2 = (remain_len - 255); | ||
249 | bytes_xfer = remain_len + | ||
250 | sizeof(struct vprbrd_i2c_write_hdr); | ||
251 | remain_len = 0; | ||
252 | } else { | ||
253 | wmsg->header.len1 = remain_len; | ||
254 | wmsg->header.len2 = 0x00; | ||
255 | bytes_xfer = remain_len + | ||
256 | sizeof(struct vprbrd_i2c_write_hdr); | ||
257 | remain_len = 0; | ||
258 | } | ||
259 | memcpy(wmsg->data, msg->buf + start, | ||
260 | bytes_xfer - sizeof(struct vprbrd_i2c_write_hdr)); | ||
261 | |||
262 | ret = usb_bulk_msg(vb->usb_dev, | ||
263 | usb_sndbulkpipe(vb->usb_dev, | ||
264 | VPRBRD_EP_OUT), wmsg, | ||
265 | bytes_xfer, &bytes_actual, VPRBRD_USB_TIMEOUT_MS); | ||
266 | if ((ret < 0) || (bytes_xfer != bytes_actual)) | ||
267 | return -EREMOTEIO; | ||
268 | } | ||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static int vprbrd_i2c_xfer(struct i2c_adapter *i2c, struct i2c_msg *msgs, | ||
273 | int num) | ||
274 | { | ||
275 | struct i2c_msg *pmsg; | ||
276 | int i, ret, | ||
277 | error = 0; | ||
278 | struct vprbrd *vb = (struct vprbrd *)i2c->algo_data; | ||
279 | struct vprbrd_i2c_addr_msg *amsg = | ||
280 | (struct vprbrd_i2c_addr_msg *)vb->buf; | ||
281 | struct vprbrd_i2c_status *smsg = (struct vprbrd_i2c_status *)vb->buf; | ||
282 | |||
283 | dev_dbg(&i2c->dev, "master xfer %d messages:\n", num); | ||
284 | |||
285 | for (i = 0 ; i < num ; i++) { | ||
286 | pmsg = &msgs[i]; | ||
287 | |||
288 | dev_dbg(&i2c->dev, | ||
289 | " %d: %s (flags %d) %d bytes to 0x%02x\n", | ||
290 | i, pmsg->flags & I2C_M_RD ? "read" : "write", | ||
291 | pmsg->flags, pmsg->len, pmsg->addr); | ||
292 | |||
293 | /* msgs longer than 2048 bytes are not supported by adapter */ | ||
294 | if (pmsg->len > 2048) | ||
295 | return -EINVAL; | ||
296 | |||
297 | mutex_lock(&vb->lock); | ||
298 | /* directly send the message */ | ||
299 | if (pmsg->flags & I2C_M_RD) { | ||
300 | /* read data */ | ||
301 | amsg->cmd = VPRBRD_I2C_CMD_ADDR; | ||
302 | amsg->unknown2 = 0x00; | ||
303 | amsg->unknown3 = 0x00; | ||
304 | amsg->addr = pmsg->addr; | ||
305 | amsg->unknown1 = 0x01; | ||
306 | amsg->len = cpu_to_le16(pmsg->len); | ||
307 | /* send the addr and len, we're interested to board */ | ||
308 | ret = vprbrd_i2c_addr(vb->usb_dev, amsg); | ||
309 | if (ret < 0) | ||
310 | error = ret; | ||
311 | |||
312 | ret = vprbrd_i2c_read(vb, pmsg); | ||
313 | if (ret < 0) | ||
314 | error = ret; | ||
315 | |||
316 | ret = vprbrd_i2c_status(i2c, smsg, error); | ||
317 | if (ret < 0) | ||
318 | error = ret; | ||
319 | /* in case of protocol error, return the error */ | ||
320 | if (error < 0) | ||
321 | goto error; | ||
322 | } else { | ||
323 | /* write data */ | ||
324 | ret = vprbrd_i2c_write(vb, pmsg); | ||
325 | |||
326 | amsg->cmd = VPRBRD_I2C_CMD_ADDR; | ||
327 | amsg->unknown2 = 0x00; | ||
328 | amsg->unknown3 = 0x00; | ||
329 | amsg->addr = pmsg->addr; | ||
330 | amsg->unknown1 = 0x00; | ||
331 | amsg->len = cpu_to_le16(pmsg->len); | ||
332 | /* send the addr, the data goes to to board */ | ||
333 | ret = vprbrd_i2c_addr(vb->usb_dev, amsg); | ||
334 | if (ret < 0) | ||
335 | error = ret; | ||
336 | |||
337 | ret = vprbrd_i2c_status(i2c, smsg, error); | ||
338 | if (ret < 0) | ||
339 | error = ret; | ||
340 | |||
341 | if (error < 0) | ||
342 | goto error; | ||
343 | } | ||
344 | mutex_unlock(&vb->lock); | ||
345 | } | ||
346 | return 0; | ||
347 | error: | ||
348 | mutex_unlock(&vb->lock); | ||
349 | return error; | ||
350 | } | ||
351 | |||
352 | static u32 vprbrd_i2c_func(struct i2c_adapter *i2c) | ||
353 | { | ||
354 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||
355 | } | ||
356 | |||
357 | /* This is the actual algorithm we define */ | ||
358 | static const struct i2c_algorithm vprbrd_algorithm = { | ||
359 | .master_xfer = vprbrd_i2c_xfer, | ||
360 | .functionality = vprbrd_i2c_func, | ||
361 | }; | ||
362 | |||
363 | static int __devinit vprbrd_i2c_probe(struct platform_device *pdev) | ||
364 | { | ||
365 | struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent); | ||
366 | struct vprbrd_i2c *vb_i2c; | ||
367 | int ret; | ||
368 | int pipe; | ||
369 | |||
370 | vb_i2c = kzalloc(sizeof(*vb_i2c), GFP_KERNEL); | ||
371 | if (vb_i2c == NULL) | ||
372 | return -ENOMEM; | ||
373 | |||
374 | /* setup i2c adapter description */ | ||
375 | vb_i2c->i2c.owner = THIS_MODULE; | ||
376 | vb_i2c->i2c.class = I2C_CLASS_HWMON; | ||
377 | vb_i2c->i2c.algo = &vprbrd_algorithm; | ||
378 | vb_i2c->i2c.algo_data = vb; | ||
379 | /* save the param in usb capabable memory */ | ||
380 | vb_i2c->bus_freq_param = i2c_bus_param; | ||
381 | |||
382 | snprintf(vb_i2c->i2c.name, sizeof(vb_i2c->i2c.name), | ||
383 | "viperboard at bus %03d device %03d", | ||
384 | vb->usb_dev->bus->busnum, vb->usb_dev->devnum); | ||
385 | |||
386 | /* setting the bus frequency */ | ||
387 | if ((i2c_bus_param <= VPRBRD_I2C_FREQ_10KHZ) | ||
388 | && (i2c_bus_param >= VPRBRD_I2C_FREQ_6MHZ)) { | ||
389 | pipe = usb_sndctrlpipe(vb->usb_dev, 0); | ||
390 | ret = usb_control_msg(vb->usb_dev, pipe, | ||
391 | VPRBRD_USB_REQUEST_I2C_FREQ, VPRBRD_USB_TYPE_OUT, | ||
392 | 0x0000, 0x0000, &vb_i2c->bus_freq_param, 1, | ||
393 | VPRBRD_USB_TIMEOUT_MS); | ||
394 | if (ret != 1) { | ||
395 | dev_err(&pdev->dev, | ||
396 | "failure setting i2c_bus_freq to %d\n", i2c_bus_freq); | ||
397 | ret = -EIO; | ||
398 | goto error; | ||
399 | } | ||
400 | } else { | ||
401 | dev_err(&pdev->dev, | ||
402 | "invalid i2c_bus_freq setting:%d\n", i2c_bus_freq); | ||
403 | ret = -EIO; | ||
404 | goto error; | ||
405 | } | ||
406 | |||
407 | vb_i2c->i2c.dev.parent = &pdev->dev; | ||
408 | |||
409 | /* attach to i2c layer */ | ||
410 | i2c_add_adapter(&vb_i2c->i2c); | ||
411 | |||
412 | platform_set_drvdata(pdev, vb_i2c); | ||
413 | |||
414 | return 0; | ||
415 | |||
416 | error: | ||
417 | kfree(vb_i2c); | ||
418 | return ret; | ||
419 | } | ||
420 | |||
421 | static int __devexit vprbrd_i2c_remove(struct platform_device *pdev) | ||
422 | { | ||
423 | struct vprbrd_i2c *vb_i2c = platform_get_drvdata(pdev); | ||
424 | int ret; | ||
425 | |||
426 | ret = i2c_del_adapter(&vb_i2c->i2c); | ||
427 | |||
428 | return ret; | ||
429 | } | ||
430 | |||
431 | static struct platform_driver vprbrd_i2c_driver = { | ||
432 | .driver.name = "viperboard-i2c", | ||
433 | .driver.owner = THIS_MODULE, | ||
434 | .probe = vprbrd_i2c_probe, | ||
435 | .remove = __devexit_p(vprbrd_i2c_remove), | ||
436 | }; | ||
437 | |||
438 | static int __init vprbrd_i2c_init(void) | ||
439 | { | ||
440 | switch (i2c_bus_freq) { | ||
441 | case 6000: | ||
442 | i2c_bus_param = VPRBRD_I2C_FREQ_6MHZ; | ||
443 | break; | ||
444 | case 3000: | ||
445 | i2c_bus_param = VPRBRD_I2C_FREQ_3MHZ; | ||
446 | break; | ||
447 | case 1000: | ||
448 | i2c_bus_param = VPRBRD_I2C_FREQ_1MHZ; | ||
449 | break; | ||
450 | case 400: | ||
451 | i2c_bus_param = VPRBRD_I2C_FREQ_400KHZ; | ||
452 | break; | ||
453 | case 200: | ||
454 | i2c_bus_param = VPRBRD_I2C_FREQ_200KHZ; | ||
455 | break; | ||
456 | case 100: | ||
457 | i2c_bus_param = VPRBRD_I2C_FREQ_100KHZ; | ||
458 | break; | ||
459 | case 10: | ||
460 | i2c_bus_param = VPRBRD_I2C_FREQ_10KHZ; | ||
461 | break; | ||
462 | default: | ||
463 | pr_warn("invalid i2c_bus_freq (%d)\n", i2c_bus_freq); | ||
464 | i2c_bus_param = VPRBRD_I2C_FREQ_100KHZ; | ||
465 | } | ||
466 | |||
467 | return platform_driver_register(&vprbrd_i2c_driver); | ||
468 | } | ||
469 | subsys_initcall(vprbrd_i2c_init); | ||
470 | |||
471 | static void __exit vprbrd_i2c_exit(void) | ||
472 | { | ||
473 | platform_driver_unregister(&vprbrd_i2c_driver); | ||
474 | } | ||
475 | module_exit(vprbrd_i2c_exit); | ||
476 | |||
477 | MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>"); | ||
478 | MODULE_DESCRIPTION("I2C master driver for Nano River Techs Viperboard"); | ||
479 | MODULE_LICENSE("GPL"); | ||
480 | MODULE_ALIAS("platform:viperboard-i2c"); | ||
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 961b8d0a4ba..fe822a14d13 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig | |||
@@ -125,4 +125,18 @@ config TI_ADC081C | |||
125 | This driver can also be built as a module. If so, the module will be | 125 | This driver can also be built as a module. If so, the module will be |
126 | called ti-adc081c. | 126 | called ti-adc081c. |
127 | 127 | ||
128 | config TI_AM335X_ADC | ||
129 | tristate "TI's ADC driver" | ||
130 | depends on MFD_TI_AM335X_TSCADC | ||
131 | help | ||
132 | Say yes here to build support for Texas Instruments ADC | ||
133 | driver which is also a MFD client. | ||
134 | |||
135 | config VIPERBOARD_ADC | ||
136 | tristate "Viperboard ADC support" | ||
137 | depends on MFD_VIPERBOARD && USB | ||
138 | help | ||
139 | Say yes here to access the ADC part of the Nano River | ||
140 | Technologies Viperboard. | ||
141 | |||
128 | endmenu | 142 | endmenu |
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 472fd7cd241..2d5f10080d8 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile | |||
@@ -13,4 +13,5 @@ obj-$(CONFIG_AT91_ADC) += at91_adc.o | |||
13 | obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o | 13 | obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o |
14 | obj-$(CONFIG_MAX1363) += max1363.o | 14 | obj-$(CONFIG_MAX1363) += max1363.o |
15 | obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o | 15 | obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o |
16 | 16 | obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o | |
17 | obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o | ||
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c new file mode 100644 index 00000000000..02a43c87a8a --- /dev/null +++ b/drivers/iio/adc/ti_am335x_adc.c | |||
@@ -0,0 +1,260 @@ | |||
1 | /* | ||
2 | * TI ADC MFD driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation version 2. | ||
9 | * | ||
10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
11 | * kind, whether express or implied; without even the implied warranty | ||
12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/init.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/err.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/iio/iio.h> | ||
25 | |||
26 | #include <linux/mfd/ti_am335x_tscadc.h> | ||
27 | #include <linux/platform_data/ti_am335x_adc.h> | ||
28 | |||
29 | struct tiadc_device { | ||
30 | struct ti_tscadc_dev *mfd_tscadc; | ||
31 | int channels; | ||
32 | }; | ||
33 | |||
34 | static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg) | ||
35 | { | ||
36 | return readl(adc->mfd_tscadc->tscadc_base + reg); | ||
37 | } | ||
38 | |||
39 | static void tiadc_writel(struct tiadc_device *adc, unsigned int reg, | ||
40 | unsigned int val) | ||
41 | { | ||
42 | writel(val, adc->mfd_tscadc->tscadc_base + reg); | ||
43 | } | ||
44 | |||
45 | static void tiadc_step_config(struct tiadc_device *adc_dev) | ||
46 | { | ||
47 | unsigned int stepconfig; | ||
48 | int i, channels = 0, steps; | ||
49 | |||
50 | /* | ||
51 | * There are 16 configurable steps and 8 analog input | ||
52 | * lines available which are shared between Touchscreen and ADC. | ||
53 | * | ||
54 | * Steps backwards i.e. from 16 towards 0 are used by ADC | ||
55 | * depending on number of input lines needed. | ||
56 | * Channel would represent which analog input | ||
57 | * needs to be given to ADC to digitalize data. | ||
58 | */ | ||
59 | |||
60 | steps = TOTAL_STEPS - adc_dev->channels; | ||
61 | channels = TOTAL_CHANNELS - adc_dev->channels; | ||
62 | |||
63 | stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1; | ||
64 | |||
65 | for (i = (steps + 1); i <= TOTAL_STEPS; i++) { | ||
66 | tiadc_writel(adc_dev, REG_STEPCONFIG(i), | ||
67 | stepconfig | STEPCONFIG_INP(channels)); | ||
68 | tiadc_writel(adc_dev, REG_STEPDELAY(i), | ||
69 | STEPCONFIG_OPENDLY); | ||
70 | channels++; | ||
71 | } | ||
72 | tiadc_writel(adc_dev, REG_SE, STPENB_STEPENB); | ||
73 | } | ||
74 | |||
75 | static int tiadc_channel_init(struct iio_dev *indio_dev, int channels) | ||
76 | { | ||
77 | struct iio_chan_spec *chan_array; | ||
78 | int i; | ||
79 | |||
80 | indio_dev->num_channels = channels; | ||
81 | chan_array = kcalloc(indio_dev->num_channels, | ||
82 | sizeof(struct iio_chan_spec), GFP_KERNEL); | ||
83 | |||
84 | if (chan_array == NULL) | ||
85 | return -ENOMEM; | ||
86 | |||
87 | for (i = 0; i < (indio_dev->num_channels); i++) { | ||
88 | struct iio_chan_spec *chan = chan_array + i; | ||
89 | chan->type = IIO_VOLTAGE; | ||
90 | chan->indexed = 1; | ||
91 | chan->channel = i; | ||
92 | chan->info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT; | ||
93 | } | ||
94 | |||
95 | indio_dev->channels = chan_array; | ||
96 | |||
97 | return indio_dev->num_channels; | ||
98 | } | ||
99 | |||
100 | static void tiadc_channels_remove(struct iio_dev *indio_dev) | ||
101 | { | ||
102 | kfree(indio_dev->channels); | ||
103 | } | ||
104 | |||
105 | static int tiadc_read_raw(struct iio_dev *indio_dev, | ||
106 | struct iio_chan_spec const *chan, | ||
107 | int *val, int *val2, long mask) | ||
108 | { | ||
109 | struct tiadc_device *adc_dev = iio_priv(indio_dev); | ||
110 | int i; | ||
111 | unsigned int fifo1count, readx1; | ||
112 | |||
113 | /* | ||
114 | * When the sub-system is first enabled, | ||
115 | * the sequencer will always start with the | ||
116 | * lowest step (1) and continue until step (16). | ||
117 | * For ex: If we have enabled 4 ADC channels and | ||
118 | * currently use only 1 out of them, the | ||
119 | * sequencer still configures all the 4 steps, | ||
120 | * leading to 3 unwanted data. | ||
121 | * Hence we need to flush out this data. | ||
122 | */ | ||
123 | |||
124 | fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); | ||
125 | for (i = 0; i < fifo1count; i++) { | ||
126 | readx1 = tiadc_readl(adc_dev, REG_FIFO1); | ||
127 | if (i == chan->channel) | ||
128 | *val = readx1 & 0xfff; | ||
129 | } | ||
130 | tiadc_writel(adc_dev, REG_SE, STPENB_STEPENB); | ||
131 | |||
132 | return IIO_VAL_INT; | ||
133 | } | ||
134 | |||
135 | static const struct iio_info tiadc_info = { | ||
136 | .read_raw = &tiadc_read_raw, | ||
137 | }; | ||
138 | |||
139 | static int __devinit tiadc_probe(struct platform_device *pdev) | ||
140 | { | ||
141 | struct iio_dev *indio_dev; | ||
142 | struct tiadc_device *adc_dev; | ||
143 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; | ||
144 | struct mfd_tscadc_board *pdata; | ||
145 | int err; | ||
146 | |||
147 | pdata = tscadc_dev->dev->platform_data; | ||
148 | if (!pdata || !pdata->adc_init) { | ||
149 | dev_err(&pdev->dev, "Could not find platform data\n"); | ||
150 | return -EINVAL; | ||
151 | } | ||
152 | |||
153 | indio_dev = iio_device_alloc(sizeof(struct tiadc_device)); | ||
154 | if (indio_dev == NULL) { | ||
155 | dev_err(&pdev->dev, "failed to allocate iio device\n"); | ||
156 | err = -ENOMEM; | ||
157 | goto err_ret; | ||
158 | } | ||
159 | adc_dev = iio_priv(indio_dev); | ||
160 | |||
161 | adc_dev->mfd_tscadc = tscadc_dev; | ||
162 | adc_dev->channels = pdata->adc_init->adc_channels; | ||
163 | |||
164 | indio_dev->dev.parent = &pdev->dev; | ||
165 | indio_dev->name = dev_name(&pdev->dev); | ||
166 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
167 | indio_dev->info = &tiadc_info; | ||
168 | |||
169 | tiadc_step_config(adc_dev); | ||
170 | |||
171 | err = tiadc_channel_init(indio_dev, adc_dev->channels); | ||
172 | if (err < 0) | ||
173 | goto err_free_device; | ||
174 | |||
175 | err = iio_device_register(indio_dev); | ||
176 | if (err) | ||
177 | goto err_free_channels; | ||
178 | |||
179 | platform_set_drvdata(pdev, indio_dev); | ||
180 | |||
181 | return 0; | ||
182 | |||
183 | err_free_channels: | ||
184 | tiadc_channels_remove(indio_dev); | ||
185 | err_free_device: | ||
186 | iio_device_free(indio_dev); | ||
187 | err_ret: | ||
188 | return err; | ||
189 | } | ||
190 | |||
191 | static int __devexit tiadc_remove(struct platform_device *pdev) | ||
192 | { | ||
193 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); | ||
194 | |||
195 | iio_device_unregister(indio_dev); | ||
196 | tiadc_channels_remove(indio_dev); | ||
197 | |||
198 | iio_device_free(indio_dev); | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | #ifdef CONFIG_PM | ||
204 | static int tiadc_suspend(struct device *dev) | ||
205 | { | ||
206 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
207 | struct tiadc_device *adc_dev = iio_priv(indio_dev); | ||
208 | struct ti_tscadc_dev *tscadc_dev = dev->platform_data; | ||
209 | unsigned int idle; | ||
210 | |||
211 | if (!device_may_wakeup(tscadc_dev->dev)) { | ||
212 | idle = tiadc_readl(adc_dev, REG_CTRL); | ||
213 | idle &= ~(CNTRLREG_TSCSSENB); | ||
214 | tiadc_writel(adc_dev, REG_CTRL, (idle | | ||
215 | CNTRLREG_POWERDOWN)); | ||
216 | } | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int tiadc_resume(struct device *dev) | ||
222 | { | ||
223 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
224 | struct tiadc_device *adc_dev = iio_priv(indio_dev); | ||
225 | unsigned int restore; | ||
226 | |||
227 | /* Make sure ADC is powered up */ | ||
228 | restore = tiadc_readl(adc_dev, REG_CTRL); | ||
229 | restore &= ~(CNTRLREG_POWERDOWN); | ||
230 | tiadc_writel(adc_dev, REG_CTRL, restore); | ||
231 | |||
232 | tiadc_step_config(adc_dev); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static const struct dev_pm_ops tiadc_pm_ops = { | ||
238 | .suspend = tiadc_suspend, | ||
239 | .resume = tiadc_resume, | ||
240 | }; | ||
241 | #define TIADC_PM_OPS (&tiadc_pm_ops) | ||
242 | #else | ||
243 | #define TIADC_PM_OPS NULL | ||
244 | #endif | ||
245 | |||
246 | static struct platform_driver tiadc_driver = { | ||
247 | .driver = { | ||
248 | .name = "tiadc", | ||
249 | .owner = THIS_MODULE, | ||
250 | .pm = TIADC_PM_OPS, | ||
251 | }, | ||
252 | .probe = tiadc_probe, | ||
253 | .remove = __devexit_p(tiadc_remove), | ||
254 | }; | ||
255 | |||
256 | module_platform_driver(tiadc_driver); | ||
257 | |||
258 | MODULE_DESCRIPTION("TI ADC controller driver"); | ||
259 | MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); | ||
260 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c new file mode 100644 index 00000000000..10136a8b20d --- /dev/null +++ b/drivers/iio/adc/viperboard_adc.c | |||
@@ -0,0 +1,181 @@ | |||
1 | /* | ||
2 | * Nano River Technologies viperboard IIO ADC driver | ||
3 | * | ||
4 | * (C) 2012 by Lemonage GmbH | ||
5 | * Author: Lars Poeschel <poeschel@lemonage.de> | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/mutex.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | |||
23 | #include <linux/usb.h> | ||
24 | #include <linux/iio/iio.h> | ||
25 | |||
26 | #include <linux/mfd/viperboard.h> | ||
27 | |||
28 | #define VPRBRD_ADC_CMD_GET 0x00 | ||
29 | |||
30 | struct vprbrd_adc_msg { | ||
31 | u8 cmd; | ||
32 | u8 chan; | ||
33 | u8 val; | ||
34 | } __packed; | ||
35 | |||
36 | struct vprbrd_adc { | ||
37 | struct vprbrd *vb; | ||
38 | }; | ||
39 | |||
40 | #define VPRBRD_ADC_CHANNEL(_index) { \ | ||
41 | .type = IIO_VOLTAGE, \ | ||
42 | .indexed = 1, \ | ||
43 | .channel = _index, \ | ||
44 | .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \ | ||
45 | .scan_index = _index, \ | ||
46 | .scan_type = { \ | ||
47 | .sign = 'u', \ | ||
48 | .realbits = 8, \ | ||
49 | .storagebits = 8, \ | ||
50 | }, \ | ||
51 | } | ||
52 | |||
53 | static struct iio_chan_spec const vprbrd_adc_iio_channels[] = { | ||
54 | VPRBRD_ADC_CHANNEL(0), | ||
55 | VPRBRD_ADC_CHANNEL(1), | ||
56 | VPRBRD_ADC_CHANNEL(2), | ||
57 | VPRBRD_ADC_CHANNEL(3), | ||
58 | }; | ||
59 | |||
60 | static int vprbrd_iio_read_raw(struct iio_dev *iio_dev, | ||
61 | struct iio_chan_spec const *chan, | ||
62 | int *val, | ||
63 | int *val2, | ||
64 | long info) | ||
65 | { | ||
66 | int ret, error = 0; | ||
67 | struct vprbrd_adc *adc = iio_priv(iio_dev); | ||
68 | struct vprbrd *vb = adc->vb; | ||
69 | struct vprbrd_adc_msg *admsg = (struct vprbrd_adc_msg *)vb->buf; | ||
70 | |||
71 | switch (info) { | ||
72 | case IIO_CHAN_INFO_RAW: | ||
73 | mutex_lock(&vb->lock); | ||
74 | |||
75 | admsg->cmd = VPRBRD_ADC_CMD_GET; | ||
76 | admsg->chan = chan->scan_index; | ||
77 | admsg->val = 0x00; | ||
78 | |||
79 | ret = usb_control_msg(vb->usb_dev, | ||
80 | usb_sndctrlpipe(vb->usb_dev, 0), VPRBRD_USB_REQUEST_ADC, | ||
81 | VPRBRD_USB_TYPE_OUT, 0x0000, 0x0000, admsg, | ||
82 | sizeof(struct vprbrd_adc_msg), VPRBRD_USB_TIMEOUT_MS); | ||
83 | if (ret != sizeof(struct vprbrd_adc_msg)) { | ||
84 | dev_err(&iio_dev->dev, "usb send error on adc read\n"); | ||
85 | error = -EREMOTEIO; | ||
86 | } | ||
87 | |||
88 | ret = usb_control_msg(vb->usb_dev, | ||
89 | usb_rcvctrlpipe(vb->usb_dev, 0), VPRBRD_USB_REQUEST_ADC, | ||
90 | VPRBRD_USB_TYPE_IN, 0x0000, 0x0000, admsg, | ||
91 | sizeof(struct vprbrd_adc_msg), VPRBRD_USB_TIMEOUT_MS); | ||
92 | |||
93 | *val = admsg->val; | ||
94 | |||
95 | mutex_unlock(&vb->lock); | ||
96 | |||
97 | if (ret != sizeof(struct vprbrd_adc_msg)) { | ||
98 | dev_err(&iio_dev->dev, "usb recv error on adc read\n"); | ||
99 | error = -EREMOTEIO; | ||
100 | } | ||
101 | |||
102 | if (error) | ||
103 | goto error; | ||
104 | |||
105 | return IIO_VAL_INT; | ||
106 | default: | ||
107 | error = -EINVAL; | ||
108 | break; | ||
109 | } | ||
110 | error: | ||
111 | return error; | ||
112 | } | ||
113 | |||
114 | static const struct iio_info vprbrd_adc_iio_info = { | ||
115 | .read_raw = &vprbrd_iio_read_raw, | ||
116 | .driver_module = THIS_MODULE, | ||
117 | }; | ||
118 | |||
119 | static int __devinit vprbrd_adc_probe(struct platform_device *pdev) | ||
120 | { | ||
121 | struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent); | ||
122 | struct vprbrd_adc *adc; | ||
123 | struct iio_dev *indio_dev; | ||
124 | int ret; | ||
125 | |||
126 | /* registering iio */ | ||
127 | indio_dev = iio_device_alloc(sizeof(*adc)); | ||
128 | if (!indio_dev) { | ||
129 | dev_err(&pdev->dev, "failed allocating iio device\n"); | ||
130 | return -ENOMEM; | ||
131 | } | ||
132 | |||
133 | adc = iio_priv(indio_dev); | ||
134 | adc->vb = vb; | ||
135 | indio_dev->name = "viperboard adc"; | ||
136 | indio_dev->dev.parent = &pdev->dev; | ||
137 | indio_dev->info = &vprbrd_adc_iio_info; | ||
138 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
139 | indio_dev->channels = vprbrd_adc_iio_channels; | ||
140 | indio_dev->num_channels = ARRAY_SIZE(vprbrd_adc_iio_channels); | ||
141 | |||
142 | ret = iio_device_register(indio_dev); | ||
143 | if (ret) { | ||
144 | dev_err(&pdev->dev, "could not register iio (adc)"); | ||
145 | goto error; | ||
146 | } | ||
147 | |||
148 | platform_set_drvdata(pdev, indio_dev); | ||
149 | |||
150 | return 0; | ||
151 | |||
152 | error: | ||
153 | iio_device_free(indio_dev); | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | static int __devexit vprbrd_adc_remove(struct platform_device *pdev) | ||
158 | { | ||
159 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); | ||
160 | |||
161 | iio_device_unregister(indio_dev); | ||
162 | iio_device_free(indio_dev); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static struct platform_driver vprbrd_adc_driver = { | ||
168 | .driver = { | ||
169 | .name = "viperboard-adc", | ||
170 | .owner = THIS_MODULE, | ||
171 | }, | ||
172 | .probe = vprbrd_adc_probe, | ||
173 | .remove = __devexit_p(vprbrd_adc_remove), | ||
174 | }; | ||
175 | |||
176 | module_platform_driver(vprbrd_adc_driver); | ||
177 | |||
178 | MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>"); | ||
179 | MODULE_DESCRIPTION("IIO ADC driver for Nano River Techs Viperboard"); | ||
180 | MODULE_LICENSE("GPL"); | ||
181 | MODULE_ALIAS("platform:viperboard-adc"); | ||
diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c index 3c843cd725f..3be3acc3a6e 100644 --- a/drivers/input/misc/da9052_onkey.c +++ b/drivers/input/misc/da9052_onkey.c | |||
@@ -24,7 +24,6 @@ struct da9052_onkey { | |||
24 | struct da9052 *da9052; | 24 | struct da9052 *da9052; |
25 | struct input_dev *input; | 25 | struct input_dev *input; |
26 | struct delayed_work work; | 26 | struct delayed_work work; |
27 | unsigned int irq; | ||
28 | }; | 27 | }; |
29 | 28 | ||
30 | static void da9052_onkey_query(struct da9052_onkey *onkey) | 29 | static void da9052_onkey_query(struct da9052_onkey *onkey) |
@@ -76,7 +75,6 @@ static int __devinit da9052_onkey_probe(struct platform_device *pdev) | |||
76 | struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent); | 75 | struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent); |
77 | struct da9052_onkey *onkey; | 76 | struct da9052_onkey *onkey; |
78 | struct input_dev *input_dev; | 77 | struct input_dev *input_dev; |
79 | int irq; | ||
80 | int error; | 78 | int error; |
81 | 79 | ||
82 | if (!da9052) { | 80 | if (!da9052) { |
@@ -84,13 +82,6 @@ static int __devinit da9052_onkey_probe(struct platform_device *pdev) | |||
84 | return -EINVAL; | 82 | return -EINVAL; |
85 | } | 83 | } |
86 | 84 | ||
87 | irq = platform_get_irq_byname(pdev, "ONKEY"); | ||
88 | if (irq < 0) { | ||
89 | dev_err(&pdev->dev, | ||
90 | "Failed to get an IRQ for input device, %d\n", irq); | ||
91 | return -EINVAL; | ||
92 | } | ||
93 | |||
94 | onkey = kzalloc(sizeof(*onkey), GFP_KERNEL); | 85 | onkey = kzalloc(sizeof(*onkey), GFP_KERNEL); |
95 | input_dev = input_allocate_device(); | 86 | input_dev = input_allocate_device(); |
96 | if (!onkey || !input_dev) { | 87 | if (!onkey || !input_dev) { |
@@ -101,7 +92,6 @@ static int __devinit da9052_onkey_probe(struct platform_device *pdev) | |||
101 | 92 | ||
102 | onkey->input = input_dev; | 93 | onkey->input = input_dev; |
103 | onkey->da9052 = da9052; | 94 | onkey->da9052 = da9052; |
104 | onkey->irq = irq; | ||
105 | INIT_DELAYED_WORK(&onkey->work, da9052_onkey_work); | 95 | INIT_DELAYED_WORK(&onkey->work, da9052_onkey_work); |
106 | 96 | ||
107 | input_dev->name = "da9052-onkey"; | 97 | input_dev->name = "da9052-onkey"; |
@@ -111,13 +101,11 @@ static int __devinit da9052_onkey_probe(struct platform_device *pdev) | |||
111 | input_dev->evbit[0] = BIT_MASK(EV_KEY); | 101 | input_dev->evbit[0] = BIT_MASK(EV_KEY); |
112 | __set_bit(KEY_POWER, input_dev->keybit); | 102 | __set_bit(KEY_POWER, input_dev->keybit); |
113 | 103 | ||
114 | error = request_threaded_irq(onkey->irq, NULL, da9052_onkey_irq, | 104 | error = da9052_request_irq(onkey->da9052, DA9052_IRQ_NONKEY, "ONKEY", |
115 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | 105 | da9052_onkey_irq, onkey); |
116 | "ONKEY", onkey); | ||
117 | if (error < 0) { | 106 | if (error < 0) { |
118 | dev_err(onkey->da9052->dev, | 107 | dev_err(onkey->da9052->dev, |
119 | "Failed to register ONKEY IRQ %d, error = %d\n", | 108 | "Failed to register ONKEY IRQ: %d\n", error); |
120 | onkey->irq, error); | ||
121 | goto err_free_mem; | 109 | goto err_free_mem; |
122 | } | 110 | } |
123 | 111 | ||
@@ -132,7 +120,7 @@ static int __devinit da9052_onkey_probe(struct platform_device *pdev) | |||
132 | return 0; | 120 | return 0; |
133 | 121 | ||
134 | err_free_irq: | 122 | err_free_irq: |
135 | free_irq(onkey->irq, onkey); | 123 | da9052_free_irq(onkey->da9052, DA9052_IRQ_NONKEY, onkey); |
136 | cancel_delayed_work_sync(&onkey->work); | 124 | cancel_delayed_work_sync(&onkey->work); |
137 | err_free_mem: | 125 | err_free_mem: |
138 | input_free_device(input_dev); | 126 | input_free_device(input_dev); |
@@ -145,7 +133,7 @@ static int __devexit da9052_onkey_remove(struct platform_device *pdev) | |||
145 | { | 133 | { |
146 | struct da9052_onkey *onkey = platform_get_drvdata(pdev); | 134 | struct da9052_onkey *onkey = platform_get_drvdata(pdev); |
147 | 135 | ||
148 | free_irq(onkey->irq, onkey); | 136 | da9052_free_irq(onkey->da9052, DA9052_IRQ_NONKEY, onkey); |
149 | cancel_delayed_work_sync(&onkey->work); | 137 | cancel_delayed_work_sync(&onkey->work); |
150 | 138 | ||
151 | input_unregister_device(onkey->input); | 139 | input_unregister_device(onkey->input); |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index f7668b24c37..0c45caddd41 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -529,9 +529,9 @@ config TOUCHSCREEN_TOUCHWIN | |||
529 | To compile this driver as a module, choose M here: the | 529 | To compile this driver as a module, choose M here: the |
530 | module will be called touchwin. | 530 | module will be called touchwin. |
531 | 531 | ||
532 | config TOUCHSCREEN_TI_TSCADC | 532 | config TOUCHSCREEN_TI_AM335X_TSC |
533 | tristate "TI Touchscreen Interface" | 533 | tristate "TI Touchscreen Interface" |
534 | depends on ARCH_OMAP2PLUS | 534 | depends on MFD_TI_AM335X_TSCADC |
535 | help | 535 | help |
536 | Say Y here if you have 4/5/8 wire touchscreen controller | 536 | Say Y here if you have 4/5/8 wire touchscreen controller |
537 | to be connected to the ADC controller on your TI AM335x SoC. | 537 | to be connected to the ADC controller on your TI AM335x SoC. |
@@ -539,7 +539,7 @@ config TOUCHSCREEN_TI_TSCADC | |||
539 | If unsure, say N. | 539 | If unsure, say N. |
540 | 540 | ||
541 | To compile this driver as a module, choose M here: the | 541 | To compile this driver as a module, choose M here: the |
542 | module will be called ti_tscadc. | 542 | module will be called ti_am335x_tsc. |
543 | 543 | ||
544 | config TOUCHSCREEN_ATMEL_TSADCC | 544 | config TOUCHSCREEN_ATMEL_TSADCC |
545 | tristate "Atmel Touchscreen Interface" | 545 | tristate "Atmel Touchscreen Interface" |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 178eb128d90..7c4c78ebe49 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -52,7 +52,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o | |||
52 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o | 52 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o |
53 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o | 53 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o |
54 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o | 54 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o |
55 | obj-$(CONFIG_TOUCHSCREEN_TI_TSCADC) += ti_tscadc.o | 55 | obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o |
56 | obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o | 56 | obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o |
57 | obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o | 57 | obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o |
58 | obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o | 58 | obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o |
diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c index e8df341090c..53133efe041 100644 --- a/drivers/input/touchscreen/da9052_tsi.c +++ b/drivers/input/touchscreen/da9052_tsi.c | |||
@@ -27,8 +27,6 @@ struct da9052_tsi { | |||
27 | struct input_dev *dev; | 27 | struct input_dev *dev; |
28 | struct delayed_work ts_pen_work; | 28 | struct delayed_work ts_pen_work; |
29 | struct mutex mutex; | 29 | struct mutex mutex; |
30 | unsigned int irq_pendwn; | ||
31 | unsigned int irq_datardy; | ||
32 | bool stopped; | 30 | bool stopped; |
33 | bool adc_on; | 31 | bool adc_on; |
34 | }; | 32 | }; |
@@ -45,8 +43,8 @@ static irqreturn_t da9052_ts_pendwn_irq(int irq, void *data) | |||
45 | 43 | ||
46 | if (!tsi->stopped) { | 44 | if (!tsi->stopped) { |
47 | /* Mask PEN_DOWN event and unmask TSI_READY event */ | 45 | /* Mask PEN_DOWN event and unmask TSI_READY event */ |
48 | disable_irq_nosync(tsi->irq_pendwn); | 46 | da9052_disable_irq_nosync(tsi->da9052, DA9052_IRQ_PENDOWN); |
49 | enable_irq(tsi->irq_datardy); | 47 | da9052_enable_irq(tsi->da9052, DA9052_IRQ_TSIREADY); |
50 | 48 | ||
51 | da9052_ts_adc_toggle(tsi, true); | 49 | da9052_ts_adc_toggle(tsi, true); |
52 | 50 | ||
@@ -137,8 +135,8 @@ static void da9052_ts_pen_work(struct work_struct *work) | |||
137 | return; | 135 | return; |
138 | 136 | ||
139 | /* Mask TSI_READY event and unmask PEN_DOWN event */ | 137 | /* Mask TSI_READY event and unmask PEN_DOWN event */ |
140 | disable_irq(tsi->irq_datardy); | 138 | da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY); |
141 | enable_irq(tsi->irq_pendwn); | 139 | da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN); |
142 | } | 140 | } |
143 | } | 141 | } |
144 | } | 142 | } |
@@ -197,7 +195,7 @@ static int da9052_ts_input_open(struct input_dev *input_dev) | |||
197 | mb(); | 195 | mb(); |
198 | 196 | ||
199 | /* Unmask PEN_DOWN event */ | 197 | /* Unmask PEN_DOWN event */ |
200 | enable_irq(tsi->irq_pendwn); | 198 | da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN); |
201 | 199 | ||
202 | /* Enable Pen Detect Circuit */ | 200 | /* Enable Pen Detect Circuit */ |
203 | return da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, | 201 | return da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, |
@@ -210,11 +208,11 @@ static void da9052_ts_input_close(struct input_dev *input_dev) | |||
210 | 208 | ||
211 | tsi->stopped = true; | 209 | tsi->stopped = true; |
212 | mb(); | 210 | mb(); |
213 | disable_irq(tsi->irq_pendwn); | 211 | da9052_disable_irq(tsi->da9052, DA9052_IRQ_PENDOWN); |
214 | cancel_delayed_work_sync(&tsi->ts_pen_work); | 212 | cancel_delayed_work_sync(&tsi->ts_pen_work); |
215 | 213 | ||
216 | if (tsi->adc_on) { | 214 | if (tsi->adc_on) { |
217 | disable_irq(tsi->irq_datardy); | 215 | da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY); |
218 | da9052_ts_adc_toggle(tsi, false); | 216 | da9052_ts_adc_toggle(tsi, false); |
219 | 217 | ||
220 | /* | 218 | /* |
@@ -222,7 +220,7 @@ static void da9052_ts_input_close(struct input_dev *input_dev) | |||
222 | * twice and we need to enable it to keep enable/disable | 220 | * twice and we need to enable it to keep enable/disable |
223 | * counter balanced. IRQ is still off though. | 221 | * counter balanced. IRQ is still off though. |
224 | */ | 222 | */ |
225 | enable_irq(tsi->irq_pendwn); | 223 | da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN); |
226 | } | 224 | } |
227 | 225 | ||
228 | /* Disable Pen Detect Circuit */ | 226 | /* Disable Pen Detect Circuit */ |
@@ -234,21 +232,12 @@ static int __devinit da9052_ts_probe(struct platform_device *pdev) | |||
234 | struct da9052 *da9052; | 232 | struct da9052 *da9052; |
235 | struct da9052_tsi *tsi; | 233 | struct da9052_tsi *tsi; |
236 | struct input_dev *input_dev; | 234 | struct input_dev *input_dev; |
237 | int irq_pendwn; | ||
238 | int irq_datardy; | ||
239 | int error; | 235 | int error; |
240 | 236 | ||
241 | da9052 = dev_get_drvdata(pdev->dev.parent); | 237 | da9052 = dev_get_drvdata(pdev->dev.parent); |
242 | if (!da9052) | 238 | if (!da9052) |
243 | return -EINVAL; | 239 | return -EINVAL; |
244 | 240 | ||
245 | irq_pendwn = platform_get_irq_byname(pdev, "PENDWN"); | ||
246 | irq_datardy = platform_get_irq_byname(pdev, "TSIRDY"); | ||
247 | if (irq_pendwn < 0 || irq_datardy < 0) { | ||
248 | dev_err(da9052->dev, "Unable to determine device interrupts\n"); | ||
249 | return -ENXIO; | ||
250 | } | ||
251 | |||
252 | tsi = kzalloc(sizeof(struct da9052_tsi), GFP_KERNEL); | 241 | tsi = kzalloc(sizeof(struct da9052_tsi), GFP_KERNEL); |
253 | input_dev = input_allocate_device(); | 242 | input_dev = input_allocate_device(); |
254 | if (!tsi || !input_dev) { | 243 | if (!tsi || !input_dev) { |
@@ -258,8 +247,6 @@ static int __devinit da9052_ts_probe(struct platform_device *pdev) | |||
258 | 247 | ||
259 | tsi->da9052 = da9052; | 248 | tsi->da9052 = da9052; |
260 | tsi->dev = input_dev; | 249 | tsi->dev = input_dev; |
261 | tsi->irq_pendwn = da9052->irq_base + irq_pendwn; | ||
262 | tsi->irq_datardy = da9052->irq_base + irq_datardy; | ||
263 | tsi->stopped = true; | 250 | tsi->stopped = true; |
264 | INIT_DELAYED_WORK(&tsi->ts_pen_work, da9052_ts_pen_work); | 251 | INIT_DELAYED_WORK(&tsi->ts_pen_work, da9052_ts_pen_work); |
265 | 252 | ||
@@ -287,31 +274,25 @@ static int __devinit da9052_ts_probe(struct platform_device *pdev) | |||
287 | /* Disable ADC */ | 274 | /* Disable ADC */ |
288 | da9052_ts_adc_toggle(tsi, false); | 275 | da9052_ts_adc_toggle(tsi, false); |
289 | 276 | ||
290 | error = request_threaded_irq(tsi->irq_pendwn, | 277 | error = da9052_request_irq(tsi->da9052, DA9052_IRQ_PENDOWN, |
291 | NULL, da9052_ts_pendwn_irq, | 278 | "pendown-irq", da9052_ts_pendwn_irq, tsi); |
292 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
293 | "PENDWN", tsi); | ||
294 | if (error) { | 279 | if (error) { |
295 | dev_err(tsi->da9052->dev, | 280 | dev_err(tsi->da9052->dev, |
296 | "Failed to register PENDWN IRQ %d, error = %d\n", | 281 | "Failed to register PENDWN IRQ: %d\n", error); |
297 | tsi->irq_pendwn, error); | ||
298 | goto err_free_mem; | 282 | goto err_free_mem; |
299 | } | 283 | } |
300 | 284 | ||
301 | error = request_threaded_irq(tsi->irq_datardy, | 285 | error = da9052_request_irq(tsi->da9052, DA9052_IRQ_TSIREADY, |
302 | NULL, da9052_ts_datardy_irq, | 286 | "tsiready-irq", da9052_ts_datardy_irq, tsi); |
303 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
304 | "TSIRDY", tsi); | ||
305 | if (error) { | 287 | if (error) { |
306 | dev_err(tsi->da9052->dev, | 288 | dev_err(tsi->da9052->dev, |
307 | "Failed to register TSIRDY IRQ %d, error = %d\n", | 289 | "Failed to register TSIRDY IRQ :%d\n", error); |
308 | tsi->irq_datardy, error); | ||
309 | goto err_free_pendwn_irq; | 290 | goto err_free_pendwn_irq; |
310 | } | 291 | } |
311 | 292 | ||
312 | /* Mask PEN_DOWN and TSI_READY events */ | 293 | /* Mask PEN_DOWN and TSI_READY events */ |
313 | disable_irq(tsi->irq_pendwn); | 294 | da9052_disable_irq(tsi->da9052, DA9052_IRQ_PENDOWN); |
314 | disable_irq(tsi->irq_datardy); | 295 | da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY); |
315 | 296 | ||
316 | error = da9052_configure_tsi(tsi); | 297 | error = da9052_configure_tsi(tsi); |
317 | if (error) | 298 | if (error) |
@@ -326,9 +307,9 @@ static int __devinit da9052_ts_probe(struct platform_device *pdev) | |||
326 | return 0; | 307 | return 0; |
327 | 308 | ||
328 | err_free_datardy_irq: | 309 | err_free_datardy_irq: |
329 | free_irq(tsi->irq_datardy, tsi); | 310 | da9052_free_irq(tsi->da9052, DA9052_IRQ_TSIREADY, tsi); |
330 | err_free_pendwn_irq: | 311 | err_free_pendwn_irq: |
331 | free_irq(tsi->irq_pendwn, tsi); | 312 | da9052_free_irq(tsi->da9052, DA9052_IRQ_PENDOWN, tsi); |
332 | err_free_mem: | 313 | err_free_mem: |
333 | kfree(tsi); | 314 | kfree(tsi); |
334 | input_free_device(input_dev); | 315 | input_free_device(input_dev); |
@@ -342,8 +323,8 @@ static int __devexit da9052_ts_remove(struct platform_device *pdev) | |||
342 | 323 | ||
343 | da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x19); | 324 | da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x19); |
344 | 325 | ||
345 | free_irq(tsi->irq_pendwn, tsi); | 326 | da9052_free_irq(tsi->da9052, DA9052_IRQ_TSIREADY, tsi); |
346 | free_irq(tsi->irq_datardy, tsi); | 327 | da9052_free_irq(tsi->da9052, DA9052_IRQ_PENDOWN, tsi); |
347 | 328 | ||
348 | input_unregister_device(tsi->dev); | 329 | input_unregister_device(tsi->dev); |
349 | kfree(tsi); | 330 | kfree(tsi); |
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c new file mode 100644 index 00000000000..7a18a8a1522 --- /dev/null +++ b/drivers/input/touchscreen/ti_am335x_tsc.c | |||
@@ -0,0 +1,398 @@ | |||
1 | /* | ||
2 | * TI Touch Screen driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation version 2. | ||
9 | * | ||
10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
11 | * kind, whether express or implied; without even the implied warranty | ||
12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/input.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/clk.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/input/ti_am335x_tsc.h> | ||
28 | #include <linux/delay.h> | ||
29 | |||
30 | #include <linux/mfd/ti_am335x_tscadc.h> | ||
31 | |||
32 | #define ADCFSM_STEPID 0x10 | ||
33 | #define SEQ_SETTLE 275 | ||
34 | #define MAX_12BIT ((1 << 12) - 1) | ||
35 | |||
36 | struct titsc { | ||
37 | struct input_dev *input; | ||
38 | struct ti_tscadc_dev *mfd_tscadc; | ||
39 | unsigned int irq; | ||
40 | unsigned int wires; | ||
41 | unsigned int x_plate_resistance; | ||
42 | bool pen_down; | ||
43 | int steps_to_configure; | ||
44 | }; | ||
45 | |||
46 | static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) | ||
47 | { | ||
48 | return readl(ts->mfd_tscadc->tscadc_base + reg); | ||
49 | } | ||
50 | |||
51 | static void titsc_writel(struct titsc *tsc, unsigned int reg, | ||
52 | unsigned int val) | ||
53 | { | ||
54 | writel(val, tsc->mfd_tscadc->tscadc_base + reg); | ||
55 | } | ||
56 | |||
57 | static void titsc_step_config(struct titsc *ts_dev) | ||
58 | { | ||
59 | unsigned int config; | ||
60 | int i, total_steps; | ||
61 | |||
62 | /* Configure the Step registers */ | ||
63 | total_steps = 2 * ts_dev->steps_to_configure; | ||
64 | |||
65 | config = STEPCONFIG_MODE_HWSYNC | | ||
66 | STEPCONFIG_AVG_16 | STEPCONFIG_XPP; | ||
67 | switch (ts_dev->wires) { | ||
68 | case 4: | ||
69 | config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN; | ||
70 | break; | ||
71 | case 5: | ||
72 | config |= STEPCONFIG_YNN | | ||
73 | STEPCONFIG_INP_AN4 | STEPCONFIG_XNN | | ||
74 | STEPCONFIG_YPP; | ||
75 | break; | ||
76 | case 8: | ||
77 | config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN; | ||
78 | break; | ||
79 | } | ||
80 | |||
81 | for (i = 1; i <= ts_dev->steps_to_configure; i++) { | ||
82 | titsc_writel(ts_dev, REG_STEPCONFIG(i), config); | ||
83 | titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | ||
84 | } | ||
85 | |||
86 | config = 0; | ||
87 | config = STEPCONFIG_MODE_HWSYNC | | ||
88 | STEPCONFIG_AVG_16 | STEPCONFIG_YNN | | ||
89 | STEPCONFIG_INM_ADCREFM | STEPCONFIG_FIFO1; | ||
90 | switch (ts_dev->wires) { | ||
91 | case 4: | ||
92 | config |= STEPCONFIG_YPP; | ||
93 | break; | ||
94 | case 5: | ||
95 | config |= STEPCONFIG_XPP | STEPCONFIG_INP_AN4 | | ||
96 | STEPCONFIG_XNP | STEPCONFIG_YPN; | ||
97 | break; | ||
98 | case 8: | ||
99 | config |= STEPCONFIG_YPP; | ||
100 | break; | ||
101 | } | ||
102 | |||
103 | for (i = (ts_dev->steps_to_configure + 1); i <= total_steps; i++) { | ||
104 | titsc_writel(ts_dev, REG_STEPCONFIG(i), config); | ||
105 | titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | ||
106 | } | ||
107 | |||
108 | config = 0; | ||
109 | /* Charge step configuration */ | ||
110 | config = STEPCONFIG_XPP | STEPCONFIG_YNN | | ||
111 | STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR | | ||
112 | STEPCHARGE_INM_AN1 | STEPCHARGE_INP_AN1; | ||
113 | |||
114 | titsc_writel(ts_dev, REG_CHARGECONFIG, config); | ||
115 | titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY); | ||
116 | |||
117 | config = 0; | ||
118 | /* Configure to calculate pressure */ | ||
119 | config = STEPCONFIG_MODE_HWSYNC | | ||
120 | STEPCONFIG_AVG_16 | STEPCONFIG_YPP | | ||
121 | STEPCONFIG_XNN | STEPCONFIG_INM_ADCREFM; | ||
122 | titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 1), config); | ||
123 | titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 1), | ||
124 | STEPCONFIG_OPENDLY); | ||
125 | |||
126 | config |= STEPCONFIG_INP_AN3 | STEPCONFIG_FIFO1; | ||
127 | titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 2), config); | ||
128 | titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 2), | ||
129 | STEPCONFIG_OPENDLY); | ||
130 | |||
131 | titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC); | ||
132 | } | ||
133 | |||
134 | static void titsc_read_coordinates(struct titsc *ts_dev, | ||
135 | unsigned int *x, unsigned int *y) | ||
136 | { | ||
137 | unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT); | ||
138 | unsigned int prev_val_x = ~0, prev_val_y = ~0; | ||
139 | unsigned int prev_diff_x = ~0, prev_diff_y = ~0; | ||
140 | unsigned int read, diff; | ||
141 | unsigned int i, channel; | ||
142 | |||
143 | /* | ||
144 | * Delta filter is used to remove large variations in sampled | ||
145 | * values from ADC. The filter tries to predict where the next | ||
146 | * coordinate could be. This is done by taking a previous | ||
147 | * coordinate and subtracting it form current one. Further the | ||
148 | * algorithm compares the difference with that of a present value, | ||
149 | * if true the value is reported to the sub system. | ||
150 | */ | ||
151 | for (i = 0; i < fifocount - 1; i++) { | ||
152 | read = titsc_readl(ts_dev, REG_FIFO0); | ||
153 | channel = read & 0xf0000; | ||
154 | channel = channel >> 0x10; | ||
155 | if ((channel >= 0) && (channel < ts_dev->steps_to_configure)) { | ||
156 | read &= 0xfff; | ||
157 | diff = abs(read - prev_val_x); | ||
158 | if (diff < prev_diff_x) { | ||
159 | prev_diff_x = diff; | ||
160 | *x = read; | ||
161 | } | ||
162 | prev_val_x = read; | ||
163 | } | ||
164 | |||
165 | read = titsc_readl(ts_dev, REG_FIFO1); | ||
166 | channel = read & 0xf0000; | ||
167 | channel = channel >> 0x10; | ||
168 | if ((channel >= ts_dev->steps_to_configure) && | ||
169 | (channel < (2 * ts_dev->steps_to_configure - 1))) { | ||
170 | read &= 0xfff; | ||
171 | diff = abs(read - prev_val_y); | ||
172 | if (diff < prev_diff_y) { | ||
173 | prev_diff_y = diff; | ||
174 | *y = read; | ||
175 | } | ||
176 | prev_val_y = read; | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | |||
181 | static irqreturn_t titsc_irq(int irq, void *dev) | ||
182 | { | ||
183 | struct titsc *ts_dev = dev; | ||
184 | struct input_dev *input_dev = ts_dev->input; | ||
185 | unsigned int status, irqclr = 0; | ||
186 | unsigned int x = 0, y = 0; | ||
187 | unsigned int z1, z2, z; | ||
188 | unsigned int fsm; | ||
189 | unsigned int fifo1count, fifo0count; | ||
190 | int i; | ||
191 | |||
192 | status = titsc_readl(ts_dev, REG_IRQSTATUS); | ||
193 | if (status & IRQENB_FIFO0THRES) { | ||
194 | titsc_read_coordinates(ts_dev, &x, &y); | ||
195 | |||
196 | z1 = titsc_readl(ts_dev, REG_FIFO0) & 0xfff; | ||
197 | z2 = titsc_readl(ts_dev, REG_FIFO1) & 0xfff; | ||
198 | |||
199 | fifo1count = titsc_readl(ts_dev, REG_FIFO1CNT); | ||
200 | for (i = 0; i < fifo1count; i++) | ||
201 | titsc_readl(ts_dev, REG_FIFO1); | ||
202 | |||
203 | fifo0count = titsc_readl(ts_dev, REG_FIFO0CNT); | ||
204 | for (i = 0; i < fifo0count; i++) | ||
205 | titsc_readl(ts_dev, REG_FIFO0); | ||
206 | |||
207 | if (ts_dev->pen_down && z1 != 0 && z2 != 0) { | ||
208 | /* | ||
209 | * Calculate pressure using formula | ||
210 | * Resistance(touch) = x plate resistance * | ||
211 | * x postion/4096 * ((z2 / z1) - 1) | ||
212 | */ | ||
213 | z = z2 - z1; | ||
214 | z *= x; | ||
215 | z *= ts_dev->x_plate_resistance; | ||
216 | z /= z1; | ||
217 | z = (z + 2047) >> 12; | ||
218 | |||
219 | if (z <= MAX_12BIT) { | ||
220 | input_report_abs(input_dev, ABS_X, x); | ||
221 | input_report_abs(input_dev, ABS_Y, y); | ||
222 | input_report_abs(input_dev, ABS_PRESSURE, z); | ||
223 | input_report_key(input_dev, BTN_TOUCH, 1); | ||
224 | input_sync(input_dev); | ||
225 | } | ||
226 | } | ||
227 | irqclr |= IRQENB_FIFO0THRES; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * Time for sequencer to settle, to read | ||
232 | * correct state of the sequencer. | ||
233 | */ | ||
234 | udelay(SEQ_SETTLE); | ||
235 | |||
236 | status = titsc_readl(ts_dev, REG_RAWIRQSTATUS); | ||
237 | if (status & IRQENB_PENUP) { | ||
238 | /* Pen up event */ | ||
239 | fsm = titsc_readl(ts_dev, REG_ADCFSM); | ||
240 | if (fsm == ADCFSM_STEPID) { | ||
241 | ts_dev->pen_down = false; | ||
242 | input_report_key(input_dev, BTN_TOUCH, 0); | ||
243 | input_report_abs(input_dev, ABS_PRESSURE, 0); | ||
244 | input_sync(input_dev); | ||
245 | } else { | ||
246 | ts_dev->pen_down = true; | ||
247 | } | ||
248 | irqclr |= IRQENB_PENUP; | ||
249 | } | ||
250 | |||
251 | titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); | ||
252 | |||
253 | titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC); | ||
254 | return IRQ_HANDLED; | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * The functions for inserting/removing driver as a module. | ||
259 | */ | ||
260 | |||
261 | static int __devinit titsc_probe(struct platform_device *pdev) | ||
262 | { | ||
263 | struct titsc *ts_dev; | ||
264 | struct input_dev *input_dev; | ||
265 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; | ||
266 | struct mfd_tscadc_board *pdata; | ||
267 | int err; | ||
268 | |||
269 | pdata = tscadc_dev->dev->platform_data; | ||
270 | |||
271 | if (!pdata) { | ||
272 | dev_err(&pdev->dev, "Could not find platform data\n"); | ||
273 | return -EINVAL; | ||
274 | } | ||
275 | |||
276 | /* Allocate memory for device */ | ||
277 | ts_dev = kzalloc(sizeof(struct titsc), GFP_KERNEL); | ||
278 | input_dev = input_allocate_device(); | ||
279 | if (!ts_dev || !input_dev) { | ||
280 | dev_err(&pdev->dev, "failed to allocate memory.\n"); | ||
281 | err = -ENOMEM; | ||
282 | goto err_free_mem; | ||
283 | } | ||
284 | |||
285 | tscadc_dev->tsc = ts_dev; | ||
286 | ts_dev->mfd_tscadc = tscadc_dev; | ||
287 | ts_dev->input = input_dev; | ||
288 | ts_dev->irq = tscadc_dev->irq; | ||
289 | ts_dev->wires = pdata->tsc_init->wires; | ||
290 | ts_dev->x_plate_resistance = pdata->tsc_init->x_plate_resistance; | ||
291 | ts_dev->steps_to_configure = pdata->tsc_init->steps_to_configure; | ||
292 | |||
293 | err = request_irq(ts_dev->irq, titsc_irq, | ||
294 | 0, pdev->dev.driver->name, ts_dev); | ||
295 | if (err) { | ||
296 | dev_err(&pdev->dev, "failed to allocate irq.\n"); | ||
297 | goto err_free_mem; | ||
298 | } | ||
299 | |||
300 | titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); | ||
301 | titsc_step_config(ts_dev); | ||
302 | titsc_writel(ts_dev, REG_FIFO0THR, ts_dev->steps_to_configure); | ||
303 | |||
304 | input_dev->name = "ti-tsc"; | ||
305 | input_dev->dev.parent = &pdev->dev; | ||
306 | |||
307 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | ||
308 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | ||
309 | |||
310 | input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); | ||
311 | input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); | ||
312 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); | ||
313 | |||
314 | /* register to the input system */ | ||
315 | err = input_register_device(input_dev); | ||
316 | if (err) | ||
317 | goto err_free_irq; | ||
318 | |||
319 | platform_set_drvdata(pdev, ts_dev); | ||
320 | return 0; | ||
321 | |||
322 | err_free_irq: | ||
323 | free_irq(ts_dev->irq, ts_dev); | ||
324 | err_free_mem: | ||
325 | input_free_device(input_dev); | ||
326 | kfree(ts_dev); | ||
327 | return err; | ||
328 | } | ||
329 | |||
330 | static int __devexit titsc_remove(struct platform_device *pdev) | ||
331 | { | ||
332 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; | ||
333 | struct titsc *ts_dev = tscadc_dev->tsc; | ||
334 | |||
335 | free_irq(ts_dev->irq, ts_dev); | ||
336 | |||
337 | input_unregister_device(ts_dev->input); | ||
338 | |||
339 | platform_set_drvdata(pdev, NULL); | ||
340 | kfree(ts_dev); | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | #ifdef CONFIG_PM | ||
345 | static int titsc_suspend(struct device *dev) | ||
346 | { | ||
347 | struct ti_tscadc_dev *tscadc_dev = dev->platform_data; | ||
348 | struct titsc *ts_dev = tscadc_dev->tsc; | ||
349 | unsigned int idle; | ||
350 | |||
351 | if (device_may_wakeup(tscadc_dev->dev)) { | ||
352 | idle = titsc_readl(ts_dev, REG_IRQENABLE); | ||
353 | titsc_writel(ts_dev, REG_IRQENABLE, | ||
354 | (idle | IRQENB_HW_PEN)); | ||
355 | titsc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB); | ||
356 | } | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static int titsc_resume(struct device *dev) | ||
361 | { | ||
362 | struct ti_tscadc_dev *tscadc_dev = dev->platform_data; | ||
363 | struct titsc *ts_dev = tscadc_dev->tsc; | ||
364 | |||
365 | if (device_may_wakeup(tscadc_dev->dev)) { | ||
366 | titsc_writel(ts_dev, REG_IRQWAKEUP, | ||
367 | 0x00); | ||
368 | titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN); | ||
369 | } | ||
370 | titsc_step_config(ts_dev); | ||
371 | titsc_writel(ts_dev, REG_FIFO0THR, | ||
372 | ts_dev->steps_to_configure); | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static const struct dev_pm_ops titsc_pm_ops = { | ||
377 | .suspend = titsc_suspend, | ||
378 | .resume = titsc_resume, | ||
379 | }; | ||
380 | #define TITSC_PM_OPS (&titsc_pm_ops) | ||
381 | #else | ||
382 | #define TITSC_PM_OPS NULL | ||
383 | #endif | ||
384 | |||
385 | static struct platform_driver ti_tsc_driver = { | ||
386 | .probe = titsc_probe, | ||
387 | .remove = __devexit_p(titsc_remove), | ||
388 | .driver = { | ||
389 | .name = "tsc", | ||
390 | .owner = THIS_MODULE, | ||
391 | .pm = TITSC_PM_OPS, | ||
392 | }, | ||
393 | }; | ||
394 | module_platform_driver(ti_tsc_driver); | ||
395 | |||
396 | MODULE_DESCRIPTION("TI touchscreen controller driver"); | ||
397 | MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); | ||
398 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c deleted file mode 100644 index d229c741d54..00000000000 --- a/drivers/input/touchscreen/ti_tscadc.c +++ /dev/null | |||
@@ -1,486 +0,0 @@ | |||
1 | /* | ||
2 | * TI Touch Screen driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation version 2. | ||
9 | * | ||
10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
11 | * kind, whether express or implied; without even the implied warranty | ||
12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/input.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/clk.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/input/ti_tscadc.h> | ||
28 | #include <linux/delay.h> | ||
29 | |||
30 | #define REG_IRQEOI 0x020 | ||
31 | #define REG_RAWIRQSTATUS 0x024 | ||
32 | #define REG_IRQSTATUS 0x028 | ||
33 | #define REG_IRQENABLE 0x02C | ||
34 | #define REG_IRQWAKEUP 0x034 | ||
35 | #define REG_CTRL 0x040 | ||
36 | #define REG_ADCFSM 0x044 | ||
37 | #define REG_CLKDIV 0x04C | ||
38 | #define REG_SE 0x054 | ||
39 | #define REG_IDLECONFIG 0x058 | ||
40 | #define REG_CHARGECONFIG 0x05C | ||
41 | #define REG_CHARGEDELAY 0x060 | ||
42 | #define REG_STEPCONFIG(n) (0x64 + ((n - 1) * 8)) | ||
43 | #define REG_STEPDELAY(n) (0x68 + ((n - 1) * 8)) | ||
44 | #define REG_STEPCONFIG13 0x0C4 | ||
45 | #define REG_STEPDELAY13 0x0C8 | ||
46 | #define REG_STEPCONFIG14 0x0CC | ||
47 | #define REG_STEPDELAY14 0x0D0 | ||
48 | #define REG_FIFO0CNT 0xE4 | ||
49 | #define REG_FIFO1THR 0xF4 | ||
50 | #define REG_FIFO0 0x100 | ||
51 | #define REG_FIFO1 0x200 | ||
52 | |||
53 | /* Register Bitfields */ | ||
54 | #define IRQWKUP_ENB BIT(0) | ||
55 | #define STPENB_STEPENB 0x7FFF | ||
56 | #define IRQENB_FIFO1THRES BIT(5) | ||
57 | #define IRQENB_PENUP BIT(9) | ||
58 | #define STEPCONFIG_MODE_HWSYNC 0x2 | ||
59 | #define STEPCONFIG_SAMPLES_AVG (1 << 4) | ||
60 | #define STEPCONFIG_XPP (1 << 5) | ||
61 | #define STEPCONFIG_XNN (1 << 6) | ||
62 | #define STEPCONFIG_YPP (1 << 7) | ||
63 | #define STEPCONFIG_YNN (1 << 8) | ||
64 | #define STEPCONFIG_XNP (1 << 9) | ||
65 | #define STEPCONFIG_YPN (1 << 10) | ||
66 | #define STEPCONFIG_INM (1 << 18) | ||
67 | #define STEPCONFIG_INP (1 << 20) | ||
68 | #define STEPCONFIG_INP_5 (1 << 21) | ||
69 | #define STEPCONFIG_FIFO1 (1 << 26) | ||
70 | #define STEPCONFIG_OPENDLY 0xff | ||
71 | #define STEPCONFIG_Z1 (3 << 19) | ||
72 | #define STEPIDLE_INP (1 << 22) | ||
73 | #define STEPCHARGE_RFP (1 << 12) | ||
74 | #define STEPCHARGE_INM (1 << 15) | ||
75 | #define STEPCHARGE_INP (1 << 19) | ||
76 | #define STEPCHARGE_RFM (1 << 23) | ||
77 | #define STEPCHARGE_DELAY 0x1 | ||
78 | #define CNTRLREG_TSCSSENB (1 << 0) | ||
79 | #define CNTRLREG_STEPID (1 << 1) | ||
80 | #define CNTRLREG_STEPCONFIGWRT (1 << 2) | ||
81 | #define CNTRLREG_4WIRE (1 << 5) | ||
82 | #define CNTRLREG_5WIRE (1 << 6) | ||
83 | #define CNTRLREG_8WIRE (3 << 5) | ||
84 | #define CNTRLREG_TSCENB (1 << 7) | ||
85 | #define ADCFSM_STEPID 0x10 | ||
86 | |||
87 | #define SEQ_SETTLE 275 | ||
88 | #define ADC_CLK 3000000 | ||
89 | #define MAX_12BIT ((1 << 12) - 1) | ||
90 | #define TSCADC_DELTA_X 15 | ||
91 | #define TSCADC_DELTA_Y 15 | ||
92 | |||
93 | struct tscadc { | ||
94 | struct input_dev *input; | ||
95 | struct clk *tsc_ick; | ||
96 | void __iomem *tsc_base; | ||
97 | unsigned int irq; | ||
98 | unsigned int wires; | ||
99 | unsigned int x_plate_resistance; | ||
100 | bool pen_down; | ||
101 | }; | ||
102 | |||
103 | static unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg) | ||
104 | { | ||
105 | return readl(ts->tsc_base + reg); | ||
106 | } | ||
107 | |||
108 | static void tscadc_writel(struct tscadc *tsc, unsigned int reg, | ||
109 | unsigned int val) | ||
110 | { | ||
111 | writel(val, tsc->tsc_base + reg); | ||
112 | } | ||
113 | |||
114 | static void tscadc_step_config(struct tscadc *ts_dev) | ||
115 | { | ||
116 | unsigned int config; | ||
117 | int i; | ||
118 | |||
119 | /* Configure the Step registers */ | ||
120 | |||
121 | config = STEPCONFIG_MODE_HWSYNC | | ||
122 | STEPCONFIG_SAMPLES_AVG | STEPCONFIG_XPP; | ||
123 | switch (ts_dev->wires) { | ||
124 | case 4: | ||
125 | config |= STEPCONFIG_INP | STEPCONFIG_XNN; | ||
126 | break; | ||
127 | case 5: | ||
128 | config |= STEPCONFIG_YNN | | ||
129 | STEPCONFIG_INP_5 | STEPCONFIG_XNN | | ||
130 | STEPCONFIG_YPP; | ||
131 | break; | ||
132 | case 8: | ||
133 | config |= STEPCONFIG_INP | STEPCONFIG_XNN; | ||
134 | break; | ||
135 | } | ||
136 | |||
137 | for (i = 1; i < 7; i++) { | ||
138 | tscadc_writel(ts_dev, REG_STEPCONFIG(i), config); | ||
139 | tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | ||
140 | } | ||
141 | |||
142 | config = 0; | ||
143 | config = STEPCONFIG_MODE_HWSYNC | | ||
144 | STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YNN | | ||
145 | STEPCONFIG_INM | STEPCONFIG_FIFO1; | ||
146 | switch (ts_dev->wires) { | ||
147 | case 4: | ||
148 | config |= STEPCONFIG_YPP; | ||
149 | break; | ||
150 | case 5: | ||
151 | config |= STEPCONFIG_XPP | STEPCONFIG_INP_5 | | ||
152 | STEPCONFIG_XNP | STEPCONFIG_YPN; | ||
153 | break; | ||
154 | case 8: | ||
155 | config |= STEPCONFIG_YPP; | ||
156 | break; | ||
157 | } | ||
158 | |||
159 | for (i = 7; i < 13; i++) { | ||
160 | tscadc_writel(ts_dev, REG_STEPCONFIG(i), config); | ||
161 | tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | ||
162 | } | ||
163 | |||
164 | config = 0; | ||
165 | /* Charge step configuration */ | ||
166 | config = STEPCONFIG_XPP | STEPCONFIG_YNN | | ||
167 | STEPCHARGE_RFP | STEPCHARGE_RFM | | ||
168 | STEPCHARGE_INM | STEPCHARGE_INP; | ||
169 | |||
170 | tscadc_writel(ts_dev, REG_CHARGECONFIG, config); | ||
171 | tscadc_writel(ts_dev, REG_CHARGEDELAY, STEPCHARGE_DELAY); | ||
172 | |||
173 | config = 0; | ||
174 | /* Configure to calculate pressure */ | ||
175 | config = STEPCONFIG_MODE_HWSYNC | | ||
176 | STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YPP | | ||
177 | STEPCONFIG_XNN | STEPCONFIG_INM; | ||
178 | tscadc_writel(ts_dev, REG_STEPCONFIG13, config); | ||
179 | tscadc_writel(ts_dev, REG_STEPDELAY13, STEPCONFIG_OPENDLY); | ||
180 | |||
181 | config |= STEPCONFIG_Z1 | STEPCONFIG_FIFO1; | ||
182 | tscadc_writel(ts_dev, REG_STEPCONFIG14, config); | ||
183 | tscadc_writel(ts_dev, REG_STEPDELAY14, STEPCONFIG_OPENDLY); | ||
184 | |||
185 | tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB); | ||
186 | } | ||
187 | |||
188 | static void tscadc_idle_config(struct tscadc *ts_config) | ||
189 | { | ||
190 | unsigned int idleconfig; | ||
191 | |||
192 | idleconfig = STEPCONFIG_YNN | | ||
193 | STEPCONFIG_INM | | ||
194 | STEPCONFIG_YPN | STEPIDLE_INP; | ||
195 | tscadc_writel(ts_config, REG_IDLECONFIG, idleconfig); | ||
196 | } | ||
197 | |||
198 | static void tscadc_read_coordinates(struct tscadc *ts_dev, | ||
199 | unsigned int *x, unsigned int *y) | ||
200 | { | ||
201 | unsigned int fifocount = tscadc_readl(ts_dev, REG_FIFO0CNT); | ||
202 | unsigned int prev_val_x = ~0, prev_val_y = ~0; | ||
203 | unsigned int prev_diff_x = ~0, prev_diff_y = ~0; | ||
204 | unsigned int read, diff; | ||
205 | unsigned int i; | ||
206 | |||
207 | /* | ||
208 | * Delta filter is used to remove large variations in sampled | ||
209 | * values from ADC. The filter tries to predict where the next | ||
210 | * coordinate could be. This is done by taking a previous | ||
211 | * coordinate and subtracting it form current one. Further the | ||
212 | * algorithm compares the difference with that of a present value, | ||
213 | * if true the value is reported to the sub system. | ||
214 | */ | ||
215 | for (i = 0; i < fifocount - 1; i++) { | ||
216 | read = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff; | ||
217 | diff = abs(read - prev_val_x); | ||
218 | if (diff < prev_diff_x) { | ||
219 | prev_diff_x = diff; | ||
220 | *x = read; | ||
221 | } | ||
222 | prev_val_x = read; | ||
223 | |||
224 | read = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff; | ||
225 | diff = abs(read - prev_val_y); | ||
226 | if (diff < prev_diff_y) { | ||
227 | prev_diff_y = diff; | ||
228 | *y = read; | ||
229 | } | ||
230 | prev_val_y = read; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | static irqreturn_t tscadc_irq(int irq, void *dev) | ||
235 | { | ||
236 | struct tscadc *ts_dev = dev; | ||
237 | struct input_dev *input_dev = ts_dev->input; | ||
238 | unsigned int status, irqclr = 0; | ||
239 | unsigned int x = 0, y = 0; | ||
240 | unsigned int z1, z2, z; | ||
241 | unsigned int fsm; | ||
242 | |||
243 | status = tscadc_readl(ts_dev, REG_IRQSTATUS); | ||
244 | if (status & IRQENB_FIFO1THRES) { | ||
245 | tscadc_read_coordinates(ts_dev, &x, &y); | ||
246 | |||
247 | z1 = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff; | ||
248 | z2 = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff; | ||
249 | |||
250 | if (ts_dev->pen_down && z1 != 0 && z2 != 0) { | ||
251 | /* | ||
252 | * Calculate pressure using formula | ||
253 | * Resistance(touch) = x plate resistance * | ||
254 | * x postion/4096 * ((z2 / z1) - 1) | ||
255 | */ | ||
256 | z = z2 - z1; | ||
257 | z *= x; | ||
258 | z *= ts_dev->x_plate_resistance; | ||
259 | z /= z1; | ||
260 | z = (z + 2047) >> 12; | ||
261 | |||
262 | if (z <= MAX_12BIT) { | ||
263 | input_report_abs(input_dev, ABS_X, x); | ||
264 | input_report_abs(input_dev, ABS_Y, y); | ||
265 | input_report_abs(input_dev, ABS_PRESSURE, z); | ||
266 | input_report_key(input_dev, BTN_TOUCH, 1); | ||
267 | input_sync(input_dev); | ||
268 | } | ||
269 | } | ||
270 | irqclr |= IRQENB_FIFO1THRES; | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * Time for sequencer to settle, to read | ||
275 | * correct state of the sequencer. | ||
276 | */ | ||
277 | udelay(SEQ_SETTLE); | ||
278 | |||
279 | status = tscadc_readl(ts_dev, REG_RAWIRQSTATUS); | ||
280 | if (status & IRQENB_PENUP) { | ||
281 | /* Pen up event */ | ||
282 | fsm = tscadc_readl(ts_dev, REG_ADCFSM); | ||
283 | if (fsm == ADCFSM_STEPID) { | ||
284 | ts_dev->pen_down = false; | ||
285 | input_report_key(input_dev, BTN_TOUCH, 0); | ||
286 | input_report_abs(input_dev, ABS_PRESSURE, 0); | ||
287 | input_sync(input_dev); | ||
288 | } else { | ||
289 | ts_dev->pen_down = true; | ||
290 | } | ||
291 | irqclr |= IRQENB_PENUP; | ||
292 | } | ||
293 | |||
294 | tscadc_writel(ts_dev, REG_IRQSTATUS, irqclr); | ||
295 | /* check pending interrupts */ | ||
296 | tscadc_writel(ts_dev, REG_IRQEOI, 0x0); | ||
297 | |||
298 | tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB); | ||
299 | return IRQ_HANDLED; | ||
300 | } | ||
301 | |||
302 | /* | ||
303 | * The functions for inserting/removing driver as a module. | ||
304 | */ | ||
305 | |||
306 | static int __devinit tscadc_probe(struct platform_device *pdev) | ||
307 | { | ||
308 | const struct tsc_data *pdata = pdev->dev.platform_data; | ||
309 | struct resource *res; | ||
310 | struct tscadc *ts_dev; | ||
311 | struct input_dev *input_dev; | ||
312 | struct clk *clk; | ||
313 | int err; | ||
314 | int clk_value, ctrl, irq; | ||
315 | |||
316 | if (!pdata) { | ||
317 | dev_err(&pdev->dev, "missing platform data.\n"); | ||
318 | return -EINVAL; | ||
319 | } | ||
320 | |||
321 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
322 | if (!res) { | ||
323 | dev_err(&pdev->dev, "no memory resource defined.\n"); | ||
324 | return -EINVAL; | ||
325 | } | ||
326 | |||
327 | irq = platform_get_irq(pdev, 0); | ||
328 | if (irq < 0) { | ||
329 | dev_err(&pdev->dev, "no irq ID is specified.\n"); | ||
330 | return -EINVAL; | ||
331 | } | ||
332 | |||
333 | /* Allocate memory for device */ | ||
334 | ts_dev = kzalloc(sizeof(struct tscadc), GFP_KERNEL); | ||
335 | input_dev = input_allocate_device(); | ||
336 | if (!ts_dev || !input_dev) { | ||
337 | dev_err(&pdev->dev, "failed to allocate memory.\n"); | ||
338 | err = -ENOMEM; | ||
339 | goto err_free_mem; | ||
340 | } | ||
341 | |||
342 | ts_dev->input = input_dev; | ||
343 | ts_dev->irq = irq; | ||
344 | ts_dev->wires = pdata->wires; | ||
345 | ts_dev->x_plate_resistance = pdata->x_plate_resistance; | ||
346 | |||
347 | res = request_mem_region(res->start, resource_size(res), pdev->name); | ||
348 | if (!res) { | ||
349 | dev_err(&pdev->dev, "failed to reserve registers.\n"); | ||
350 | err = -EBUSY; | ||
351 | goto err_free_mem; | ||
352 | } | ||
353 | |||
354 | ts_dev->tsc_base = ioremap(res->start, resource_size(res)); | ||
355 | if (!ts_dev->tsc_base) { | ||
356 | dev_err(&pdev->dev, "failed to map registers.\n"); | ||
357 | err = -ENOMEM; | ||
358 | goto err_release_mem_region; | ||
359 | } | ||
360 | |||
361 | err = request_irq(ts_dev->irq, tscadc_irq, | ||
362 | 0, pdev->dev.driver->name, ts_dev); | ||
363 | if (err) { | ||
364 | dev_err(&pdev->dev, "failed to allocate irq.\n"); | ||
365 | goto err_unmap_regs; | ||
366 | } | ||
367 | |||
368 | ts_dev->tsc_ick = clk_get(&pdev->dev, "adc_tsc_ick"); | ||
369 | if (IS_ERR(ts_dev->tsc_ick)) { | ||
370 | dev_err(&pdev->dev, "failed to get TSC ick\n"); | ||
371 | goto err_free_irq; | ||
372 | } | ||
373 | clk_enable(ts_dev->tsc_ick); | ||
374 | |||
375 | clk = clk_get(&pdev->dev, "adc_tsc_fck"); | ||
376 | if (IS_ERR(clk)) { | ||
377 | dev_err(&pdev->dev, "failed to get TSC fck\n"); | ||
378 | err = PTR_ERR(clk); | ||
379 | goto err_disable_clk; | ||
380 | } | ||
381 | |||
382 | clk_value = clk_get_rate(clk) / ADC_CLK; | ||
383 | clk_put(clk); | ||
384 | |||
385 | if (clk_value < 7) { | ||
386 | dev_err(&pdev->dev, "clock input less than min clock requirement\n"); | ||
387 | goto err_disable_clk; | ||
388 | } | ||
389 | /* CLKDIV needs to be configured to the value minus 1 */ | ||
390 | tscadc_writel(ts_dev, REG_CLKDIV, clk_value - 1); | ||
391 | |||
392 | /* Enable wake-up of the SoC using touchscreen */ | ||
393 | tscadc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB); | ||
394 | |||
395 | ctrl = CNTRLREG_STEPCONFIGWRT | | ||
396 | CNTRLREG_TSCENB | | ||
397 | CNTRLREG_STEPID; | ||
398 | switch (ts_dev->wires) { | ||
399 | case 4: | ||
400 | ctrl |= CNTRLREG_4WIRE; | ||
401 | break; | ||
402 | case 5: | ||
403 | ctrl |= CNTRLREG_5WIRE; | ||
404 | break; | ||
405 | case 8: | ||
406 | ctrl |= CNTRLREG_8WIRE; | ||
407 | break; | ||
408 | } | ||
409 | tscadc_writel(ts_dev, REG_CTRL, ctrl); | ||
410 | |||
411 | tscadc_idle_config(ts_dev); | ||
412 | tscadc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO1THRES); | ||
413 | tscadc_step_config(ts_dev); | ||
414 | tscadc_writel(ts_dev, REG_FIFO1THR, 6); | ||
415 | |||
416 | ctrl |= CNTRLREG_TSCSSENB; | ||
417 | tscadc_writel(ts_dev, REG_CTRL, ctrl); | ||
418 | |||
419 | input_dev->name = "ti-tsc-adc"; | ||
420 | input_dev->dev.parent = &pdev->dev; | ||
421 | |||
422 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | ||
423 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | ||
424 | |||
425 | input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); | ||
426 | input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); | ||
427 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); | ||
428 | |||
429 | /* register to the input system */ | ||
430 | err = input_register_device(input_dev); | ||
431 | if (err) | ||
432 | goto err_disable_clk; | ||
433 | |||
434 | platform_set_drvdata(pdev, ts_dev); | ||
435 | return 0; | ||
436 | |||
437 | err_disable_clk: | ||
438 | clk_disable(ts_dev->tsc_ick); | ||
439 | clk_put(ts_dev->tsc_ick); | ||
440 | err_free_irq: | ||
441 | free_irq(ts_dev->irq, ts_dev); | ||
442 | err_unmap_regs: | ||
443 | iounmap(ts_dev->tsc_base); | ||
444 | err_release_mem_region: | ||
445 | release_mem_region(res->start, resource_size(res)); | ||
446 | err_free_mem: | ||
447 | input_free_device(input_dev); | ||
448 | kfree(ts_dev); | ||
449 | return err; | ||
450 | } | ||
451 | |||
452 | static int __devexit tscadc_remove(struct platform_device *pdev) | ||
453 | { | ||
454 | struct tscadc *ts_dev = platform_get_drvdata(pdev); | ||
455 | struct resource *res; | ||
456 | |||
457 | free_irq(ts_dev->irq, ts_dev); | ||
458 | |||
459 | input_unregister_device(ts_dev->input); | ||
460 | |||
461 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
462 | iounmap(ts_dev->tsc_base); | ||
463 | release_mem_region(res->start, resource_size(res)); | ||
464 | |||
465 | clk_disable(ts_dev->tsc_ick); | ||
466 | clk_put(ts_dev->tsc_ick); | ||
467 | |||
468 | kfree(ts_dev); | ||
469 | |||
470 | platform_set_drvdata(pdev, NULL); | ||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | static struct platform_driver ti_tsc_driver = { | ||
475 | .probe = tscadc_probe, | ||
476 | .remove = __devexit_p(tscadc_remove), | ||
477 | .driver = { | ||
478 | .name = "tsc", | ||
479 | .owner = THIS_MODULE, | ||
480 | }, | ||
481 | }; | ||
482 | module_platform_driver(ti_tsc_driver); | ||
483 | |||
484 | MODULE_DESCRIPTION("TI touchscreen controller driver"); | ||
485 | MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); | ||
486 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b63987c6ed2..1c0abd4dfc4 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -104,6 +104,17 @@ config MFD_TI_SSP | |||
104 | To compile this driver as a module, choose M here: the | 104 | To compile this driver as a module, choose M here: the |
105 | module will be called ti-ssp. | 105 | module will be called ti-ssp. |
106 | 106 | ||
107 | config MFD_TI_AM335X_TSCADC | ||
108 | tristate "TI ADC / Touch Screen chip support" | ||
109 | select MFD_CORE | ||
110 | select REGMAP | ||
111 | select REGMAP_MMIO | ||
112 | help | ||
113 | If you say yes here you get support for Texas Instruments series | ||
114 | of Touch Screen /ADC chips. | ||
115 | To compile this driver as a module, choose M here: the | ||
116 | module will be called ti_am335x_tscadc. | ||
117 | |||
107 | config HTC_EGPIO | 118 | config HTC_EGPIO |
108 | bool "HTC EGPIO support" | 119 | bool "HTC EGPIO support" |
109 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM | 120 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM |
@@ -253,6 +264,20 @@ config MFD_TPS65912_SPI | |||
253 | If you say yes here you get support for the TPS65912 series of | 264 | If you say yes here you get support for the TPS65912 series of |
254 | PM chips with SPI interface. | 265 | PM chips with SPI interface. |
255 | 266 | ||
267 | config MFD_TPS80031 | ||
268 | bool "TI TPS80031/TPS80032 Power Management chips" | ||
269 | depends on I2C=y && GENERIC_HARDIRQS | ||
270 | select MFD_CORE | ||
271 | select REGMAP_I2C | ||
272 | select REGMAP_IRQ | ||
273 | help | ||
274 | If you say yes here you get support for the Texas Instruments | ||
275 | TPS80031/ TPS80032 Fully Integrated Power Management with Power | ||
276 | Path and Battery Charger. The device provides five configurable | ||
277 | step-down converters, 11 general purpose LDOs, USB OTG Module, | ||
278 | ADC, RTC, 2 PWM, System Voltage Regulator/Battery Charger with | ||
279 | Power Path from USB, 32K clock generator. | ||
280 | |||
256 | config MENELAUS | 281 | config MENELAUS |
257 | bool "Texas Instruments TWL92330/Menelaus PM chip" | 282 | bool "Texas Instruments TWL92330/Menelaus PM chip" |
258 | depends on I2C=y && ARCH_OMAP2 | 283 | depends on I2C=y && ARCH_OMAP2 |
@@ -309,10 +334,10 @@ config MFD_TWL4030_AUDIO | |||
309 | 334 | ||
310 | config TWL6040_CORE | 335 | config TWL6040_CORE |
311 | bool "Support for TWL6040 audio codec" | 336 | bool "Support for TWL6040 audio codec" |
312 | depends on I2C=y && GENERIC_HARDIRQS | 337 | depends on I2C=y |
313 | select MFD_CORE | 338 | select MFD_CORE |
314 | select REGMAP_I2C | 339 | select REGMAP_I2C |
315 | select IRQ_DOMAIN | 340 | select REGMAP_IRQ |
316 | default n | 341 | default n |
317 | help | 342 | help |
318 | Say yes here if you want support for Texas Instruments TWL6040 audio | 343 | Say yes here if you want support for Texas Instruments TWL6040 audio |
@@ -990,6 +1015,7 @@ config MFD_TPS65090 | |||
990 | depends on I2C=y && GENERIC_HARDIRQS | 1015 | depends on I2C=y && GENERIC_HARDIRQS |
991 | select MFD_CORE | 1016 | select MFD_CORE |
992 | select REGMAP_I2C | 1017 | select REGMAP_I2C |
1018 | select REGMAP_IRQ | ||
993 | help | 1019 | help |
994 | If you say yes here you get support for the TPS65090 series of | 1020 | If you say yes here you get support for the TPS65090 series of |
995 | Power Management chips. | 1021 | Power Management chips. |
@@ -1034,6 +1060,7 @@ config MFD_STA2X11 | |||
1034 | bool "STA2X11 multi function device support" | 1060 | bool "STA2X11 multi function device support" |
1035 | depends on STA2X11 | 1061 | depends on STA2X11 |
1036 | select MFD_CORE | 1062 | select MFD_CORE |
1063 | select REGMAP_MMIO | ||
1037 | 1064 | ||
1038 | config MFD_SYSCON | 1065 | config MFD_SYSCON |
1039 | bool "System Controller Register R/W Based on Regmap" | 1066 | bool "System Controller Register R/W Based on Regmap" |
@@ -1053,6 +1080,38 @@ config MFD_PALMAS | |||
1053 | If you say yes here you get support for the Palmas | 1080 | If you say yes here you get support for the Palmas |
1054 | series of PMIC chips from Texas Instruments. | 1081 | series of PMIC chips from Texas Instruments. |
1055 | 1082 | ||
1083 | config MFD_VIPERBOARD | ||
1084 | tristate "Support for Nano River Technologies Viperboard" | ||
1085 | select MFD_CORE | ||
1086 | depends on USB | ||
1087 | default n | ||
1088 | help | ||
1089 | Say yes here if you want support for Nano River Technologies | ||
1090 | Viperboard. | ||
1091 | There are mfd cell drivers available for i2c master, adc and | ||
1092 | both gpios found on the board. The spi part does not yet | ||
1093 | have a driver. | ||
1094 | You need to select the mfd cell drivers separately. | ||
1095 | The drivers do not support all features the board exposes. | ||
1096 | |||
1097 | config MFD_RETU | ||
1098 | tristate "Support for Retu multi-function device" | ||
1099 | select MFD_CORE | ||
1100 | depends on I2C | ||
1101 | select REGMAP_IRQ | ||
1102 | help | ||
1103 | Retu is a multi-function device found on Nokia Internet Tablets | ||
1104 | (770, N800 and N810). | ||
1105 | |||
1106 | config MFD_AS3711 | ||
1107 | bool "Support for AS3711" | ||
1108 | select MFD_CORE | ||
1109 | select REGMAP_I2C | ||
1110 | select REGMAP_IRQ | ||
1111 | depends on I2C=y | ||
1112 | help | ||
1113 | Support for the AS3711 PMIC from AMS | ||
1114 | |||
1056 | endmenu | 1115 | endmenu |
1057 | endif | 1116 | endif |
1058 | 1117 | ||
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 69f260ae022..8b977f8045a 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -19,6 +19,7 @@ obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o | |||
19 | obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o | 19 | obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o |
20 | obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o | 20 | obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o |
21 | obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o | 21 | obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o |
22 | obj-$(CONFIG_MFD_TI_AM335X_TSCADC) += ti_am335x_tscadc.o | ||
22 | 23 | ||
23 | obj-$(CONFIG_MFD_STA2X11) += sta2x11-mfd.o | 24 | obj-$(CONFIG_MFD_STA2X11) += sta2x11-mfd.o |
24 | obj-$(CONFIG_MFD_STMPE) += stmpe.o | 25 | obj-$(CONFIG_MFD_STMPE) += stmpe.o |
@@ -55,18 +56,19 @@ obj-$(CONFIG_TPS6105X) += tps6105x.o | |||
55 | obj-$(CONFIG_TPS65010) += tps65010.o | 56 | obj-$(CONFIG_TPS65010) += tps65010.o |
56 | obj-$(CONFIG_TPS6507X) += tps6507x.o | 57 | obj-$(CONFIG_TPS6507X) += tps6507x.o |
57 | obj-$(CONFIG_MFD_TPS65217) += tps65217.o | 58 | obj-$(CONFIG_MFD_TPS65217) += tps65217.o |
58 | obj-$(CONFIG_MFD_TPS65910) += tps65910.o tps65910-irq.o | 59 | obj-$(CONFIG_MFD_TPS65910) += tps65910.o |
59 | tps65912-objs := tps65912-core.o tps65912-irq.o | 60 | tps65912-objs := tps65912-core.o tps65912-irq.o |
60 | obj-$(CONFIG_MFD_TPS65912) += tps65912.o | 61 | obj-$(CONFIG_MFD_TPS65912) += tps65912.o |
61 | obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o | 62 | obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o |
62 | obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o | 63 | obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o |
64 | obj-$(CONFIG_MFD_TPS80031) += tps80031.o | ||
63 | obj-$(CONFIG_MENELAUS) += menelaus.o | 65 | obj-$(CONFIG_MENELAUS) += menelaus.o |
64 | 66 | ||
65 | obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o | 67 | obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o |
66 | obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o | 68 | obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o |
67 | obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o | 69 | obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o |
68 | obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o | 70 | obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o |
69 | obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o twl6040-irq.o | 71 | obj-$(CONFIG_TWL6040_CORE) += twl6040.o |
70 | 72 | ||
71 | obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o | 73 | obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o |
72 | obj-$(CONFIG_MFD_MC13XXX_SPI) += mc13xxx-spi.o | 74 | obj-$(CONFIG_MFD_MC13XXX_SPI) += mc13xxx-spi.o |
@@ -89,6 +91,7 @@ obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o | |||
89 | 91 | ||
90 | obj-$(CONFIG_PMIC_DA903X) += da903x.o | 92 | obj-$(CONFIG_PMIC_DA903X) += da903x.o |
91 | 93 | ||
94 | obj-$(CONFIG_PMIC_DA9052) += da9052-irq.o | ||
92 | obj-$(CONFIG_PMIC_DA9052) += da9052-core.o | 95 | obj-$(CONFIG_PMIC_DA9052) += da9052-core.o |
93 | obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o | 96 | obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o |
94 | obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o | 97 | obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o |
@@ -137,8 +140,11 @@ obj-$(CONFIG_MFD_TPS65090) += tps65090.o | |||
137 | obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o | 140 | obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o |
138 | obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o | 141 | obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o |
139 | obj-$(CONFIG_MFD_PALMAS) += palmas.o | 142 | obj-$(CONFIG_MFD_PALMAS) += palmas.o |
143 | obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o | ||
140 | obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o | 144 | obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o |
141 | obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o | 145 | obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o |
142 | obj-$(CONFIG_MFD_SYSCON) += syscon.o | 146 | obj-$(CONFIG_MFD_SYSCON) += syscon.o |
143 | obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o | 147 | obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o |
144 | obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o vexpress-sysreg.o | 148 | obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o vexpress-sysreg.o |
149 | obj-$(CONFIG_MFD_RETU) += retu-mfd.o | ||
150 | obj-$(CONFIG_MFD_AS3711) += as3711.o | ||
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 59da1650fb8..e1650badd10 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c | |||
@@ -586,38 +586,6 @@ int ab8500_suspend(struct ab8500 *ab8500) | |||
586 | return 0; | 586 | return 0; |
587 | } | 587 | } |
588 | 588 | ||
589 | /* AB8500 GPIO Resources */ | ||
590 | static struct resource __devinitdata ab8500_gpio_resources[] = { | ||
591 | { | ||
592 | .name = "GPIO_INT6", | ||
593 | .start = AB8500_INT_GPIO6R, | ||
594 | .end = AB8500_INT_GPIO41F, | ||
595 | .flags = IORESOURCE_IRQ, | ||
596 | } | ||
597 | }; | ||
598 | |||
599 | /* AB9540 GPIO Resources */ | ||
600 | static struct resource __devinitdata ab9540_gpio_resources[] = { | ||
601 | { | ||
602 | .name = "GPIO_INT6", | ||
603 | .start = AB8500_INT_GPIO6R, | ||
604 | .end = AB8500_INT_GPIO41F, | ||
605 | .flags = IORESOURCE_IRQ, | ||
606 | }, | ||
607 | { | ||
608 | .name = "GPIO_INT14", | ||
609 | .start = AB9540_INT_GPIO50R, | ||
610 | .end = AB9540_INT_GPIO54R, | ||
611 | .flags = IORESOURCE_IRQ, | ||
612 | }, | ||
613 | { | ||
614 | .name = "GPIO_INT15", | ||
615 | .start = AB9540_INT_GPIO50F, | ||
616 | .end = AB9540_INT_GPIO54F, | ||
617 | .flags = IORESOURCE_IRQ, | ||
618 | } | ||
619 | }; | ||
620 | |||
621 | static struct resource ab8500_gpadc_resources[] = { | 589 | static struct resource ab8500_gpadc_resources[] = { |
622 | { | 590 | { |
623 | .name = "HW_CONV_END", | 591 | .name = "HW_CONV_END", |
@@ -979,6 +947,10 @@ static struct mfd_cell abx500_common_devs[] = { | |||
979 | .of_compatible = "stericsson,ab8500-regulator", | 947 | .of_compatible = "stericsson,ab8500-regulator", |
980 | }, | 948 | }, |
981 | { | 949 | { |
950 | .name = "abx500-clk", | ||
951 | .of_compatible = "stericsson,abx500-clk", | ||
952 | }, | ||
953 | { | ||
982 | .name = "ab8500-gpadc", | 954 | .name = "ab8500-gpadc", |
983 | .of_compatible = "stericsson,ab8500-gpadc", | 955 | .of_compatible = "stericsson,ab8500-gpadc", |
984 | .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), | 956 | .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), |
@@ -1080,8 +1052,6 @@ static struct mfd_cell ab8500_devs[] = { | |||
1080 | { | 1052 | { |
1081 | .name = "ab8500-gpio", | 1053 | .name = "ab8500-gpio", |
1082 | .of_compatible = "stericsson,ab8500-gpio", | 1054 | .of_compatible = "stericsson,ab8500-gpio", |
1083 | .num_resources = ARRAY_SIZE(ab8500_gpio_resources), | ||
1084 | .resources = ab8500_gpio_resources, | ||
1085 | }, | 1055 | }, |
1086 | { | 1056 | { |
1087 | .name = "ab8500-usb", | 1057 | .name = "ab8500-usb", |
@@ -1098,8 +1068,6 @@ static struct mfd_cell ab8500_devs[] = { | |||
1098 | static struct mfd_cell ab9540_devs[] = { | 1068 | static struct mfd_cell ab9540_devs[] = { |
1099 | { | 1069 | { |
1100 | .name = "ab8500-gpio", | 1070 | .name = "ab8500-gpio", |
1101 | .num_resources = ARRAY_SIZE(ab9540_gpio_resources), | ||
1102 | .resources = ab9540_gpio_resources, | ||
1103 | }, | 1071 | }, |
1104 | { | 1072 | { |
1105 | .name = "ab9540-usb", | 1073 | .name = "ab9540-usb", |
@@ -1284,7 +1252,7 @@ static int ab8500_probe(struct platform_device *pdev) | |||
1284 | int i; | 1252 | int i; |
1285 | u8 value; | 1253 | u8 value; |
1286 | 1254 | ||
1287 | ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL); | 1255 | ab8500 = devm_kzalloc(&pdev->dev, sizeof *ab8500, GFP_KERNEL); |
1288 | if (!ab8500) | 1256 | if (!ab8500) |
1289 | return -ENOMEM; | 1257 | return -ENOMEM; |
1290 | 1258 | ||
@@ -1294,10 +1262,8 @@ static int ab8500_probe(struct platform_device *pdev) | |||
1294 | ab8500->dev = &pdev->dev; | 1262 | ab8500->dev = &pdev->dev; |
1295 | 1263 | ||
1296 | resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 1264 | resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
1297 | if (!resource) { | 1265 | if (!resource) |
1298 | ret = -ENODEV; | 1266 | return -ENODEV; |
1299 | goto out_free_ab8500; | ||
1300 | } | ||
1301 | 1267 | ||
1302 | ab8500->irq = resource->start; | 1268 | ab8500->irq = resource->start; |
1303 | 1269 | ||
@@ -1320,7 +1286,7 @@ static int ab8500_probe(struct platform_device *pdev) | |||
1320 | ret = get_register_interruptible(ab8500, AB8500_MISC, | 1286 | ret = get_register_interruptible(ab8500, AB8500_MISC, |
1321 | AB8500_IC_NAME_REG, &value); | 1287 | AB8500_IC_NAME_REG, &value); |
1322 | if (ret < 0) | 1288 | if (ret < 0) |
1323 | goto out_free_ab8500; | 1289 | return ret; |
1324 | 1290 | ||
1325 | ab8500->version = value; | 1291 | ab8500->version = value; |
1326 | } | 1292 | } |
@@ -1328,7 +1294,7 @@ static int ab8500_probe(struct platform_device *pdev) | |||
1328 | ret = get_register_interruptible(ab8500, AB8500_MISC, | 1294 | ret = get_register_interruptible(ab8500, AB8500_MISC, |
1329 | AB8500_REV_REG, &value); | 1295 | AB8500_REV_REG, &value); |
1330 | if (ret < 0) | 1296 | if (ret < 0) |
1331 | goto out_free_ab8500; | 1297 | return ret; |
1332 | 1298 | ||
1333 | ab8500->chip_id = value; | 1299 | ab8500->chip_id = value; |
1334 | 1300 | ||
@@ -1345,14 +1311,13 @@ static int ab8500_probe(struct platform_device *pdev) | |||
1345 | ab8500->mask_size = AB8500_NUM_IRQ_REGS; | 1311 | ab8500->mask_size = AB8500_NUM_IRQ_REGS; |
1346 | ab8500->irq_reg_offset = ab8500_irq_regoffset; | 1312 | ab8500->irq_reg_offset = ab8500_irq_regoffset; |
1347 | } | 1313 | } |
1348 | ab8500->mask = kzalloc(ab8500->mask_size, GFP_KERNEL); | 1314 | ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size, GFP_KERNEL); |
1349 | if (!ab8500->mask) | 1315 | if (!ab8500->mask) |
1350 | return -ENOMEM; | 1316 | return -ENOMEM; |
1351 | ab8500->oldmask = kzalloc(ab8500->mask_size, GFP_KERNEL); | 1317 | ab8500->oldmask = devm_kzalloc(&pdev->dev, ab8500->mask_size, GFP_KERNEL); |
1352 | if (!ab8500->oldmask) { | 1318 | if (!ab8500->oldmask) |
1353 | ret = -ENOMEM; | 1319 | return -ENOMEM; |
1354 | goto out_freemask; | 1320 | |
1355 | } | ||
1356 | /* | 1321 | /* |
1357 | * ab8500 has switched off due to (SWITCH_OFF_STATUS): | 1322 | * ab8500 has switched off due to (SWITCH_OFF_STATUS): |
1358 | * 0x01 Swoff bit programming | 1323 | * 0x01 Swoff bit programming |
@@ -1406,37 +1371,37 @@ static int ab8500_probe(struct platform_device *pdev) | |||
1406 | 1371 | ||
1407 | ret = abx500_register_ops(ab8500->dev, &ab8500_ops); | 1372 | ret = abx500_register_ops(ab8500->dev, &ab8500_ops); |
1408 | if (ret) | 1373 | if (ret) |
1409 | goto out_freeoldmask; | 1374 | return ret; |
1410 | 1375 | ||
1411 | for (i = 0; i < ab8500->mask_size; i++) | 1376 | for (i = 0; i < ab8500->mask_size; i++) |
1412 | ab8500->mask[i] = ab8500->oldmask[i] = 0xff; | 1377 | ab8500->mask[i] = ab8500->oldmask[i] = 0xff; |
1413 | 1378 | ||
1414 | ret = ab8500_irq_init(ab8500, np); | 1379 | ret = ab8500_irq_init(ab8500, np); |
1415 | if (ret) | 1380 | if (ret) |
1416 | goto out_freeoldmask; | 1381 | return ret; |
1417 | 1382 | ||
1418 | /* Activate this feature only in ab9540 */ | 1383 | /* Activate this feature only in ab9540 */ |
1419 | /* till tests are done on ab8500 1p2 or later*/ | 1384 | /* till tests are done on ab8500 1p2 or later*/ |
1420 | if (is_ab9540(ab8500)) { | 1385 | if (is_ab9540(ab8500)) { |
1421 | ret = request_threaded_irq(ab8500->irq, NULL, | 1386 | ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL, |
1422 | ab8500_hierarchical_irq, | 1387 | ab8500_hierarchical_irq, |
1423 | IRQF_ONESHOT | IRQF_NO_SUSPEND, | 1388 | IRQF_ONESHOT | IRQF_NO_SUSPEND, |
1424 | "ab8500", ab8500); | 1389 | "ab8500", ab8500); |
1425 | } | 1390 | } |
1426 | else { | 1391 | else { |
1427 | ret = request_threaded_irq(ab8500->irq, NULL, | 1392 | ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL, |
1428 | ab8500_irq, | 1393 | ab8500_irq, |
1429 | IRQF_ONESHOT | IRQF_NO_SUSPEND, | 1394 | IRQF_ONESHOT | IRQF_NO_SUSPEND, |
1430 | "ab8500", ab8500); | 1395 | "ab8500", ab8500); |
1431 | if (ret) | 1396 | if (ret) |
1432 | goto out_freeoldmask; | 1397 | return ret; |
1433 | } | 1398 | } |
1434 | 1399 | ||
1435 | ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs, | 1400 | ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs, |
1436 | ARRAY_SIZE(abx500_common_devs), NULL, | 1401 | ARRAY_SIZE(abx500_common_devs), NULL, |
1437 | ab8500->irq_base, ab8500->domain); | 1402 | ab8500->irq_base, ab8500->domain); |
1438 | if (ret) | 1403 | if (ret) |
1439 | goto out_freeirq; | 1404 | return ret; |
1440 | 1405 | ||
1441 | if (is_ab9540(ab8500)) | 1406 | if (is_ab9540(ab8500)) |
1442 | ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, | 1407 | ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, |
@@ -1447,14 +1412,14 @@ static int ab8500_probe(struct platform_device *pdev) | |||
1447 | ARRAY_SIZE(ab8500_devs), NULL, | 1412 | ARRAY_SIZE(ab8500_devs), NULL, |
1448 | ab8500->irq_base, ab8500->domain); | 1413 | ab8500->irq_base, ab8500->domain); |
1449 | if (ret) | 1414 | if (ret) |
1450 | goto out_freeirq; | 1415 | return ret; |
1451 | 1416 | ||
1452 | if (is_ab9540(ab8500) || is_ab8505(ab8500)) | 1417 | if (is_ab9540(ab8500) || is_ab8505(ab8500)) |
1453 | ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs, | 1418 | ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs, |
1454 | ARRAY_SIZE(ab9540_ab8505_devs), NULL, | 1419 | ARRAY_SIZE(ab9540_ab8505_devs), NULL, |
1455 | ab8500->irq_base, ab8500->domain); | 1420 | ab8500->irq_base, ab8500->domain); |
1456 | if (ret) | 1421 | if (ret) |
1457 | goto out_freeirq; | 1422 | return ret; |
1458 | 1423 | ||
1459 | if (!no_bm) { | 1424 | if (!no_bm) { |
1460 | /* Add battery management devices */ | 1425 | /* Add battery management devices */ |
@@ -1475,17 +1440,6 @@ static int ab8500_probe(struct platform_device *pdev) | |||
1475 | dev_err(ab8500->dev, "error creating sysfs entries\n"); | 1440 | dev_err(ab8500->dev, "error creating sysfs entries\n"); |
1476 | 1441 | ||
1477 | return ret; | 1442 | return ret; |
1478 | |||
1479 | out_freeirq: | ||
1480 | free_irq(ab8500->irq, ab8500); | ||
1481 | out_freeoldmask: | ||
1482 | kfree(ab8500->oldmask); | ||
1483 | out_freemask: | ||
1484 | kfree(ab8500->mask); | ||
1485 | out_free_ab8500: | ||
1486 | kfree(ab8500); | ||
1487 | |||
1488 | return ret; | ||
1489 | } | 1443 | } |
1490 | 1444 | ||
1491 | static int ab8500_remove(struct platform_device *pdev) | 1445 | static int ab8500_remove(struct platform_device *pdev) |
@@ -1498,11 +1452,6 @@ static int ab8500_remove(struct platform_device *pdev) | |||
1498 | sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group); | 1452 | sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group); |
1499 | 1453 | ||
1500 | mfd_remove_devices(ab8500->dev); | 1454 | mfd_remove_devices(ab8500->dev); |
1501 | free_irq(ab8500->irq, ab8500); | ||
1502 | |||
1503 | kfree(ab8500->oldmask); | ||
1504 | kfree(ab8500->mask); | ||
1505 | kfree(ab8500); | ||
1506 | 1455 | ||
1507 | return 0; | 1456 | return 0; |
1508 | } | 1457 | } |
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index c784f4602a7..bc8a3edb6bb 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c | |||
@@ -292,6 +292,7 @@ int arizona_dev_init(struct arizona *arizona) | |||
292 | struct device *dev = arizona->dev; | 292 | struct device *dev = arizona->dev; |
293 | const char *type_name; | 293 | const char *type_name; |
294 | unsigned int reg, val; | 294 | unsigned int reg, val; |
295 | int (*apply_patch)(struct arizona *) = NULL; | ||
295 | int ret, i; | 296 | int ret, i; |
296 | 297 | ||
297 | dev_set_drvdata(arizona->dev, arizona); | 298 | dev_set_drvdata(arizona->dev, arizona); |
@@ -391,7 +392,7 @@ int arizona_dev_init(struct arizona *arizona) | |||
391 | arizona->type); | 392 | arizona->type); |
392 | arizona->type = WM5102; | 393 | arizona->type = WM5102; |
393 | } | 394 | } |
394 | ret = wm5102_patch(arizona); | 395 | apply_patch = wm5102_patch; |
395 | break; | 396 | break; |
396 | #endif | 397 | #endif |
397 | #ifdef CONFIG_MFD_WM5110 | 398 | #ifdef CONFIG_MFD_WM5110 |
@@ -402,7 +403,7 @@ int arizona_dev_init(struct arizona *arizona) | |||
402 | arizona->type); | 403 | arizona->type); |
403 | arizona->type = WM5110; | 404 | arizona->type = WM5110; |
404 | } | 405 | } |
405 | ret = wm5110_patch(arizona); | 406 | apply_patch = wm5110_patch; |
406 | break; | 407 | break; |
407 | #endif | 408 | #endif |
408 | default: | 409 | default: |
@@ -412,9 +413,6 @@ int arizona_dev_init(struct arizona *arizona) | |||
412 | 413 | ||
413 | dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A'); | 414 | dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A'); |
414 | 415 | ||
415 | if (ret != 0) | ||
416 | dev_err(arizona->dev, "Failed to apply patch: %d\n", ret); | ||
417 | |||
418 | /* If we have a /RESET GPIO we'll already be reset */ | 416 | /* If we have a /RESET GPIO we'll already be reset */ |
419 | if (!arizona->pdata.reset) { | 417 | if (!arizona->pdata.reset) { |
420 | regcache_mark_dirty(arizona->regmap); | 418 | regcache_mark_dirty(arizona->regmap); |
@@ -438,6 +436,15 @@ int arizona_dev_init(struct arizona *arizona) | |||
438 | goto err_reset; | 436 | goto err_reset; |
439 | } | 437 | } |
440 | 438 | ||
439 | if (apply_patch) { | ||
440 | ret = apply_patch(arizona); | ||
441 | if (ret != 0) { | ||
442 | dev_err(arizona->dev, "Failed to apply patch: %d\n", | ||
443 | ret); | ||
444 | goto err_reset; | ||
445 | } | ||
446 | } | ||
447 | |||
441 | for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { | 448 | for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { |
442 | if (!arizona->pdata.gpio_defaults[i]) | 449 | if (!arizona->pdata.gpio_defaults[i]) |
443 | continue; | 450 | continue; |
diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index b1b00917740..74713bf5371 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c | |||
@@ -224,6 +224,7 @@ int arizona_irq_init(struct arizona *arizona) | |||
224 | arizona->virq = irq_domain_add_linear(NULL, 2, &arizona_domain_ops, | 224 | arizona->virq = irq_domain_add_linear(NULL, 2, &arizona_domain_ops, |
225 | arizona); | 225 | arizona); |
226 | if (!arizona->virq) { | 226 | if (!arizona->virq) { |
227 | dev_err(arizona->dev, "Failed to add core IRQ domain\n"); | ||
227 | ret = -EINVAL; | 228 | ret = -EINVAL; |
228 | goto err; | 229 | goto err; |
229 | } | 230 | } |
diff --git a/drivers/mfd/as3711.c b/drivers/mfd/as3711.c new file mode 100644 index 00000000000..e994c969112 --- /dev/null +++ b/drivers/mfd/as3711.c | |||
@@ -0,0 +1,217 @@ | |||
1 | /* | ||
2 | * AS3711 PMIC MFC driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Renesas Electronics Corporation | ||
5 | * Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the version 2 of the GNU General Public License as | ||
9 | * published by the Free Software Foundation | ||
10 | */ | ||
11 | |||
12 | #include <linux/device.h> | ||
13 | #include <linux/err.h> | ||
14 | #include <linux/i2c.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/mfd/as3711.h> | ||
18 | #include <linux/mfd/core.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/regmap.h> | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | enum { | ||
24 | AS3711_REGULATOR, | ||
25 | AS3711_BACKLIGHT, | ||
26 | }; | ||
27 | |||
28 | /* | ||
29 | * Ok to have it static: it is only used during probing and multiple I2C devices | ||
30 | * cannot be probed simultaneously. Just make sure to avoid stale data. | ||
31 | */ | ||
32 | static struct mfd_cell as3711_subdevs[] = { | ||
33 | [AS3711_REGULATOR] = {.name = "as3711-regulator",}, | ||
34 | [AS3711_BACKLIGHT] = {.name = "as3711-backlight",}, | ||
35 | }; | ||
36 | |||
37 | static bool as3711_volatile_reg(struct device *dev, unsigned int reg) | ||
38 | { | ||
39 | switch (reg) { | ||
40 | case AS3711_GPIO_SIGNAL_IN: | ||
41 | case AS3711_INTERRUPT_STATUS_1: | ||
42 | case AS3711_INTERRUPT_STATUS_2: | ||
43 | case AS3711_INTERRUPT_STATUS_3: | ||
44 | case AS3711_CHARGER_STATUS_1: | ||
45 | case AS3711_CHARGER_STATUS_2: | ||
46 | case AS3711_REG_STATUS: | ||
47 | return true; | ||
48 | } | ||
49 | return false; | ||
50 | } | ||
51 | |||
52 | static bool as3711_precious_reg(struct device *dev, unsigned int reg) | ||
53 | { | ||
54 | switch (reg) { | ||
55 | case AS3711_INTERRUPT_STATUS_1: | ||
56 | case AS3711_INTERRUPT_STATUS_2: | ||
57 | case AS3711_INTERRUPT_STATUS_3: | ||
58 | return true; | ||
59 | } | ||
60 | return false; | ||
61 | } | ||
62 | |||
63 | static bool as3711_readable_reg(struct device *dev, unsigned int reg) | ||
64 | { | ||
65 | switch (reg) { | ||
66 | case AS3711_SD_1_VOLTAGE: | ||
67 | case AS3711_SD_2_VOLTAGE: | ||
68 | case AS3711_SD_3_VOLTAGE: | ||
69 | case AS3711_SD_4_VOLTAGE: | ||
70 | case AS3711_LDO_1_VOLTAGE: | ||
71 | case AS3711_LDO_2_VOLTAGE: | ||
72 | case AS3711_LDO_3_VOLTAGE: | ||
73 | case AS3711_LDO_4_VOLTAGE: | ||
74 | case AS3711_LDO_5_VOLTAGE: | ||
75 | case AS3711_LDO_6_VOLTAGE: | ||
76 | case AS3711_LDO_7_VOLTAGE: | ||
77 | case AS3711_LDO_8_VOLTAGE: | ||
78 | case AS3711_SD_CONTROL: | ||
79 | case AS3711_GPIO_SIGNAL_OUT: | ||
80 | case AS3711_GPIO_SIGNAL_IN: | ||
81 | case AS3711_SD_CONTROL_1: | ||
82 | case AS3711_SD_CONTROL_2: | ||
83 | case AS3711_CURR_CONTROL: | ||
84 | case AS3711_CURR1_VALUE: | ||
85 | case AS3711_CURR2_VALUE: | ||
86 | case AS3711_CURR3_VALUE: | ||
87 | case AS3711_STEPUP_CONTROL_1: | ||
88 | case AS3711_STEPUP_CONTROL_2: | ||
89 | case AS3711_STEPUP_CONTROL_4: | ||
90 | case AS3711_STEPUP_CONTROL_5: | ||
91 | case AS3711_REG_STATUS: | ||
92 | case AS3711_INTERRUPT_STATUS_1: | ||
93 | case AS3711_INTERRUPT_STATUS_2: | ||
94 | case AS3711_INTERRUPT_STATUS_3: | ||
95 | case AS3711_CHARGER_STATUS_1: | ||
96 | case AS3711_CHARGER_STATUS_2: | ||
97 | case AS3711_ASIC_ID_1: | ||
98 | case AS3711_ASIC_ID_2: | ||
99 | return true; | ||
100 | } | ||
101 | return false; | ||
102 | } | ||
103 | |||
104 | static const struct regmap_config as3711_regmap_config = { | ||
105 | .reg_bits = 8, | ||
106 | .val_bits = 8, | ||
107 | .volatile_reg = as3711_volatile_reg, | ||
108 | .readable_reg = as3711_readable_reg, | ||
109 | .precious_reg = as3711_precious_reg, | ||
110 | .max_register = AS3711_MAX_REGS, | ||
111 | .num_reg_defaults_raw = AS3711_MAX_REGS, | ||
112 | .cache_type = REGCACHE_RBTREE, | ||
113 | }; | ||
114 | |||
115 | static int as3711_i2c_probe(struct i2c_client *client, | ||
116 | const struct i2c_device_id *id) | ||
117 | { | ||
118 | struct as3711 *as3711; | ||
119 | struct as3711_platform_data *pdata = client->dev.platform_data; | ||
120 | unsigned int id1, id2; | ||
121 | int ret; | ||
122 | |||
123 | if (!pdata) | ||
124 | dev_dbg(&client->dev, "Platform data not found\n"); | ||
125 | |||
126 | as3711 = devm_kzalloc(&client->dev, sizeof(struct as3711), GFP_KERNEL); | ||
127 | if (!as3711) { | ||
128 | dev_err(&client->dev, "Memory allocation failed\n"); | ||
129 | return -ENOMEM; | ||
130 | } | ||
131 | |||
132 | as3711->dev = &client->dev; | ||
133 | i2c_set_clientdata(client, as3711); | ||
134 | |||
135 | if (client->irq) | ||
136 | dev_notice(&client->dev, "IRQ not supported yet\n"); | ||
137 | |||
138 | as3711->regmap = devm_regmap_init_i2c(client, &as3711_regmap_config); | ||
139 | if (IS_ERR(as3711->regmap)) { | ||
140 | ret = PTR_ERR(as3711->regmap); | ||
141 | dev_err(&client->dev, "regmap initialization failed: %d\n", ret); | ||
142 | return ret; | ||
143 | } | ||
144 | |||
145 | ret = regmap_read(as3711->regmap, AS3711_ASIC_ID_1, &id1); | ||
146 | if (!ret) | ||
147 | ret = regmap_read(as3711->regmap, AS3711_ASIC_ID_2, &id2); | ||
148 | if (ret < 0) { | ||
149 | dev_err(&client->dev, "regmap_read() failed: %d\n", ret); | ||
150 | return ret; | ||
151 | } | ||
152 | if (id1 != 0x8b) | ||
153 | return -ENODEV; | ||
154 | dev_info(as3711->dev, "AS3711 detected: %x:%x\n", id1, id2); | ||
155 | |||
156 | /* We can reuse as3711_subdevs[], it will be copied in mfd_add_devices() */ | ||
157 | if (pdata) { | ||
158 | as3711_subdevs[AS3711_REGULATOR].platform_data = &pdata->regulator; | ||
159 | as3711_subdevs[AS3711_REGULATOR].pdata_size = sizeof(pdata->regulator); | ||
160 | as3711_subdevs[AS3711_BACKLIGHT].platform_data = &pdata->backlight; | ||
161 | as3711_subdevs[AS3711_BACKLIGHT].pdata_size = sizeof(pdata->backlight); | ||
162 | } else { | ||
163 | as3711_subdevs[AS3711_REGULATOR].platform_data = NULL; | ||
164 | as3711_subdevs[AS3711_REGULATOR].pdata_size = 0; | ||
165 | as3711_subdevs[AS3711_BACKLIGHT].platform_data = NULL; | ||
166 | as3711_subdevs[AS3711_BACKLIGHT].pdata_size = 0; | ||
167 | } | ||
168 | |||
169 | ret = mfd_add_devices(as3711->dev, -1, as3711_subdevs, | ||
170 | ARRAY_SIZE(as3711_subdevs), NULL, 0, NULL); | ||
171 | if (ret < 0) | ||
172 | dev_err(&client->dev, "add mfd devices failed: %d\n", ret); | ||
173 | |||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | static int as3711_i2c_remove(struct i2c_client *client) | ||
178 | { | ||
179 | struct as3711 *as3711 = i2c_get_clientdata(client); | ||
180 | |||
181 | mfd_remove_devices(as3711->dev); | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | static const struct i2c_device_id as3711_i2c_id[] = { | ||
186 | {.name = "as3711", .driver_data = 0}, | ||
187 | {} | ||
188 | }; | ||
189 | |||
190 | MODULE_DEVICE_TABLE(i2c, as3711_i2c_id); | ||
191 | |||
192 | static struct i2c_driver as3711_i2c_driver = { | ||
193 | .driver = { | ||
194 | .name = "as3711", | ||
195 | .owner = THIS_MODULE, | ||
196 | }, | ||
197 | .probe = as3711_i2c_probe, | ||
198 | .remove = as3711_i2c_remove, | ||
199 | .id_table = as3711_i2c_id, | ||
200 | }; | ||
201 | |||
202 | static int __init as3711_i2c_init(void) | ||
203 | { | ||
204 | return i2c_add_driver(&as3711_i2c_driver); | ||
205 | } | ||
206 | /* Initialise early */ | ||
207 | subsys_initcall(as3711_i2c_init); | ||
208 | |||
209 | static void __exit as3711_i2c_exit(void) | ||
210 | { | ||
211 | i2c_del_driver(&as3711_i2c_driver); | ||
212 | } | ||
213 | module_exit(as3711_i2c_exit); | ||
214 | |||
215 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); | ||
216 | MODULE_DESCRIPTION("AS3711 PMIC driver"); | ||
217 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c index 689b747416a..a3c9613f916 100644 --- a/drivers/mfd/da9052-core.c +++ b/drivers/mfd/da9052-core.c | |||
@@ -15,7 +15,6 @@ | |||
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/input.h> | 16 | #include <linux/input.h> |
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/irq.h> | ||
19 | #include <linux/mfd/core.h> | 18 | #include <linux/mfd/core.h> |
20 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
21 | #include <linux/module.h> | 20 | #include <linux/module.h> |
@@ -24,16 +23,6 @@ | |||
24 | #include <linux/mfd/da9052/pdata.h> | 23 | #include <linux/mfd/da9052/pdata.h> |
25 | #include <linux/mfd/da9052/reg.h> | 24 | #include <linux/mfd/da9052/reg.h> |
26 | 25 | ||
27 | #define DA9052_NUM_IRQ_REGS 4 | ||
28 | #define DA9052_IRQ_MASK_POS_1 0x01 | ||
29 | #define DA9052_IRQ_MASK_POS_2 0x02 | ||
30 | #define DA9052_IRQ_MASK_POS_3 0x04 | ||
31 | #define DA9052_IRQ_MASK_POS_4 0x08 | ||
32 | #define DA9052_IRQ_MASK_POS_5 0x10 | ||
33 | #define DA9052_IRQ_MASK_POS_6 0x20 | ||
34 | #define DA9052_IRQ_MASK_POS_7 0x40 | ||
35 | #define DA9052_IRQ_MASK_POS_8 0x80 | ||
36 | |||
37 | static bool da9052_reg_readable(struct device *dev, unsigned int reg) | 26 | static bool da9052_reg_readable(struct device *dev, unsigned int reg) |
38 | { | 27 | { |
39 | switch (reg) { | 28 | switch (reg) { |
@@ -425,15 +414,6 @@ err: | |||
425 | } | 414 | } |
426 | EXPORT_SYMBOL_GPL(da9052_adc_manual_read); | 415 | EXPORT_SYMBOL_GPL(da9052_adc_manual_read); |
427 | 416 | ||
428 | static irqreturn_t da9052_auxadc_irq(int irq, void *irq_data) | ||
429 | { | ||
430 | struct da9052 *da9052 = irq_data; | ||
431 | |||
432 | complete(&da9052->done); | ||
433 | |||
434 | return IRQ_HANDLED; | ||
435 | } | ||
436 | |||
437 | int da9052_adc_read_temp(struct da9052 *da9052) | 417 | int da9052_adc_read_temp(struct da9052 *da9052) |
438 | { | 418 | { |
439 | int tbat; | 419 | int tbat; |
@@ -447,74 +427,6 @@ int da9052_adc_read_temp(struct da9052 *da9052) | |||
447 | } | 427 | } |
448 | EXPORT_SYMBOL_GPL(da9052_adc_read_temp); | 428 | EXPORT_SYMBOL_GPL(da9052_adc_read_temp); |
449 | 429 | ||
450 | static struct resource da9052_rtc_resource = { | ||
451 | .name = "ALM", | ||
452 | .start = DA9052_IRQ_ALARM, | ||
453 | .end = DA9052_IRQ_ALARM, | ||
454 | .flags = IORESOURCE_IRQ, | ||
455 | }; | ||
456 | |||
457 | static struct resource da9052_onkey_resource = { | ||
458 | .name = "ONKEY", | ||
459 | .start = DA9052_IRQ_NONKEY, | ||
460 | .end = DA9052_IRQ_NONKEY, | ||
461 | .flags = IORESOURCE_IRQ, | ||
462 | }; | ||
463 | |||
464 | static struct resource da9052_bat_resources[] = { | ||
465 | { | ||
466 | .name = "BATT TEMP", | ||
467 | .start = DA9052_IRQ_TBAT, | ||
468 | .end = DA9052_IRQ_TBAT, | ||
469 | .flags = IORESOURCE_IRQ, | ||
470 | }, | ||
471 | { | ||
472 | .name = "DCIN DET", | ||
473 | .start = DA9052_IRQ_DCIN, | ||
474 | .end = DA9052_IRQ_DCIN, | ||
475 | .flags = IORESOURCE_IRQ, | ||
476 | }, | ||
477 | { | ||
478 | .name = "DCIN REM", | ||
479 | .start = DA9052_IRQ_DCINREM, | ||
480 | .end = DA9052_IRQ_DCINREM, | ||
481 | .flags = IORESOURCE_IRQ, | ||
482 | }, | ||
483 | { | ||
484 | .name = "VBUS DET", | ||
485 | .start = DA9052_IRQ_VBUS, | ||
486 | .end = DA9052_IRQ_VBUS, | ||
487 | .flags = IORESOURCE_IRQ, | ||
488 | }, | ||
489 | { | ||
490 | .name = "VBUS REM", | ||
491 | .start = DA9052_IRQ_VBUSREM, | ||
492 | .end = DA9052_IRQ_VBUSREM, | ||
493 | .flags = IORESOURCE_IRQ, | ||
494 | }, | ||
495 | { | ||
496 | .name = "CHG END", | ||
497 | .start = DA9052_IRQ_CHGEND, | ||
498 | .end = DA9052_IRQ_CHGEND, | ||
499 | .flags = IORESOURCE_IRQ, | ||
500 | }, | ||
501 | }; | ||
502 | |||
503 | static struct resource da9052_tsi_resources[] = { | ||
504 | { | ||
505 | .name = "PENDWN", | ||
506 | .start = DA9052_IRQ_PENDOWN, | ||
507 | .end = DA9052_IRQ_PENDOWN, | ||
508 | .flags = IORESOURCE_IRQ, | ||
509 | }, | ||
510 | { | ||
511 | .name = "TSIRDY", | ||
512 | .start = DA9052_IRQ_TSIREADY, | ||
513 | .end = DA9052_IRQ_TSIREADY, | ||
514 | .flags = IORESOURCE_IRQ, | ||
515 | }, | ||
516 | }; | ||
517 | |||
518 | static struct mfd_cell da9052_subdev_info[] = { | 430 | static struct mfd_cell da9052_subdev_info[] = { |
519 | { | 431 | { |
520 | .name = "da9052-regulator", | 432 | .name = "da9052-regulator", |
@@ -574,13 +486,9 @@ static struct mfd_cell da9052_subdev_info[] = { | |||
574 | }, | 486 | }, |
575 | { | 487 | { |
576 | .name = "da9052-onkey", | 488 | .name = "da9052-onkey", |
577 | .resources = &da9052_onkey_resource, | ||
578 | .num_resources = 1, | ||
579 | }, | 489 | }, |
580 | { | 490 | { |
581 | .name = "da9052-rtc", | 491 | .name = "da9052-rtc", |
582 | .resources = &da9052_rtc_resource, | ||
583 | .num_resources = 1, | ||
584 | }, | 492 | }, |
585 | { | 493 | { |
586 | .name = "da9052-gpio", | 494 | .name = "da9052-gpio", |
@@ -602,160 +510,15 @@ static struct mfd_cell da9052_subdev_info[] = { | |||
602 | }, | 510 | }, |
603 | { | 511 | { |
604 | .name = "da9052-tsi", | 512 | .name = "da9052-tsi", |
605 | .resources = da9052_tsi_resources, | ||
606 | .num_resources = ARRAY_SIZE(da9052_tsi_resources), | ||
607 | }, | 513 | }, |
608 | { | 514 | { |
609 | .name = "da9052-bat", | 515 | .name = "da9052-bat", |
610 | .resources = da9052_bat_resources, | ||
611 | .num_resources = ARRAY_SIZE(da9052_bat_resources), | ||
612 | }, | 516 | }, |
613 | { | 517 | { |
614 | .name = "da9052-watchdog", | 518 | .name = "da9052-watchdog", |
615 | }, | 519 | }, |
616 | }; | 520 | }; |
617 | 521 | ||
618 | static struct regmap_irq da9052_irqs[] = { | ||
619 | [DA9052_IRQ_DCIN] = { | ||
620 | .reg_offset = 0, | ||
621 | .mask = DA9052_IRQ_MASK_POS_1, | ||
622 | }, | ||
623 | [DA9052_IRQ_VBUS] = { | ||
624 | .reg_offset = 0, | ||
625 | .mask = DA9052_IRQ_MASK_POS_2, | ||
626 | }, | ||
627 | [DA9052_IRQ_DCINREM] = { | ||
628 | .reg_offset = 0, | ||
629 | .mask = DA9052_IRQ_MASK_POS_3, | ||
630 | }, | ||
631 | [DA9052_IRQ_VBUSREM] = { | ||
632 | .reg_offset = 0, | ||
633 | .mask = DA9052_IRQ_MASK_POS_4, | ||
634 | }, | ||
635 | [DA9052_IRQ_VDDLOW] = { | ||
636 | .reg_offset = 0, | ||
637 | .mask = DA9052_IRQ_MASK_POS_5, | ||
638 | }, | ||
639 | [DA9052_IRQ_ALARM] = { | ||
640 | .reg_offset = 0, | ||
641 | .mask = DA9052_IRQ_MASK_POS_6, | ||
642 | }, | ||
643 | [DA9052_IRQ_SEQRDY] = { | ||
644 | .reg_offset = 0, | ||
645 | .mask = DA9052_IRQ_MASK_POS_7, | ||
646 | }, | ||
647 | [DA9052_IRQ_COMP1V2] = { | ||
648 | .reg_offset = 0, | ||
649 | .mask = DA9052_IRQ_MASK_POS_8, | ||
650 | }, | ||
651 | [DA9052_IRQ_NONKEY] = { | ||
652 | .reg_offset = 1, | ||
653 | .mask = DA9052_IRQ_MASK_POS_1, | ||
654 | }, | ||
655 | [DA9052_IRQ_IDFLOAT] = { | ||
656 | .reg_offset = 1, | ||
657 | .mask = DA9052_IRQ_MASK_POS_2, | ||
658 | }, | ||
659 | [DA9052_IRQ_IDGND] = { | ||
660 | .reg_offset = 1, | ||
661 | .mask = DA9052_IRQ_MASK_POS_3, | ||
662 | }, | ||
663 | [DA9052_IRQ_CHGEND] = { | ||
664 | .reg_offset = 1, | ||
665 | .mask = DA9052_IRQ_MASK_POS_4, | ||
666 | }, | ||
667 | [DA9052_IRQ_TBAT] = { | ||
668 | .reg_offset = 1, | ||
669 | .mask = DA9052_IRQ_MASK_POS_5, | ||
670 | }, | ||
671 | [DA9052_IRQ_ADC_EOM] = { | ||
672 | .reg_offset = 1, | ||
673 | .mask = DA9052_IRQ_MASK_POS_6, | ||
674 | }, | ||
675 | [DA9052_IRQ_PENDOWN] = { | ||
676 | .reg_offset = 1, | ||
677 | .mask = DA9052_IRQ_MASK_POS_7, | ||
678 | }, | ||
679 | [DA9052_IRQ_TSIREADY] = { | ||
680 | .reg_offset = 1, | ||
681 | .mask = DA9052_IRQ_MASK_POS_8, | ||
682 | }, | ||
683 | [DA9052_IRQ_GPI0] = { | ||
684 | .reg_offset = 2, | ||
685 | .mask = DA9052_IRQ_MASK_POS_1, | ||
686 | }, | ||
687 | [DA9052_IRQ_GPI1] = { | ||
688 | .reg_offset = 2, | ||
689 | .mask = DA9052_IRQ_MASK_POS_2, | ||
690 | }, | ||
691 | [DA9052_IRQ_GPI2] = { | ||
692 | .reg_offset = 2, | ||
693 | .mask = DA9052_IRQ_MASK_POS_3, | ||
694 | }, | ||
695 | [DA9052_IRQ_GPI3] = { | ||
696 | .reg_offset = 2, | ||
697 | .mask = DA9052_IRQ_MASK_POS_4, | ||
698 | }, | ||
699 | [DA9052_IRQ_GPI4] = { | ||
700 | .reg_offset = 2, | ||
701 | .mask = DA9052_IRQ_MASK_POS_5, | ||
702 | }, | ||
703 | [DA9052_IRQ_GPI5] = { | ||
704 | .reg_offset = 2, | ||
705 | .mask = DA9052_IRQ_MASK_POS_6, | ||
706 | }, | ||
707 | [DA9052_IRQ_GPI6] = { | ||
708 | .reg_offset = 2, | ||
709 | .mask = DA9052_IRQ_MASK_POS_7, | ||
710 | }, | ||
711 | [DA9052_IRQ_GPI7] = { | ||
712 | .reg_offset = 2, | ||
713 | .mask = DA9052_IRQ_MASK_POS_8, | ||
714 | }, | ||
715 | [DA9052_IRQ_GPI8] = { | ||
716 | .reg_offset = 3, | ||
717 | .mask = DA9052_IRQ_MASK_POS_1, | ||
718 | }, | ||
719 | [DA9052_IRQ_GPI9] = { | ||
720 | .reg_offset = 3, | ||
721 | .mask = DA9052_IRQ_MASK_POS_2, | ||
722 | }, | ||
723 | [DA9052_IRQ_GPI10] = { | ||
724 | .reg_offset = 3, | ||
725 | .mask = DA9052_IRQ_MASK_POS_3, | ||
726 | }, | ||
727 | [DA9052_IRQ_GPI11] = { | ||
728 | .reg_offset = 3, | ||
729 | .mask = DA9052_IRQ_MASK_POS_4, | ||
730 | }, | ||
731 | [DA9052_IRQ_GPI12] = { | ||
732 | .reg_offset = 3, | ||
733 | .mask = DA9052_IRQ_MASK_POS_5, | ||
734 | }, | ||
735 | [DA9052_IRQ_GPI13] = { | ||
736 | .reg_offset = 3, | ||
737 | .mask = DA9052_IRQ_MASK_POS_6, | ||
738 | }, | ||
739 | [DA9052_IRQ_GPI14] = { | ||
740 | .reg_offset = 3, | ||
741 | .mask = DA9052_IRQ_MASK_POS_7, | ||
742 | }, | ||
743 | [DA9052_IRQ_GPI15] = { | ||
744 | .reg_offset = 3, | ||
745 | .mask = DA9052_IRQ_MASK_POS_8, | ||
746 | }, | ||
747 | }; | ||
748 | |||
749 | static struct regmap_irq_chip da9052_regmap_irq_chip = { | ||
750 | .name = "da9052_irq", | ||
751 | .status_base = DA9052_EVENT_A_REG, | ||
752 | .mask_base = DA9052_IRQ_MASK_A_REG, | ||
753 | .ack_base = DA9052_EVENT_A_REG, | ||
754 | .num_regs = DA9052_NUM_IRQ_REGS, | ||
755 | .irqs = da9052_irqs, | ||
756 | .num_irqs = ARRAY_SIZE(da9052_irqs), | ||
757 | }; | ||
758 | |||
759 | struct regmap_config da9052_regmap_config = { | 522 | struct regmap_config da9052_regmap_config = { |
760 | .reg_bits = 8, | 523 | .reg_bits = 8, |
761 | .val_bits = 8, | 524 | .val_bits = 8, |
@@ -782,45 +545,31 @@ int da9052_device_init(struct da9052 *da9052, u8 chip_id) | |||
782 | 545 | ||
783 | da9052->chip_id = chip_id; | 546 | da9052->chip_id = chip_id; |
784 | 547 | ||
785 | if (!pdata || !pdata->irq_base) | 548 | ret = da9052_irq_init(da9052); |
786 | da9052->irq_base = -1; | 549 | if (ret != 0) { |
787 | else | 550 | dev_err(da9052->dev, "da9052_irq_init failed: %d\n", ret); |
788 | da9052->irq_base = pdata->irq_base; | 551 | return ret; |
789 | 552 | } | |
790 | ret = regmap_add_irq_chip(da9052->regmap, da9052->chip_irq, | ||
791 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
792 | da9052->irq_base, &da9052_regmap_irq_chip, | ||
793 | &da9052->irq_data); | ||
794 | if (ret < 0) | ||
795 | goto regmap_err; | ||
796 | |||
797 | da9052->irq_base = regmap_irq_chip_get_base(da9052->irq_data); | ||
798 | |||
799 | ret = request_threaded_irq(DA9052_IRQ_ADC_EOM, NULL, da9052_auxadc_irq, | ||
800 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
801 | "adc irq", da9052); | ||
802 | if (ret != 0) | ||
803 | dev_err(da9052->dev, "DA9052 ADC IRQ failed ret=%d\n", ret); | ||
804 | 553 | ||
805 | ret = mfd_add_devices(da9052->dev, -1, da9052_subdev_info, | 554 | ret = mfd_add_devices(da9052->dev, -1, da9052_subdev_info, |
806 | ARRAY_SIZE(da9052_subdev_info), NULL, 0, NULL); | 555 | ARRAY_SIZE(da9052_subdev_info), NULL, 0, NULL); |
807 | if (ret) | 556 | if (ret) { |
557 | dev_err(da9052->dev, "mfd_add_devices failed: %d\n", ret); | ||
808 | goto err; | 558 | goto err; |
559 | } | ||
809 | 560 | ||
810 | return 0; | 561 | return 0; |
811 | 562 | ||
812 | err: | 563 | err: |
813 | free_irq(DA9052_IRQ_ADC_EOM, da9052); | 564 | da9052_irq_exit(da9052); |
814 | mfd_remove_devices(da9052->dev); | 565 | |
815 | regmap_err: | ||
816 | return ret; | 566 | return ret; |
817 | } | 567 | } |
818 | 568 | ||
819 | void da9052_device_exit(struct da9052 *da9052) | 569 | void da9052_device_exit(struct da9052 *da9052) |
820 | { | 570 | { |
821 | free_irq(DA9052_IRQ_ADC_EOM, da9052); | ||
822 | regmap_del_irq_chip(da9052->chip_irq, da9052->irq_data); | ||
823 | mfd_remove_devices(da9052->dev); | 571 | mfd_remove_devices(da9052->dev); |
572 | da9052_irq_exit(da9052); | ||
824 | } | 573 | } |
825 | 574 | ||
826 | MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); | 575 | MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); |
diff --git a/drivers/mfd/da9052-irq.c b/drivers/mfd/da9052-irq.c new file mode 100644 index 00000000000..57ae7841f53 --- /dev/null +++ b/drivers/mfd/da9052-irq.c | |||
@@ -0,0 +1,288 @@ | |||
1 | /* | ||
2 | * DA9052 interrupt support | ||
3 | * | ||
4 | * Author: Fabio Estevam <fabio.estevam@freescale.com> | ||
5 | * Based on arizona-irq.c, which is: | ||
6 | * | ||
7 | * Copyright 2012 Wolfson Microelectronics plc | ||
8 | * | ||
9 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <linux/device.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/input.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/irq.h> | ||
21 | #include <linux/irqdomain.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/module.h> | ||
24 | |||
25 | #include <linux/mfd/da9052/da9052.h> | ||
26 | #include <linux/mfd/da9052/reg.h> | ||
27 | |||
28 | #define DA9052_NUM_IRQ_REGS 4 | ||
29 | #define DA9052_IRQ_MASK_POS_1 0x01 | ||
30 | #define DA9052_IRQ_MASK_POS_2 0x02 | ||
31 | #define DA9052_IRQ_MASK_POS_3 0x04 | ||
32 | #define DA9052_IRQ_MASK_POS_4 0x08 | ||
33 | #define DA9052_IRQ_MASK_POS_5 0x10 | ||
34 | #define DA9052_IRQ_MASK_POS_6 0x20 | ||
35 | #define DA9052_IRQ_MASK_POS_7 0x40 | ||
36 | #define DA9052_IRQ_MASK_POS_8 0x80 | ||
37 | |||
38 | static struct regmap_irq da9052_irqs[] = { | ||
39 | [DA9052_IRQ_DCIN] = { | ||
40 | .reg_offset = 0, | ||
41 | .mask = DA9052_IRQ_MASK_POS_1, | ||
42 | }, | ||
43 | [DA9052_IRQ_VBUS] = { | ||
44 | .reg_offset = 0, | ||
45 | .mask = DA9052_IRQ_MASK_POS_2, | ||
46 | }, | ||
47 | [DA9052_IRQ_DCINREM] = { | ||
48 | .reg_offset = 0, | ||
49 | .mask = DA9052_IRQ_MASK_POS_3, | ||
50 | }, | ||
51 | [DA9052_IRQ_VBUSREM] = { | ||
52 | .reg_offset = 0, | ||
53 | .mask = DA9052_IRQ_MASK_POS_4, | ||
54 | }, | ||
55 | [DA9052_IRQ_VDDLOW] = { | ||
56 | .reg_offset = 0, | ||
57 | .mask = DA9052_IRQ_MASK_POS_5, | ||
58 | }, | ||
59 | [DA9052_IRQ_ALARM] = { | ||
60 | .reg_offset = 0, | ||
61 | .mask = DA9052_IRQ_MASK_POS_6, | ||
62 | }, | ||
63 | [DA9052_IRQ_SEQRDY] = { | ||
64 | .reg_offset = 0, | ||
65 | .mask = DA9052_IRQ_MASK_POS_7, | ||
66 | }, | ||
67 | [DA9052_IRQ_COMP1V2] = { | ||
68 | .reg_offset = 0, | ||
69 | .mask = DA9052_IRQ_MASK_POS_8, | ||
70 | }, | ||
71 | [DA9052_IRQ_NONKEY] = { | ||
72 | .reg_offset = 1, | ||
73 | .mask = DA9052_IRQ_MASK_POS_1, | ||
74 | }, | ||
75 | [DA9052_IRQ_IDFLOAT] = { | ||
76 | .reg_offset = 1, | ||
77 | .mask = DA9052_IRQ_MASK_POS_2, | ||
78 | }, | ||
79 | [DA9052_IRQ_IDGND] = { | ||
80 | .reg_offset = 1, | ||
81 | .mask = DA9052_IRQ_MASK_POS_3, | ||
82 | }, | ||
83 | [DA9052_IRQ_CHGEND] = { | ||
84 | .reg_offset = 1, | ||
85 | .mask = DA9052_IRQ_MASK_POS_4, | ||
86 | }, | ||
87 | [DA9052_IRQ_TBAT] = { | ||
88 | .reg_offset = 1, | ||
89 | .mask = DA9052_IRQ_MASK_POS_5, | ||
90 | }, | ||
91 | [DA9052_IRQ_ADC_EOM] = { | ||
92 | .reg_offset = 1, | ||
93 | .mask = DA9052_IRQ_MASK_POS_6, | ||
94 | }, | ||
95 | [DA9052_IRQ_PENDOWN] = { | ||
96 | .reg_offset = 1, | ||
97 | .mask = DA9052_IRQ_MASK_POS_7, | ||
98 | }, | ||
99 | [DA9052_IRQ_TSIREADY] = { | ||
100 | .reg_offset = 1, | ||
101 | .mask = DA9052_IRQ_MASK_POS_8, | ||
102 | }, | ||
103 | [DA9052_IRQ_GPI0] = { | ||
104 | .reg_offset = 2, | ||
105 | .mask = DA9052_IRQ_MASK_POS_1, | ||
106 | }, | ||
107 | [DA9052_IRQ_GPI1] = { | ||
108 | .reg_offset = 2, | ||
109 | .mask = DA9052_IRQ_MASK_POS_2, | ||
110 | }, | ||
111 | [DA9052_IRQ_GPI2] = { | ||
112 | .reg_offset = 2, | ||
113 | .mask = DA9052_IRQ_MASK_POS_3, | ||
114 | }, | ||
115 | [DA9052_IRQ_GPI3] = { | ||
116 | .reg_offset = 2, | ||
117 | .mask = DA9052_IRQ_MASK_POS_4, | ||
118 | }, | ||
119 | [DA9052_IRQ_GPI4] = { | ||
120 | .reg_offset = 2, | ||
121 | .mask = DA9052_IRQ_MASK_POS_5, | ||
122 | }, | ||
123 | [DA9052_IRQ_GPI5] = { | ||
124 | .reg_offset = 2, | ||
125 | .mask = DA9052_IRQ_MASK_POS_6, | ||
126 | }, | ||
127 | [DA9052_IRQ_GPI6] = { | ||
128 | .reg_offset = 2, | ||
129 | .mask = DA9052_IRQ_MASK_POS_7, | ||
130 | }, | ||
131 | [DA9052_IRQ_GPI7] = { | ||
132 | .reg_offset = 2, | ||
133 | .mask = DA9052_IRQ_MASK_POS_8, | ||
134 | }, | ||
135 | [DA9052_IRQ_GPI8] = { | ||
136 | .reg_offset = 3, | ||
137 | .mask = DA9052_IRQ_MASK_POS_1, | ||
138 | }, | ||
139 | [DA9052_IRQ_GPI9] = { | ||
140 | .reg_offset = 3, | ||
141 | .mask = DA9052_IRQ_MASK_POS_2, | ||
142 | }, | ||
143 | [DA9052_IRQ_GPI10] = { | ||
144 | .reg_offset = 3, | ||
145 | .mask = DA9052_IRQ_MASK_POS_3, | ||
146 | }, | ||
147 | [DA9052_IRQ_GPI11] = { | ||
148 | .reg_offset = 3, | ||
149 | .mask = DA9052_IRQ_MASK_POS_4, | ||
150 | }, | ||
151 | [DA9052_IRQ_GPI12] = { | ||
152 | .reg_offset = 3, | ||
153 | .mask = DA9052_IRQ_MASK_POS_5, | ||
154 | }, | ||
155 | [DA9052_IRQ_GPI13] = { | ||
156 | .reg_offset = 3, | ||
157 | .mask = DA9052_IRQ_MASK_POS_6, | ||
158 | }, | ||
159 | [DA9052_IRQ_GPI14] = { | ||
160 | .reg_offset = 3, | ||
161 | .mask = DA9052_IRQ_MASK_POS_7, | ||
162 | }, | ||
163 | [DA9052_IRQ_GPI15] = { | ||
164 | .reg_offset = 3, | ||
165 | .mask = DA9052_IRQ_MASK_POS_8, | ||
166 | }, | ||
167 | }; | ||
168 | |||
169 | static struct regmap_irq_chip da9052_regmap_irq_chip = { | ||
170 | .name = "da9052_irq", | ||
171 | .status_base = DA9052_EVENT_A_REG, | ||
172 | .mask_base = DA9052_IRQ_MASK_A_REG, | ||
173 | .ack_base = DA9052_EVENT_A_REG, | ||
174 | .num_regs = DA9052_NUM_IRQ_REGS, | ||
175 | .irqs = da9052_irqs, | ||
176 | .num_irqs = ARRAY_SIZE(da9052_irqs), | ||
177 | }; | ||
178 | |||
179 | static int da9052_map_irq(struct da9052 *da9052, int irq) | ||
180 | { | ||
181 | return regmap_irq_get_virq(da9052->irq_data, irq); | ||
182 | } | ||
183 | |||
184 | int da9052_enable_irq(struct da9052 *da9052, int irq) | ||
185 | { | ||
186 | irq = da9052_map_irq(da9052, irq); | ||
187 | if (irq < 0) | ||
188 | return irq; | ||
189 | |||
190 | enable_irq(irq); | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | EXPORT_SYMBOL_GPL(da9052_enable_irq); | ||
195 | |||
196 | int da9052_disable_irq(struct da9052 *da9052, int irq) | ||
197 | { | ||
198 | irq = da9052_map_irq(da9052, irq); | ||
199 | if (irq < 0) | ||
200 | return irq; | ||
201 | |||
202 | disable_irq(irq); | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | EXPORT_SYMBOL_GPL(da9052_disable_irq); | ||
207 | |||
208 | int da9052_disable_irq_nosync(struct da9052 *da9052, int irq) | ||
209 | { | ||
210 | irq = da9052_map_irq(da9052, irq); | ||
211 | if (irq < 0) | ||
212 | return irq; | ||
213 | |||
214 | disable_irq_nosync(irq); | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | EXPORT_SYMBOL_GPL(da9052_disable_irq_nosync); | ||
219 | |||
220 | int da9052_request_irq(struct da9052 *da9052, int irq, char *name, | ||
221 | irq_handler_t handler, void *data) | ||
222 | { | ||
223 | irq = da9052_map_irq(da9052, irq); | ||
224 | if (irq < 0) | ||
225 | return irq; | ||
226 | |||
227 | return request_threaded_irq(irq, NULL, handler, | ||
228 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
229 | name, data); | ||
230 | } | ||
231 | EXPORT_SYMBOL_GPL(da9052_request_irq); | ||
232 | |||
233 | void da9052_free_irq(struct da9052 *da9052, int irq, void *data) | ||
234 | { | ||
235 | irq = da9052_map_irq(da9052, irq); | ||
236 | if (irq < 0) | ||
237 | return; | ||
238 | |||
239 | free_irq(irq, data); | ||
240 | } | ||
241 | EXPORT_SYMBOL_GPL(da9052_free_irq); | ||
242 | |||
243 | static irqreturn_t da9052_auxadc_irq(int irq, void *irq_data) | ||
244 | { | ||
245 | struct da9052 *da9052 = irq_data; | ||
246 | |||
247 | complete(&da9052->done); | ||
248 | |||
249 | return IRQ_HANDLED; | ||
250 | } | ||
251 | |||
252 | int da9052_irq_init(struct da9052 *da9052) | ||
253 | { | ||
254 | int ret; | ||
255 | |||
256 | ret = regmap_add_irq_chip(da9052->regmap, da9052->chip_irq, | ||
257 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
258 | -1, &da9052_regmap_irq_chip, | ||
259 | &da9052->irq_data); | ||
260 | if (ret < 0) { | ||
261 | dev_err(da9052->dev, "regmap_add_irq_chip failed: %d\n", ret); | ||
262 | goto regmap_err; | ||
263 | } | ||
264 | |||
265 | ret = da9052_request_irq(da9052, DA9052_IRQ_ADC_EOM, "adc-irq", | ||
266 | da9052_auxadc_irq, da9052); | ||
267 | |||
268 | if (ret != 0) { | ||
269 | dev_err(da9052->dev, "DA9052_IRQ_ADC_EOM failed: %d\n", ret); | ||
270 | goto request_irq_err; | ||
271 | } | ||
272 | |||
273 | return 0; | ||
274 | |||
275 | request_irq_err: | ||
276 | regmap_del_irq_chip(da9052->chip_irq, da9052->irq_data); | ||
277 | regmap_err: | ||
278 | return ret; | ||
279 | |||
280 | } | ||
281 | |||
282 | int da9052_irq_exit(struct da9052 *da9052) | ||
283 | { | ||
284 | da9052_free_irq(da9052, DA9052_IRQ_ADC_EOM , da9052); | ||
285 | regmap_del_irq_chip(da9052->chip_irq, da9052->irq_data); | ||
286 | |||
287 | return 0; | ||
288 | } | ||
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 29710565a08..dc8826d8d69 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c | |||
@@ -2763,7 +2763,7 @@ static int db8500_irq_init(struct device_node *np) | |||
2763 | 2763 | ||
2764 | void __init db8500_prcmu_early_init(void) | 2764 | void __init db8500_prcmu_early_init(void) |
2765 | { | 2765 | { |
2766 | if (cpu_is_u8500v2()) { | 2766 | if (cpu_is_u8500v2() || cpu_is_u9540()) { |
2767 | void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K); | 2767 | void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K); |
2768 | 2768 | ||
2769 | if (tcpm_base != NULL) { | 2769 | if (tcpm_base != NULL) { |
@@ -2781,7 +2781,11 @@ void __init db8500_prcmu_early_init(void) | |||
2781 | iounmap(tcpm_base); | 2781 | iounmap(tcpm_base); |
2782 | } | 2782 | } |
2783 | 2783 | ||
2784 | tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE); | 2784 | if (cpu_is_u9540()) |
2785 | tcdm_base = ioremap_nocache(U8500_PRCMU_TCDM_BASE, | ||
2786 | SZ_4K + SZ_8K) + SZ_8K; | ||
2787 | else | ||
2788 | tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE); | ||
2785 | } else { | 2789 | } else { |
2786 | pr_err("prcmu: Unsupported chip version\n"); | 2790 | pr_err("prcmu: Unsupported chip version\n"); |
2787 | BUG(); | 2791 | BUG(); |
diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index 0b8b55bb9b1..e80587f1a79 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c | |||
@@ -211,7 +211,7 @@ static int jz4740_adc_probe(struct platform_device *pdev) | |||
211 | int ret; | 211 | int ret; |
212 | int irq_base; | 212 | int irq_base; |
213 | 213 | ||
214 | adc = kmalloc(sizeof(*adc), GFP_KERNEL); | 214 | adc = devm_kzalloc(&pdev->dev, sizeof(*adc), GFP_KERNEL); |
215 | if (!adc) { | 215 | if (!adc) { |
216 | dev_err(&pdev->dev, "Failed to allocate driver structure\n"); | 216 | dev_err(&pdev->dev, "Failed to allocate driver structure\n"); |
217 | return -ENOMEM; | 217 | return -ENOMEM; |
@@ -221,30 +221,27 @@ static int jz4740_adc_probe(struct platform_device *pdev) | |||
221 | if (adc->irq < 0) { | 221 | if (adc->irq < 0) { |
222 | ret = adc->irq; | 222 | ret = adc->irq; |
223 | dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); | 223 | dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); |
224 | goto err_free; | 224 | return ret; |
225 | } | 225 | } |
226 | 226 | ||
227 | irq_base = platform_get_irq(pdev, 1); | 227 | irq_base = platform_get_irq(pdev, 1); |
228 | if (irq_base < 0) { | 228 | if (irq_base < 0) { |
229 | ret = irq_base; | 229 | dev_err(&pdev->dev, "Failed to get irq base: %d\n", irq_base); |
230 | dev_err(&pdev->dev, "Failed to get irq base: %d\n", ret); | 230 | return irq_base; |
231 | goto err_free; | ||
232 | } | 231 | } |
233 | 232 | ||
234 | mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 233 | mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
235 | if (!mem_base) { | 234 | if (!mem_base) { |
236 | ret = -ENOENT; | ||
237 | dev_err(&pdev->dev, "Failed to get platform mmio resource\n"); | 235 | dev_err(&pdev->dev, "Failed to get platform mmio resource\n"); |
238 | goto err_free; | 236 | return -ENOENT; |
239 | } | 237 | } |
240 | 238 | ||
241 | /* Only request the shared registers for the MFD driver */ | 239 | /* Only request the shared registers for the MFD driver */ |
242 | adc->mem = request_mem_region(mem_base->start, JZ_REG_ADC_STATUS, | 240 | adc->mem = request_mem_region(mem_base->start, JZ_REG_ADC_STATUS, |
243 | pdev->name); | 241 | pdev->name); |
244 | if (!adc->mem) { | 242 | if (!adc->mem) { |
245 | ret = -EBUSY; | ||
246 | dev_err(&pdev->dev, "Failed to request mmio memory region\n"); | 243 | dev_err(&pdev->dev, "Failed to request mmio memory region\n"); |
247 | goto err_free; | 244 | return -EBUSY; |
248 | } | 245 | } |
249 | 246 | ||
250 | adc->base = ioremap_nocache(adc->mem->start, resource_size(adc->mem)); | 247 | adc->base = ioremap_nocache(adc->mem->start, resource_size(adc->mem)); |
@@ -301,9 +298,6 @@ err_iounmap: | |||
301 | iounmap(adc->base); | 298 | iounmap(adc->base); |
302 | err_release_mem_region: | 299 | err_release_mem_region: |
303 | release_mem_region(adc->mem->start, resource_size(adc->mem)); | 300 | release_mem_region(adc->mem->start, resource_size(adc->mem)); |
304 | err_free: | ||
305 | kfree(adc); | ||
306 | |||
307 | return ret; | 301 | return ret; |
308 | } | 302 | } |
309 | 303 | ||
@@ -325,8 +319,6 @@ static int jz4740_adc_remove(struct platform_device *pdev) | |||
325 | 319 | ||
326 | platform_set_drvdata(pdev, NULL); | 320 | platform_set_drvdata(pdev, NULL); |
327 | 321 | ||
328 | kfree(adc); | ||
329 | |||
330 | return 0; | 322 | return 0; |
331 | } | 323 | } |
332 | 324 | ||
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 2ad24caa07d..d9d930302e9 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c | |||
@@ -734,7 +734,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev, | |||
734 | pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg); | 734 | pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg); |
735 | base_addr = base_addr_cfg & 0x0000ff80; | 735 | base_addr = base_addr_cfg & 0x0000ff80; |
736 | if (!base_addr) { | 736 | if (!base_addr) { |
737 | dev_err(&dev->dev, "I/O space for ACPI uninitialized\n"); | 737 | dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n"); |
738 | lpc_ich_cells[LPC_GPIO].num_resources--; | 738 | lpc_ich_cells[LPC_GPIO].num_resources--; |
739 | goto gpe0_done; | 739 | goto gpe0_done; |
740 | } | 740 | } |
@@ -760,7 +760,7 @@ gpe0_done: | |||
760 | pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg); | 760 | pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg); |
761 | base_addr = base_addr_cfg & 0x0000ff80; | 761 | base_addr = base_addr_cfg & 0x0000ff80; |
762 | if (!base_addr) { | 762 | if (!base_addr) { |
763 | dev_err(&dev->dev, "I/O space for GPIO uninitialized\n"); | 763 | dev_notice(&dev->dev, "I/O space for GPIO uninitialized\n"); |
764 | ret = -ENODEV; | 764 | ret = -ENODEV; |
765 | goto gpio_done; | 765 | goto gpio_done; |
766 | } | 766 | } |
@@ -810,7 +810,7 @@ static int lpc_ich_init_wdt(struct pci_dev *dev, | |||
810 | pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg); | 810 | pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg); |
811 | base_addr = base_addr_cfg & 0x0000ff80; | 811 | base_addr = base_addr_cfg & 0x0000ff80; |
812 | if (!base_addr) { | 812 | if (!base_addr) { |
813 | dev_err(&dev->dev, "I/O space for ACPI uninitialized\n"); | 813 | dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n"); |
814 | ret = -ENODEV; | 814 | ret = -ENODEV; |
815 | goto wdt_done; | 815 | goto wdt_done; |
816 | } | 816 | } |
@@ -830,12 +830,15 @@ static int lpc_ich_init_wdt(struct pci_dev *dev, | |||
830 | * we have to read RCBA from PCI Config space 0xf0 and use | 830 | * we have to read RCBA from PCI Config space 0xf0 and use |
831 | * it as base. GCS = RCBA + ICH6_GCS(0x3410). | 831 | * it as base. GCS = RCBA + ICH6_GCS(0x3410). |
832 | */ | 832 | */ |
833 | if (lpc_chipset_info[id->driver_data].iTCO_version == 2) { | 833 | if (lpc_chipset_info[id->driver_data].iTCO_version == 1) { |
834 | /* Don't register iomem for TCO ver 1 */ | ||
835 | lpc_ich_cells[LPC_WDT].num_resources--; | ||
836 | } else { | ||
834 | pci_read_config_dword(dev, RCBABASE, &base_addr_cfg); | 837 | pci_read_config_dword(dev, RCBABASE, &base_addr_cfg); |
835 | base_addr = base_addr_cfg & 0xffffc000; | 838 | base_addr = base_addr_cfg & 0xffffc000; |
836 | if (!(base_addr_cfg & 1)) { | 839 | if (!(base_addr_cfg & 1)) { |
837 | pr_err("RCBA is disabled by hardware/BIOS, " | 840 | dev_notice(&dev->dev, "RCBA is disabled by " |
838 | "device disabled\n"); | 841 | "hardware/BIOS, device disabled\n"); |
839 | ret = -ENODEV; | 842 | ret = -ENODEV; |
840 | goto wdt_done; | 843 | goto wdt_done; |
841 | } | 844 | } |
@@ -871,6 +874,7 @@ static int lpc_ich_probe(struct pci_dev *dev, | |||
871 | * successfully. | 874 | * successfully. |
872 | */ | 875 | */ |
873 | if (!cell_added) { | 876 | if (!cell_added) { |
877 | dev_warn(&dev->dev, "No MFD cells added\n"); | ||
874 | lpc_ich_restore_config_space(dev); | 878 | lpc_ich_restore_config_space(dev); |
875 | return -ENODEV; | 879 | return -ENODEV; |
876 | } | 880 | } |
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 1aba0238f42..2a9b100c482 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c | |||
@@ -119,6 +119,11 @@ | |||
119 | #define MC13XXX_REVISION_FAB (0x03 << 11) | 119 | #define MC13XXX_REVISION_FAB (0x03 << 11) |
120 | #define MC13XXX_REVISION_ICIDCODE (0x3f << 13) | 120 | #define MC13XXX_REVISION_ICIDCODE (0x3f << 13) |
121 | 121 | ||
122 | #define MC34708_REVISION_REVMETAL (0x07 << 0) | ||
123 | #define MC34708_REVISION_REVFULL (0x07 << 3) | ||
124 | #define MC34708_REVISION_FIN (0x07 << 6) | ||
125 | #define MC34708_REVISION_FAB (0x07 << 9) | ||
126 | |||
122 | #define MC13XXX_ADC1 44 | 127 | #define MC13XXX_ADC1 44 |
123 | #define MC13XXX_ADC1_ADEN (1 << 0) | 128 | #define MC13XXX_ADC1_ADEN (1 << 0) |
124 | #define MC13XXX_ADC1_RAND (1 << 1) | 129 | #define MC13XXX_ADC1_RAND (1 << 1) |
@@ -410,62 +415,52 @@ static irqreturn_t mc13xxx_irq_thread(int irq, void *data) | |||
410 | return IRQ_RETVAL(handled); | 415 | return IRQ_RETVAL(handled); |
411 | } | 416 | } |
412 | 417 | ||
413 | static const char *mc13xxx_chipname[] = { | ||
414 | [MC13XXX_ID_MC13783] = "mc13783", | ||
415 | [MC13XXX_ID_MC13892] = "mc13892", | ||
416 | }; | ||
417 | |||
418 | #define maskval(reg, mask) (((reg) & (mask)) >> __ffs(mask)) | 418 | #define maskval(reg, mask) (((reg) & (mask)) >> __ffs(mask)) |
419 | static int mc13xxx_identify(struct mc13xxx *mc13xxx) | 419 | static void mc13xxx_print_revision(struct mc13xxx *mc13xxx, u32 revision) |
420 | { | 420 | { |
421 | u32 icid; | 421 | dev_info(mc13xxx->dev, "%s: rev: %d.%d, " |
422 | u32 revision; | 422 | "fin: %d, fab: %d, icid: %d/%d\n", |
423 | int ret; | 423 | mc13xxx->variant->name, |
424 | 424 | maskval(revision, MC13XXX_REVISION_REVFULL), | |
425 | /* | 425 | maskval(revision, MC13XXX_REVISION_REVMETAL), |
426 | * Get the generation ID from register 46, as apparently some older | 426 | maskval(revision, MC13XXX_REVISION_FIN), |
427 | * IC revisions only have this info at this location. Newer ICs seem to | 427 | maskval(revision, MC13XXX_REVISION_FAB), |
428 | * have both. | 428 | maskval(revision, MC13XXX_REVISION_ICID), |
429 | */ | 429 | maskval(revision, MC13XXX_REVISION_ICIDCODE)); |
430 | ret = mc13xxx_reg_read(mc13xxx, 46, &icid); | 430 | } |
431 | if (ret) | ||
432 | return ret; | ||
433 | 431 | ||
434 | icid = (icid >> 6) & 0x7; | 432 | static void mc34708_print_revision(struct mc13xxx *mc13xxx, u32 revision) |
433 | { | ||
434 | dev_info(mc13xxx->dev, "%s: rev %d.%d, fin: %d, fab: %d\n", | ||
435 | mc13xxx->variant->name, | ||
436 | maskval(revision, MC34708_REVISION_REVFULL), | ||
437 | maskval(revision, MC34708_REVISION_REVMETAL), | ||
438 | maskval(revision, MC34708_REVISION_FIN), | ||
439 | maskval(revision, MC34708_REVISION_FAB)); | ||
440 | } | ||
435 | 441 | ||
436 | switch (icid) { | 442 | /* These are only exported for mc13xxx-i2c and mc13xxx-spi */ |
437 | case 2: | 443 | struct mc13xxx_variant mc13xxx_variant_mc13783 = { |
438 | mc13xxx->ictype = MC13XXX_ID_MC13783; | 444 | .name = "mc13783", |
439 | break; | 445 | .print_revision = mc13xxx_print_revision, |
440 | case 7: | 446 | }; |
441 | mc13xxx->ictype = MC13XXX_ID_MC13892; | 447 | EXPORT_SYMBOL_GPL(mc13xxx_variant_mc13783); |
442 | break; | ||
443 | default: | ||
444 | mc13xxx->ictype = MC13XXX_ID_INVALID; | ||
445 | break; | ||
446 | } | ||
447 | 448 | ||
448 | if (mc13xxx->ictype == MC13XXX_ID_MC13783 || | 449 | struct mc13xxx_variant mc13xxx_variant_mc13892 = { |
449 | mc13xxx->ictype == MC13XXX_ID_MC13892) { | 450 | .name = "mc13892", |
450 | ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision); | 451 | .print_revision = mc13xxx_print_revision, |
451 | 452 | }; | |
452 | dev_info(mc13xxx->dev, "%s: rev: %d.%d, " | 453 | EXPORT_SYMBOL_GPL(mc13xxx_variant_mc13892); |
453 | "fin: %d, fab: %d, icid: %d/%d\n", | ||
454 | mc13xxx_chipname[mc13xxx->ictype], | ||
455 | maskval(revision, MC13XXX_REVISION_REVFULL), | ||
456 | maskval(revision, MC13XXX_REVISION_REVMETAL), | ||
457 | maskval(revision, MC13XXX_REVISION_FIN), | ||
458 | maskval(revision, MC13XXX_REVISION_FAB), | ||
459 | maskval(revision, MC13XXX_REVISION_ICID), | ||
460 | maskval(revision, MC13XXX_REVISION_ICIDCODE)); | ||
461 | } | ||
462 | 454 | ||
463 | return (mc13xxx->ictype == MC13XXX_ID_INVALID) ? -ENODEV : 0; | 455 | struct mc13xxx_variant mc13xxx_variant_mc34708 = { |
464 | } | 456 | .name = "mc34708", |
457 | .print_revision = mc34708_print_revision, | ||
458 | }; | ||
459 | EXPORT_SYMBOL_GPL(mc13xxx_variant_mc34708); | ||
465 | 460 | ||
466 | static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx) | 461 | static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx) |
467 | { | 462 | { |
468 | return mc13xxx_chipname[mc13xxx->ictype]; | 463 | return mc13xxx->variant->name; |
469 | } | 464 | } |
470 | 465 | ||
471 | int mc13xxx_get_flags(struct mc13xxx *mc13xxx) | 466 | int mc13xxx_get_flags(struct mc13xxx *mc13xxx) |
@@ -653,13 +648,16 @@ int mc13xxx_common_init(struct mc13xxx *mc13xxx, | |||
653 | struct mc13xxx_platform_data *pdata, int irq) | 648 | struct mc13xxx_platform_data *pdata, int irq) |
654 | { | 649 | { |
655 | int ret; | 650 | int ret; |
651 | u32 revision; | ||
656 | 652 | ||
657 | mc13xxx_lock(mc13xxx); | 653 | mc13xxx_lock(mc13xxx); |
658 | 654 | ||
659 | ret = mc13xxx_identify(mc13xxx); | 655 | ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision); |
660 | if (ret) | 656 | if (ret) |
661 | goto err_revision; | 657 | goto err_revision; |
662 | 658 | ||
659 | mc13xxx->variant->print_revision(mc13xxx, revision); | ||
660 | |||
663 | /* mask all irqs */ | 661 | /* mask all irqs */ |
664 | ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK0, 0x00ffffff); | 662 | ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK0, 0x00ffffff); |
665 | if (ret) | 663 | if (ret) |
diff --git a/drivers/mfd/mc13xxx-i2c.c b/drivers/mfd/mc13xxx-i2c.c index 7957999f30b..f745e27ee87 100644 --- a/drivers/mfd/mc13xxx-i2c.c +++ b/drivers/mfd/mc13xxx-i2c.c | |||
@@ -24,7 +24,10 @@ | |||
24 | static const struct i2c_device_id mc13xxx_i2c_device_id[] = { | 24 | static const struct i2c_device_id mc13xxx_i2c_device_id[] = { |
25 | { | 25 | { |
26 | .name = "mc13892", | 26 | .name = "mc13892", |
27 | .driver_data = MC13XXX_ID_MC13892, | 27 | .driver_data = (kernel_ulong_t)&mc13xxx_variant_mc13892, |
28 | }, { | ||
29 | .name = "mc34708", | ||
30 | .driver_data = (kernel_ulong_t)&mc13xxx_variant_mc34708, | ||
28 | }, { | 31 | }, { |
29 | /* sentinel */ | 32 | /* sentinel */ |
30 | } | 33 | } |
@@ -34,7 +37,10 @@ MODULE_DEVICE_TABLE(i2c, mc13xxx_i2c_device_id); | |||
34 | static const struct of_device_id mc13xxx_dt_ids[] = { | 37 | static const struct of_device_id mc13xxx_dt_ids[] = { |
35 | { | 38 | { |
36 | .compatible = "fsl,mc13892", | 39 | .compatible = "fsl,mc13892", |
37 | .data = (void *) &mc13xxx_i2c_device_id[0], | 40 | .data = &mc13xxx_variant_mc13892, |
41 | }, { | ||
42 | .compatible = "fsl,mc34708", | ||
43 | .data = &mc13xxx_variant_mc34708, | ||
38 | }, { | 44 | }, { |
39 | /* sentinel */ | 45 | /* sentinel */ |
40 | } | 46 | } |
@@ -76,11 +82,15 @@ static int mc13xxx_i2c_probe(struct i2c_client *client, | |||
76 | return ret; | 82 | return ret; |
77 | } | 83 | } |
78 | 84 | ||
79 | ret = mc13xxx_common_init(mc13xxx, pdata, client->irq); | 85 | if (client->dev.of_node) { |
86 | const struct of_device_id *of_id = | ||
87 | of_match_device(mc13xxx_dt_ids, &client->dev); | ||
88 | mc13xxx->variant = of_id->data; | ||
89 | } else { | ||
90 | mc13xxx->variant = (void *)id->driver_data; | ||
91 | } | ||
80 | 92 | ||
81 | if (ret == 0 && (id->driver_data != mc13xxx->ictype)) | 93 | ret = mc13xxx_common_init(mc13xxx, pdata, client->irq); |
82 | dev_warn(mc13xxx->dev, | ||
83 | "device id doesn't match auto detection!\n"); | ||
84 | 94 | ||
85 | return ret; | 95 | return ret; |
86 | } | 96 | } |
diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c index cb32f69d80b..3032bae20b6 100644 --- a/drivers/mfd/mc13xxx-spi.c +++ b/drivers/mfd/mc13xxx-spi.c | |||
@@ -28,10 +28,13 @@ | |||
28 | static const struct spi_device_id mc13xxx_device_id[] = { | 28 | static const struct spi_device_id mc13xxx_device_id[] = { |
29 | { | 29 | { |
30 | .name = "mc13783", | 30 | .name = "mc13783", |
31 | .driver_data = MC13XXX_ID_MC13783, | 31 | .driver_data = (kernel_ulong_t)&mc13xxx_variant_mc13783, |
32 | }, { | 32 | }, { |
33 | .name = "mc13892", | 33 | .name = "mc13892", |
34 | .driver_data = MC13XXX_ID_MC13892, | 34 | .driver_data = (kernel_ulong_t)&mc13xxx_variant_mc13892, |
35 | }, { | ||
36 | .name = "mc34708", | ||
37 | .driver_data = (kernel_ulong_t)&mc13xxx_variant_mc34708, | ||
35 | }, { | 38 | }, { |
36 | /* sentinel */ | 39 | /* sentinel */ |
37 | } | 40 | } |
@@ -39,8 +42,9 @@ static const struct spi_device_id mc13xxx_device_id[] = { | |||
39 | MODULE_DEVICE_TABLE(spi, mc13xxx_device_id); | 42 | MODULE_DEVICE_TABLE(spi, mc13xxx_device_id); |
40 | 43 | ||
41 | static const struct of_device_id mc13xxx_dt_ids[] = { | 44 | static const struct of_device_id mc13xxx_dt_ids[] = { |
42 | { .compatible = "fsl,mc13783", .data = (void *) MC13XXX_ID_MC13783, }, | 45 | { .compatible = "fsl,mc13783", .data = &mc13xxx_variant_mc13783, }, |
43 | { .compatible = "fsl,mc13892", .data = (void *) MC13XXX_ID_MC13892, }, | 46 | { .compatible = "fsl,mc13892", .data = &mc13xxx_variant_mc13892, }, |
47 | { .compatible = "fsl,mc34708", .data = &mc13xxx_variant_mc34708, }, | ||
44 | { /* sentinel */ } | 48 | { /* sentinel */ } |
45 | }; | 49 | }; |
46 | MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids); | 50 | MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids); |
@@ -144,19 +148,18 @@ static int mc13xxx_spi_probe(struct spi_device *spi) | |||
144 | return ret; | 148 | return ret; |
145 | } | 149 | } |
146 | 150 | ||
147 | ret = mc13xxx_common_init(mc13xxx, pdata, spi->irq); | 151 | if (spi->dev.of_node) { |
152 | const struct of_device_id *of_id = | ||
153 | of_match_device(mc13xxx_dt_ids, &spi->dev); | ||
148 | 154 | ||
149 | if (ret) { | 155 | mc13xxx->variant = of_id->data; |
150 | dev_set_drvdata(&spi->dev, NULL); | ||
151 | } else { | 156 | } else { |
152 | const struct spi_device_id *devid = | 157 | const struct spi_device_id *id_entry = spi_get_device_id(spi); |
153 | spi_get_device_id(spi); | 158 | |
154 | if (!devid || devid->driver_data != mc13xxx->ictype) | 159 | mc13xxx->variant = (void *)id_entry->driver_data; |
155 | dev_warn(mc13xxx->dev, | ||
156 | "device id doesn't match auto detection!\n"); | ||
157 | } | 160 | } |
158 | 161 | ||
159 | return ret; | 162 | return mc13xxx_common_init(mc13xxx, pdata, spi->irq); |
160 | } | 163 | } |
161 | 164 | ||
162 | static int mc13xxx_spi_remove(struct spi_device *spi) | 165 | static int mc13xxx_spi_remove(struct spi_device *spi) |
diff --git a/drivers/mfd/mc13xxx.h b/drivers/mfd/mc13xxx.h index bbba06feea0..460ec5c7b18 100644 --- a/drivers/mfd/mc13xxx.h +++ b/drivers/mfd/mc13xxx.h | |||
@@ -13,19 +13,25 @@ | |||
13 | #include <linux/regmap.h> | 13 | #include <linux/regmap.h> |
14 | #include <linux/mfd/mc13xxx.h> | 14 | #include <linux/mfd/mc13xxx.h> |
15 | 15 | ||
16 | enum mc13xxx_id { | 16 | #define MC13XXX_NUMREGS 0x3f |
17 | MC13XXX_ID_MC13783, | 17 | |
18 | MC13XXX_ID_MC13892, | 18 | struct mc13xxx; |
19 | MC13XXX_ID_INVALID, | 19 | |
20 | struct mc13xxx_variant { | ||
21 | const char *name; | ||
22 | void (*print_revision)(struct mc13xxx *mc13xxx, u32 revision); | ||
20 | }; | 23 | }; |
21 | 24 | ||
22 | #define MC13XXX_NUMREGS 0x3f | 25 | extern struct mc13xxx_variant |
26 | mc13xxx_variant_mc13783, | ||
27 | mc13xxx_variant_mc13892, | ||
28 | mc13xxx_variant_mc34708; | ||
23 | 29 | ||
24 | struct mc13xxx { | 30 | struct mc13xxx { |
25 | struct regmap *regmap; | 31 | struct regmap *regmap; |
26 | 32 | ||
27 | struct device *dev; | 33 | struct device *dev; |
28 | enum mc13xxx_id ictype; | 34 | const struct mc13xxx_variant *variant; |
29 | 35 | ||
30 | struct mutex lock; | 36 | struct mutex lock; |
31 | int irq; | 37 | int irq; |
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index f8b77711ad2..7604f4e5df4 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c | |||
@@ -21,6 +21,10 @@ | |||
21 | #include <linux/irqdomain.h> | 21 | #include <linux/irqdomain.h> |
22 | #include <linux/of.h> | 22 | #include <linux/of.h> |
23 | 23 | ||
24 | static struct device_type mfd_dev_type = { | ||
25 | .name = "mfd_device", | ||
26 | }; | ||
27 | |||
24 | int mfd_cell_enable(struct platform_device *pdev) | 28 | int mfd_cell_enable(struct platform_device *pdev) |
25 | { | 29 | { |
26 | const struct mfd_cell *cell = mfd_get_cell(pdev); | 30 | const struct mfd_cell *cell = mfd_get_cell(pdev); |
@@ -91,6 +95,7 @@ static int mfd_add_device(struct device *parent, int id, | |||
91 | goto fail_device; | 95 | goto fail_device; |
92 | 96 | ||
93 | pdev->dev.parent = parent; | 97 | pdev->dev.parent = parent; |
98 | pdev->dev.type = &mfd_dev_type; | ||
94 | 99 | ||
95 | if (parent->of_node && cell->of_compatible) { | 100 | if (parent->of_node && cell->of_compatible) { |
96 | for_each_child_of_node(parent->of_node, np) { | 101 | for_each_child_of_node(parent->of_node, np) { |
@@ -204,10 +209,16 @@ EXPORT_SYMBOL(mfd_add_devices); | |||
204 | 209 | ||
205 | static int mfd_remove_devices_fn(struct device *dev, void *c) | 210 | static int mfd_remove_devices_fn(struct device *dev, void *c) |
206 | { | 211 | { |
207 | struct platform_device *pdev = to_platform_device(dev); | 212 | struct platform_device *pdev; |
208 | const struct mfd_cell *cell = mfd_get_cell(pdev); | 213 | const struct mfd_cell *cell; |
209 | atomic_t **usage_count = c; | 214 | atomic_t **usage_count = c; |
210 | 215 | ||
216 | if (dev->type != &mfd_dev_type) | ||
217 | return 0; | ||
218 | |||
219 | pdev = to_platform_device(dev); | ||
220 | cell = mfd_get_cell(pdev); | ||
221 | |||
211 | /* find the base address of usage_count pointers (for freeing) */ | 222 | /* find the base address of usage_count pointers (for freeing) */ |
212 | if (!*usage_count || (cell->usage_count < *usage_count)) | 223 | if (!*usage_count || (cell->usage_count < *usage_count)) |
213 | *usage_count = cell->usage_count; | 224 | *usage_count = cell->usage_count; |
diff --git a/drivers/mfd/rc5t583-irq.c b/drivers/mfd/rc5t583-irq.c index fe00cdd6f83..b41db596870 100644 --- a/drivers/mfd/rc5t583-irq.c +++ b/drivers/mfd/rc5t583-irq.c | |||
@@ -345,7 +345,7 @@ int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base) | |||
345 | mutex_init(&rc5t583->irq_lock); | 345 | mutex_init(&rc5t583->irq_lock); |
346 | 346 | ||
347 | /* Initailize all int register to 0 */ | 347 | /* Initailize all int register to 0 */ |
348 | for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++) { | 348 | for (i = 0; i < RC5T583_MAX_INTERRUPT_EN_REGS; i++) { |
349 | ret = rc5t583_write(rc5t583->dev, irq_en_add[i], | 349 | ret = rc5t583_write(rc5t583->dev, irq_en_add[i], |
350 | rc5t583->irq_en_reg[i]); | 350 | rc5t583->irq_en_reg[i]); |
351 | if (ret < 0) | 351 | if (ret < 0) |
diff --git a/drivers/mfd/retu-mfd.c b/drivers/mfd/retu-mfd.c new file mode 100644 index 00000000000..7ff4a37ab0c --- /dev/null +++ b/drivers/mfd/retu-mfd.c | |||
@@ -0,0 +1,264 @@ | |||
1 | /* | ||
2 | * Retu MFD driver | ||
3 | * | ||
4 | * Copyright (C) 2004, 2005 Nokia Corporation | ||
5 | * | ||
6 | * Based on code written by Juha Yrjölä, David Weinehall and Mikko Ylinen. | ||
7 | * Rewritten by Aaro Koskinen. | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General | ||
10 | * Public License. See the file "COPYING" in the main directory of this | ||
11 | * archive for more details. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/err.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/irq.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/mutex.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/regmap.h> | ||
27 | #include <linux/mfd/core.h> | ||
28 | #include <linux/mfd/retu.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/moduleparam.h> | ||
31 | |||
32 | /* Registers */ | ||
33 | #define RETU_REG_ASICR 0x00 /* ASIC ID and revision */ | ||
34 | #define RETU_REG_ASICR_VILMA (1 << 7) /* Bit indicating Vilma */ | ||
35 | #define RETU_REG_IDR 0x01 /* Interrupt ID */ | ||
36 | #define RETU_REG_IMR 0x02 /* Interrupt mask */ | ||
37 | |||
38 | /* Interrupt sources */ | ||
39 | #define RETU_INT_PWR 0 /* Power button */ | ||
40 | |||
41 | struct retu_dev { | ||
42 | struct regmap *regmap; | ||
43 | struct device *dev; | ||
44 | struct mutex mutex; | ||
45 | struct regmap_irq_chip_data *irq_data; | ||
46 | }; | ||
47 | |||
48 | static struct resource retu_pwrbutton_res[] = { | ||
49 | { | ||
50 | .name = "retu-pwrbutton", | ||
51 | .start = RETU_INT_PWR, | ||
52 | .end = RETU_INT_PWR, | ||
53 | .flags = IORESOURCE_IRQ, | ||
54 | }, | ||
55 | }; | ||
56 | |||
57 | static struct mfd_cell retu_devs[] = { | ||
58 | { | ||
59 | .name = "retu-wdt" | ||
60 | }, | ||
61 | { | ||
62 | .name = "retu-pwrbutton", | ||
63 | .resources = retu_pwrbutton_res, | ||
64 | .num_resources = ARRAY_SIZE(retu_pwrbutton_res), | ||
65 | } | ||
66 | }; | ||
67 | |||
68 | static struct regmap_irq retu_irqs[] = { | ||
69 | [RETU_INT_PWR] = { | ||
70 | .mask = 1 << RETU_INT_PWR, | ||
71 | } | ||
72 | }; | ||
73 | |||
74 | static struct regmap_irq_chip retu_irq_chip = { | ||
75 | .name = "RETU", | ||
76 | .irqs = retu_irqs, | ||
77 | .num_irqs = ARRAY_SIZE(retu_irqs), | ||
78 | .num_regs = 1, | ||
79 | .status_base = RETU_REG_IDR, | ||
80 | .mask_base = RETU_REG_IMR, | ||
81 | .ack_base = RETU_REG_IDR, | ||
82 | }; | ||
83 | |||
84 | /* Retu device registered for the power off. */ | ||
85 | static struct retu_dev *retu_pm_power_off; | ||
86 | |||
87 | int retu_read(struct retu_dev *rdev, u8 reg) | ||
88 | { | ||
89 | int ret; | ||
90 | int value; | ||
91 | |||
92 | mutex_lock(&rdev->mutex); | ||
93 | ret = regmap_read(rdev->regmap, reg, &value); | ||
94 | mutex_unlock(&rdev->mutex); | ||
95 | |||
96 | return ret ? ret : value; | ||
97 | } | ||
98 | EXPORT_SYMBOL_GPL(retu_read); | ||
99 | |||
100 | int retu_write(struct retu_dev *rdev, u8 reg, u16 data) | ||
101 | { | ||
102 | int ret; | ||
103 | |||
104 | mutex_lock(&rdev->mutex); | ||
105 | ret = regmap_write(rdev->regmap, reg, data); | ||
106 | mutex_unlock(&rdev->mutex); | ||
107 | |||
108 | return ret; | ||
109 | } | ||
110 | EXPORT_SYMBOL_GPL(retu_write); | ||
111 | |||
112 | static void retu_power_off(void) | ||
113 | { | ||
114 | struct retu_dev *rdev = retu_pm_power_off; | ||
115 | int reg; | ||
116 | |||
117 | mutex_lock(&retu_pm_power_off->mutex); | ||
118 | |||
119 | /* Ignore power button state */ | ||
120 | regmap_read(rdev->regmap, RETU_REG_CC1, ®); | ||
121 | regmap_write(rdev->regmap, RETU_REG_CC1, reg | 2); | ||
122 | |||
123 | /* Expire watchdog immediately */ | ||
124 | regmap_write(rdev->regmap, RETU_REG_WATCHDOG, 0); | ||
125 | |||
126 | /* Wait for poweroff */ | ||
127 | for (;;) | ||
128 | cpu_relax(); | ||
129 | |||
130 | mutex_unlock(&retu_pm_power_off->mutex); | ||
131 | } | ||
132 | |||
133 | static int retu_regmap_read(void *context, const void *reg, size_t reg_size, | ||
134 | void *val, size_t val_size) | ||
135 | { | ||
136 | int ret; | ||
137 | struct device *dev = context; | ||
138 | struct i2c_client *i2c = to_i2c_client(dev); | ||
139 | |||
140 | BUG_ON(reg_size != 1 || val_size != 2); | ||
141 | |||
142 | ret = i2c_smbus_read_word_data(i2c, *(u8 const *)reg); | ||
143 | if (ret < 0) | ||
144 | return ret; | ||
145 | |||
146 | *(u16 *)val = ret; | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int retu_regmap_write(void *context, const void *data, size_t count) | ||
151 | { | ||
152 | u8 reg; | ||
153 | u16 val; | ||
154 | struct device *dev = context; | ||
155 | struct i2c_client *i2c = to_i2c_client(dev); | ||
156 | |||
157 | BUG_ON(count != sizeof(reg) + sizeof(val)); | ||
158 | memcpy(®, data, sizeof(reg)); | ||
159 | memcpy(&val, data + sizeof(reg), sizeof(val)); | ||
160 | return i2c_smbus_write_word_data(i2c, reg, val); | ||
161 | } | ||
162 | |||
163 | static struct regmap_bus retu_bus = { | ||
164 | .read = retu_regmap_read, | ||
165 | .write = retu_regmap_write, | ||
166 | .val_format_endian_default = REGMAP_ENDIAN_NATIVE, | ||
167 | }; | ||
168 | |||
169 | static struct regmap_config retu_config = { | ||
170 | .reg_bits = 8, | ||
171 | .val_bits = 16, | ||
172 | }; | ||
173 | |||
174 | static int __devinit retu_probe(struct i2c_client *i2c, | ||
175 | const struct i2c_device_id *id) | ||
176 | { | ||
177 | struct retu_dev *rdev; | ||
178 | int ret; | ||
179 | |||
180 | rdev = devm_kzalloc(&i2c->dev, sizeof(*rdev), GFP_KERNEL); | ||
181 | if (rdev == NULL) | ||
182 | return -ENOMEM; | ||
183 | |||
184 | i2c_set_clientdata(i2c, rdev); | ||
185 | rdev->dev = &i2c->dev; | ||
186 | mutex_init(&rdev->mutex); | ||
187 | rdev->regmap = devm_regmap_init(&i2c->dev, &retu_bus, &i2c->dev, | ||
188 | &retu_config); | ||
189 | if (IS_ERR(rdev->regmap)) | ||
190 | return PTR_ERR(rdev->regmap); | ||
191 | |||
192 | ret = retu_read(rdev, RETU_REG_ASICR); | ||
193 | if (ret < 0) { | ||
194 | dev_err(rdev->dev, "could not read Retu revision: %d\n", ret); | ||
195 | return ret; | ||
196 | } | ||
197 | |||
198 | dev_info(rdev->dev, "Retu%s v%d.%d found\n", | ||
199 | (ret & RETU_REG_ASICR_VILMA) ? " & Vilma" : "", | ||
200 | (ret >> 4) & 0x7, ret & 0xf); | ||
201 | |||
202 | /* Mask all RETU interrupts. */ | ||
203 | ret = retu_write(rdev, RETU_REG_IMR, 0xffff); | ||
204 | if (ret < 0) | ||
205 | return ret; | ||
206 | |||
207 | ret = regmap_add_irq_chip(rdev->regmap, i2c->irq, IRQF_ONESHOT, -1, | ||
208 | &retu_irq_chip, &rdev->irq_data); | ||
209 | if (ret < 0) | ||
210 | return ret; | ||
211 | |||
212 | ret = mfd_add_devices(rdev->dev, -1, retu_devs, ARRAY_SIZE(retu_devs), | ||
213 | NULL, regmap_irq_chip_get_base(rdev->irq_data), | ||
214 | NULL); | ||
215 | if (ret < 0) { | ||
216 | regmap_del_irq_chip(i2c->irq, rdev->irq_data); | ||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | if (!pm_power_off) { | ||
221 | retu_pm_power_off = rdev; | ||
222 | pm_power_off = retu_power_off; | ||
223 | } | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static int __devexit retu_remove(struct i2c_client *i2c) | ||
229 | { | ||
230 | struct retu_dev *rdev = i2c_get_clientdata(i2c); | ||
231 | |||
232 | if (retu_pm_power_off == rdev) { | ||
233 | pm_power_off = NULL; | ||
234 | retu_pm_power_off = NULL; | ||
235 | } | ||
236 | mfd_remove_devices(rdev->dev); | ||
237 | regmap_del_irq_chip(i2c->irq, rdev->irq_data); | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static const struct i2c_device_id retu_id[] = { | ||
243 | { "retu-mfd", 0 }, | ||
244 | { } | ||
245 | }; | ||
246 | MODULE_DEVICE_TABLE(i2c, retu_id); | ||
247 | |||
248 | static struct i2c_driver retu_driver = { | ||
249 | .driver = { | ||
250 | .name = "retu-mfd", | ||
251 | .owner = THIS_MODULE, | ||
252 | }, | ||
253 | .probe = retu_probe, | ||
254 | .remove = retu_remove, | ||
255 | .id_table = retu_id, | ||
256 | }; | ||
257 | module_i2c_driver(retu_driver); | ||
258 | |||
259 | MODULE_DESCRIPTION("Retu MFD driver"); | ||
260 | MODULE_AUTHOR("Juha Yrjölä"); | ||
261 | MODULE_AUTHOR("David Weinehall"); | ||
262 | MODULE_AUTHOR("Mikko Ylinen"); | ||
263 | MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>"); | ||
264 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index 56d4377c62c..3a44efa2920 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/slab.h> | ||
25 | #include <linux/dma-mapping.h> | 26 | #include <linux/dma-mapping.h> |
26 | #include <linux/highmem.h> | 27 | #include <linux/highmem.h> |
27 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c index c901fa50fea..0dd84e99081 100644 --- a/drivers/mfd/sec-irq.c +++ b/drivers/mfd/sec-irq.c | |||
@@ -24,67 +24,67 @@ | |||
24 | 24 | ||
25 | static struct regmap_irq s2mps11_irqs[] = { | 25 | static struct regmap_irq s2mps11_irqs[] = { |
26 | [S2MPS11_IRQ_PWRONF] = { | 26 | [S2MPS11_IRQ_PWRONF] = { |
27 | .reg_offset = 1, | 27 | .reg_offset = 0, |
28 | .mask = S2MPS11_IRQ_PWRONF_MASK, | 28 | .mask = S2MPS11_IRQ_PWRONF_MASK, |
29 | }, | 29 | }, |
30 | [S2MPS11_IRQ_PWRONR] = { | 30 | [S2MPS11_IRQ_PWRONR] = { |
31 | .reg_offset = 1, | 31 | .reg_offset = 0, |
32 | .mask = S2MPS11_IRQ_PWRONR_MASK, | 32 | .mask = S2MPS11_IRQ_PWRONR_MASK, |
33 | }, | 33 | }, |
34 | [S2MPS11_IRQ_JIGONBF] = { | 34 | [S2MPS11_IRQ_JIGONBF] = { |
35 | .reg_offset = 1, | 35 | .reg_offset = 0, |
36 | .mask = S2MPS11_IRQ_JIGONBF_MASK, | 36 | .mask = S2MPS11_IRQ_JIGONBF_MASK, |
37 | }, | 37 | }, |
38 | [S2MPS11_IRQ_JIGONBR] = { | 38 | [S2MPS11_IRQ_JIGONBR] = { |
39 | .reg_offset = 1, | 39 | .reg_offset = 0, |
40 | .mask = S2MPS11_IRQ_JIGONBR_MASK, | 40 | .mask = S2MPS11_IRQ_JIGONBR_MASK, |
41 | }, | 41 | }, |
42 | [S2MPS11_IRQ_ACOKBF] = { | 42 | [S2MPS11_IRQ_ACOKBF] = { |
43 | .reg_offset = 1, | 43 | .reg_offset = 0, |
44 | .mask = S2MPS11_IRQ_ACOKBF_MASK, | 44 | .mask = S2MPS11_IRQ_ACOKBF_MASK, |
45 | }, | 45 | }, |
46 | [S2MPS11_IRQ_ACOKBR] = { | 46 | [S2MPS11_IRQ_ACOKBR] = { |
47 | .reg_offset = 1, | 47 | .reg_offset = 0, |
48 | .mask = S2MPS11_IRQ_ACOKBR_MASK, | 48 | .mask = S2MPS11_IRQ_ACOKBR_MASK, |
49 | }, | 49 | }, |
50 | [S2MPS11_IRQ_PWRON1S] = { | 50 | [S2MPS11_IRQ_PWRON1S] = { |
51 | .reg_offset = 1, | 51 | .reg_offset = 0, |
52 | .mask = S2MPS11_IRQ_PWRON1S_MASK, | 52 | .mask = S2MPS11_IRQ_PWRON1S_MASK, |
53 | }, | 53 | }, |
54 | [S2MPS11_IRQ_MRB] = { | 54 | [S2MPS11_IRQ_MRB] = { |
55 | .reg_offset = 1, | 55 | .reg_offset = 0, |
56 | .mask = S2MPS11_IRQ_MRB_MASK, | 56 | .mask = S2MPS11_IRQ_MRB_MASK, |
57 | }, | 57 | }, |
58 | [S2MPS11_IRQ_RTC60S] = { | 58 | [S2MPS11_IRQ_RTC60S] = { |
59 | .reg_offset = 2, | 59 | .reg_offset = 1, |
60 | .mask = S2MPS11_IRQ_RTC60S_MASK, | 60 | .mask = S2MPS11_IRQ_RTC60S_MASK, |
61 | }, | 61 | }, |
62 | [S2MPS11_IRQ_RTCA1] = { | 62 | [S2MPS11_IRQ_RTCA1] = { |
63 | .reg_offset = 2, | 63 | .reg_offset = 1, |
64 | .mask = S2MPS11_IRQ_RTCA1_MASK, | 64 | .mask = S2MPS11_IRQ_RTCA1_MASK, |
65 | }, | 65 | }, |
66 | [S2MPS11_IRQ_RTCA2] = { | 66 | [S2MPS11_IRQ_RTCA2] = { |
67 | .reg_offset = 2, | 67 | .reg_offset = 1, |
68 | .mask = S2MPS11_IRQ_RTCA2_MASK, | 68 | .mask = S2MPS11_IRQ_RTCA2_MASK, |
69 | }, | 69 | }, |
70 | [S2MPS11_IRQ_SMPL] = { | 70 | [S2MPS11_IRQ_SMPL] = { |
71 | .reg_offset = 2, | 71 | .reg_offset = 1, |
72 | .mask = S2MPS11_IRQ_SMPL_MASK, | 72 | .mask = S2MPS11_IRQ_SMPL_MASK, |
73 | }, | 73 | }, |
74 | [S2MPS11_IRQ_RTC1S] = { | 74 | [S2MPS11_IRQ_RTC1S] = { |
75 | .reg_offset = 2, | 75 | .reg_offset = 1, |
76 | .mask = S2MPS11_IRQ_RTC1S_MASK, | 76 | .mask = S2MPS11_IRQ_RTC1S_MASK, |
77 | }, | 77 | }, |
78 | [S2MPS11_IRQ_WTSR] = { | 78 | [S2MPS11_IRQ_WTSR] = { |
79 | .reg_offset = 2, | 79 | .reg_offset = 1, |
80 | .mask = S2MPS11_IRQ_WTSR_MASK, | 80 | .mask = S2MPS11_IRQ_WTSR_MASK, |
81 | }, | 81 | }, |
82 | [S2MPS11_IRQ_INT120C] = { | 82 | [S2MPS11_IRQ_INT120C] = { |
83 | .reg_offset = 3, | 83 | .reg_offset = 2, |
84 | .mask = S2MPS11_IRQ_INT120C_MASK, | 84 | .mask = S2MPS11_IRQ_INT120C_MASK, |
85 | }, | 85 | }, |
86 | [S2MPS11_IRQ_INT140C] = { | 86 | [S2MPS11_IRQ_INT140C] = { |
87 | .reg_offset = 3, | 87 | .reg_offset = 2, |
88 | .mask = S2MPS11_IRQ_INT140C_MASK, | 88 | .mask = S2MPS11_IRQ_INT140C_MASK, |
89 | }, | 89 | }, |
90 | }; | 90 | }; |
@@ -92,146 +92,146 @@ static struct regmap_irq s2mps11_irqs[] = { | |||
92 | 92 | ||
93 | static struct regmap_irq s5m8767_irqs[] = { | 93 | static struct regmap_irq s5m8767_irqs[] = { |
94 | [S5M8767_IRQ_PWRR] = { | 94 | [S5M8767_IRQ_PWRR] = { |
95 | .reg_offset = 1, | 95 | .reg_offset = 0, |
96 | .mask = S5M8767_IRQ_PWRR_MASK, | 96 | .mask = S5M8767_IRQ_PWRR_MASK, |
97 | }, | 97 | }, |
98 | [S5M8767_IRQ_PWRF] = { | 98 | [S5M8767_IRQ_PWRF] = { |
99 | .reg_offset = 1, | 99 | .reg_offset = 0, |
100 | .mask = S5M8767_IRQ_PWRF_MASK, | 100 | .mask = S5M8767_IRQ_PWRF_MASK, |
101 | }, | 101 | }, |
102 | [S5M8767_IRQ_PWR1S] = { | 102 | [S5M8767_IRQ_PWR1S] = { |
103 | .reg_offset = 1, | 103 | .reg_offset = 0, |
104 | .mask = S5M8767_IRQ_PWR1S_MASK, | 104 | .mask = S5M8767_IRQ_PWR1S_MASK, |
105 | }, | 105 | }, |
106 | [S5M8767_IRQ_JIGR] = { | 106 | [S5M8767_IRQ_JIGR] = { |
107 | .reg_offset = 1, | 107 | .reg_offset = 0, |
108 | .mask = S5M8767_IRQ_JIGR_MASK, | 108 | .mask = S5M8767_IRQ_JIGR_MASK, |
109 | }, | 109 | }, |
110 | [S5M8767_IRQ_JIGF] = { | 110 | [S5M8767_IRQ_JIGF] = { |
111 | .reg_offset = 1, | 111 | .reg_offset = 0, |
112 | .mask = S5M8767_IRQ_JIGF_MASK, | 112 | .mask = S5M8767_IRQ_JIGF_MASK, |
113 | }, | 113 | }, |
114 | [S5M8767_IRQ_LOWBAT2] = { | 114 | [S5M8767_IRQ_LOWBAT2] = { |
115 | .reg_offset = 1, | 115 | .reg_offset = 0, |
116 | .mask = S5M8767_IRQ_LOWBAT2_MASK, | 116 | .mask = S5M8767_IRQ_LOWBAT2_MASK, |
117 | }, | 117 | }, |
118 | [S5M8767_IRQ_LOWBAT1] = { | 118 | [S5M8767_IRQ_LOWBAT1] = { |
119 | .reg_offset = 1, | 119 | .reg_offset = 0, |
120 | .mask = S5M8767_IRQ_LOWBAT1_MASK, | 120 | .mask = S5M8767_IRQ_LOWBAT1_MASK, |
121 | }, | 121 | }, |
122 | [S5M8767_IRQ_MRB] = { | 122 | [S5M8767_IRQ_MRB] = { |
123 | .reg_offset = 2, | 123 | .reg_offset = 1, |
124 | .mask = S5M8767_IRQ_MRB_MASK, | 124 | .mask = S5M8767_IRQ_MRB_MASK, |
125 | }, | 125 | }, |
126 | [S5M8767_IRQ_DVSOK2] = { | 126 | [S5M8767_IRQ_DVSOK2] = { |
127 | .reg_offset = 2, | 127 | .reg_offset = 1, |
128 | .mask = S5M8767_IRQ_DVSOK2_MASK, | 128 | .mask = S5M8767_IRQ_DVSOK2_MASK, |
129 | }, | 129 | }, |
130 | [S5M8767_IRQ_DVSOK3] = { | 130 | [S5M8767_IRQ_DVSOK3] = { |
131 | .reg_offset = 2, | 131 | .reg_offset = 1, |
132 | .mask = S5M8767_IRQ_DVSOK3_MASK, | 132 | .mask = S5M8767_IRQ_DVSOK3_MASK, |
133 | }, | 133 | }, |
134 | [S5M8767_IRQ_DVSOK4] = { | 134 | [S5M8767_IRQ_DVSOK4] = { |
135 | .reg_offset = 2, | 135 | .reg_offset = 1, |
136 | .mask = S5M8767_IRQ_DVSOK4_MASK, | 136 | .mask = S5M8767_IRQ_DVSOK4_MASK, |
137 | }, | 137 | }, |
138 | [S5M8767_IRQ_RTC60S] = { | 138 | [S5M8767_IRQ_RTC60S] = { |
139 | .reg_offset = 3, | 139 | .reg_offset = 2, |
140 | .mask = S5M8767_IRQ_RTC60S_MASK, | 140 | .mask = S5M8767_IRQ_RTC60S_MASK, |
141 | }, | 141 | }, |
142 | [S5M8767_IRQ_RTCA1] = { | 142 | [S5M8767_IRQ_RTCA1] = { |
143 | .reg_offset = 3, | 143 | .reg_offset = 2, |
144 | .mask = S5M8767_IRQ_RTCA1_MASK, | 144 | .mask = S5M8767_IRQ_RTCA1_MASK, |
145 | }, | 145 | }, |
146 | [S5M8767_IRQ_RTCA2] = { | 146 | [S5M8767_IRQ_RTCA2] = { |
147 | .reg_offset = 3, | 147 | .reg_offset = 2, |
148 | .mask = S5M8767_IRQ_RTCA2_MASK, | 148 | .mask = S5M8767_IRQ_RTCA2_MASK, |
149 | }, | 149 | }, |
150 | [S5M8767_IRQ_SMPL] = { | 150 | [S5M8767_IRQ_SMPL] = { |
151 | .reg_offset = 3, | 151 | .reg_offset = 2, |
152 | .mask = S5M8767_IRQ_SMPL_MASK, | 152 | .mask = S5M8767_IRQ_SMPL_MASK, |
153 | }, | 153 | }, |
154 | [S5M8767_IRQ_RTC1S] = { | 154 | [S5M8767_IRQ_RTC1S] = { |
155 | .reg_offset = 3, | 155 | .reg_offset = 2, |
156 | .mask = S5M8767_IRQ_RTC1S_MASK, | 156 | .mask = S5M8767_IRQ_RTC1S_MASK, |
157 | }, | 157 | }, |
158 | [S5M8767_IRQ_WTSR] = { | 158 | [S5M8767_IRQ_WTSR] = { |
159 | .reg_offset = 3, | 159 | .reg_offset = 2, |
160 | .mask = S5M8767_IRQ_WTSR_MASK, | 160 | .mask = S5M8767_IRQ_WTSR_MASK, |
161 | }, | 161 | }, |
162 | }; | 162 | }; |
163 | 163 | ||
164 | static struct regmap_irq s5m8763_irqs[] = { | 164 | static struct regmap_irq s5m8763_irqs[] = { |
165 | [S5M8763_IRQ_DCINF] = { | 165 | [S5M8763_IRQ_DCINF] = { |
166 | .reg_offset = 1, | 166 | .reg_offset = 0, |
167 | .mask = S5M8763_IRQ_DCINF_MASK, | 167 | .mask = S5M8763_IRQ_DCINF_MASK, |
168 | }, | 168 | }, |
169 | [S5M8763_IRQ_DCINR] = { | 169 | [S5M8763_IRQ_DCINR] = { |
170 | .reg_offset = 1, | 170 | .reg_offset = 0, |
171 | .mask = S5M8763_IRQ_DCINR_MASK, | 171 | .mask = S5M8763_IRQ_DCINR_MASK, |
172 | }, | 172 | }, |
173 | [S5M8763_IRQ_JIGF] = { | 173 | [S5M8763_IRQ_JIGF] = { |
174 | .reg_offset = 1, | 174 | .reg_offset = 0, |
175 | .mask = S5M8763_IRQ_JIGF_MASK, | 175 | .mask = S5M8763_IRQ_JIGF_MASK, |
176 | }, | 176 | }, |
177 | [S5M8763_IRQ_JIGR] = { | 177 | [S5M8763_IRQ_JIGR] = { |
178 | .reg_offset = 1, | 178 | .reg_offset = 0, |
179 | .mask = S5M8763_IRQ_JIGR_MASK, | 179 | .mask = S5M8763_IRQ_JIGR_MASK, |
180 | }, | 180 | }, |
181 | [S5M8763_IRQ_PWRONF] = { | 181 | [S5M8763_IRQ_PWRONF] = { |
182 | .reg_offset = 1, | 182 | .reg_offset = 0, |
183 | .mask = S5M8763_IRQ_PWRONF_MASK, | 183 | .mask = S5M8763_IRQ_PWRONF_MASK, |
184 | }, | 184 | }, |
185 | [S5M8763_IRQ_PWRONR] = { | 185 | [S5M8763_IRQ_PWRONR] = { |
186 | .reg_offset = 1, | 186 | .reg_offset = 0, |
187 | .mask = S5M8763_IRQ_PWRONR_MASK, | 187 | .mask = S5M8763_IRQ_PWRONR_MASK, |
188 | }, | 188 | }, |
189 | [S5M8763_IRQ_WTSREVNT] = { | 189 | [S5M8763_IRQ_WTSREVNT] = { |
190 | .reg_offset = 2, | 190 | .reg_offset = 1, |
191 | .mask = S5M8763_IRQ_WTSREVNT_MASK, | 191 | .mask = S5M8763_IRQ_WTSREVNT_MASK, |
192 | }, | 192 | }, |
193 | [S5M8763_IRQ_SMPLEVNT] = { | 193 | [S5M8763_IRQ_SMPLEVNT] = { |
194 | .reg_offset = 2, | 194 | .reg_offset = 1, |
195 | .mask = S5M8763_IRQ_SMPLEVNT_MASK, | 195 | .mask = S5M8763_IRQ_SMPLEVNT_MASK, |
196 | }, | 196 | }, |
197 | [S5M8763_IRQ_ALARM1] = { | 197 | [S5M8763_IRQ_ALARM1] = { |
198 | .reg_offset = 2, | 198 | .reg_offset = 1, |
199 | .mask = S5M8763_IRQ_ALARM1_MASK, | 199 | .mask = S5M8763_IRQ_ALARM1_MASK, |
200 | }, | 200 | }, |
201 | [S5M8763_IRQ_ALARM0] = { | 201 | [S5M8763_IRQ_ALARM0] = { |
202 | .reg_offset = 2, | 202 | .reg_offset = 1, |
203 | .mask = S5M8763_IRQ_ALARM0_MASK, | 203 | .mask = S5M8763_IRQ_ALARM0_MASK, |
204 | }, | 204 | }, |
205 | [S5M8763_IRQ_ONKEY1S] = { | 205 | [S5M8763_IRQ_ONKEY1S] = { |
206 | .reg_offset = 3, | 206 | .reg_offset = 2, |
207 | .mask = S5M8763_IRQ_ONKEY1S_MASK, | 207 | .mask = S5M8763_IRQ_ONKEY1S_MASK, |
208 | }, | 208 | }, |
209 | [S5M8763_IRQ_TOPOFFR] = { | 209 | [S5M8763_IRQ_TOPOFFR] = { |
210 | .reg_offset = 3, | 210 | .reg_offset = 2, |
211 | .mask = S5M8763_IRQ_TOPOFFR_MASK, | 211 | .mask = S5M8763_IRQ_TOPOFFR_MASK, |
212 | }, | 212 | }, |
213 | [S5M8763_IRQ_DCINOVPR] = { | 213 | [S5M8763_IRQ_DCINOVPR] = { |
214 | .reg_offset = 3, | 214 | .reg_offset = 2, |
215 | .mask = S5M8763_IRQ_DCINOVPR_MASK, | 215 | .mask = S5M8763_IRQ_DCINOVPR_MASK, |
216 | }, | 216 | }, |
217 | [S5M8763_IRQ_CHGRSTF] = { | 217 | [S5M8763_IRQ_CHGRSTF] = { |
218 | .reg_offset = 3, | 218 | .reg_offset = 2, |
219 | .mask = S5M8763_IRQ_CHGRSTF_MASK, | 219 | .mask = S5M8763_IRQ_CHGRSTF_MASK, |
220 | }, | 220 | }, |
221 | [S5M8763_IRQ_DONER] = { | 221 | [S5M8763_IRQ_DONER] = { |
222 | .reg_offset = 3, | 222 | .reg_offset = 2, |
223 | .mask = S5M8763_IRQ_DONER_MASK, | 223 | .mask = S5M8763_IRQ_DONER_MASK, |
224 | }, | 224 | }, |
225 | [S5M8763_IRQ_CHGFAULT] = { | 225 | [S5M8763_IRQ_CHGFAULT] = { |
226 | .reg_offset = 3, | 226 | .reg_offset = 2, |
227 | .mask = S5M8763_IRQ_CHGFAULT_MASK, | 227 | .mask = S5M8763_IRQ_CHGFAULT_MASK, |
228 | }, | 228 | }, |
229 | [S5M8763_IRQ_LOBAT1] = { | 229 | [S5M8763_IRQ_LOBAT1] = { |
230 | .reg_offset = 4, | 230 | .reg_offset = 3, |
231 | .mask = S5M8763_IRQ_LOBAT1_MASK, | 231 | .mask = S5M8763_IRQ_LOBAT1_MASK, |
232 | }, | 232 | }, |
233 | [S5M8763_IRQ_LOBAT2] = { | 233 | [S5M8763_IRQ_LOBAT2] = { |
234 | .reg_offset = 4, | 234 | .reg_offset = 3, |
235 | .mask = S5M8763_IRQ_LOBAT2_MASK, | 235 | .mask = S5M8763_IRQ_LOBAT2_MASK, |
236 | }, | 236 | }, |
237 | }; | 237 | }; |
diff --git a/drivers/mfd/sta2x11-mfd.c b/drivers/mfd/sta2x11-mfd.c index d6284cacd27..1225dcbcfcf 100644 --- a/drivers/mfd/sta2x11-mfd.c +++ b/drivers/mfd/sta2x11-mfd.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2009-2011 Wind River Systems, Inc. | 2 | * Copyright (c) 2009-2011 Wind River Systems, Inc. |
3 | * Copyright (c) 2011 ST Microelectronics (Alessandro Rubini) | 3 | * Copyright (c) 2011 ST Microelectronics (Alessandro Rubini, Davide Ciminaghi) |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License version 2 as | 6 | * it under the terms of the GNU General Public License version 2 as |
@@ -27,21 +27,28 @@ | |||
27 | #include <linux/io.h> | 27 | #include <linux/io.h> |
28 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
29 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
30 | #include <linux/debugfs.h> | ||
31 | #include <linux/seq_file.h> | 30 | #include <linux/seq_file.h> |
32 | #include <linux/platform_device.h> | 31 | #include <linux/platform_device.h> |
33 | #include <linux/mfd/core.h> | 32 | #include <linux/mfd/core.h> |
34 | #include <linux/mfd/sta2x11-mfd.h> | 33 | #include <linux/mfd/sta2x11-mfd.h> |
34 | #include <linux/regmap.h> | ||
35 | 35 | ||
36 | #include <asm/sta2x11.h> | 36 | #include <asm/sta2x11.h> |
37 | 37 | ||
38 | static inline int __reg_within_range(unsigned int r, | ||
39 | unsigned int start, | ||
40 | unsigned int end) | ||
41 | { | ||
42 | return ((r >= start) && (r <= end)); | ||
43 | } | ||
44 | |||
38 | /* This describes STA2X11 MFD chip for us, we may have several */ | 45 | /* This describes STA2X11 MFD chip for us, we may have several */ |
39 | struct sta2x11_mfd { | 46 | struct sta2x11_mfd { |
40 | struct sta2x11_instance *instance; | 47 | struct sta2x11_instance *instance; |
41 | spinlock_t lock; | 48 | struct regmap *regmap[sta2x11_n_mfd_plat_devs]; |
49 | spinlock_t lock[sta2x11_n_mfd_plat_devs]; | ||
42 | struct list_head list; | 50 | struct list_head list; |
43 | void __iomem *sctl_regs; | 51 | void __iomem *regs[sta2x11_n_mfd_plat_devs]; |
44 | void __iomem *apbreg_regs; | ||
45 | }; | 52 | }; |
46 | 53 | ||
47 | static LIST_HEAD(sta2x11_mfd_list); | 54 | static LIST_HEAD(sta2x11_mfd_list); |
@@ -71,6 +78,7 @@ static struct sta2x11_mfd *sta2x11_mfd_find(struct pci_dev *pdev) | |||
71 | 78 | ||
72 | static int sta2x11_mfd_add(struct pci_dev *pdev, gfp_t flags) | 79 | static int sta2x11_mfd_add(struct pci_dev *pdev, gfp_t flags) |
73 | { | 80 | { |
81 | int i; | ||
74 | struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev); | 82 | struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev); |
75 | struct sta2x11_instance *instance; | 83 | struct sta2x11_instance *instance; |
76 | 84 | ||
@@ -83,7 +91,8 @@ static int sta2x11_mfd_add(struct pci_dev *pdev, gfp_t flags) | |||
83 | if (!mfd) | 91 | if (!mfd) |
84 | return -ENOMEM; | 92 | return -ENOMEM; |
85 | INIT_LIST_HEAD(&mfd->list); | 93 | INIT_LIST_HEAD(&mfd->list); |
86 | spin_lock_init(&mfd->lock); | 94 | for (i = 0; i < ARRAY_SIZE(mfd->lock); i++) |
95 | spin_lock_init(&mfd->lock[i]); | ||
87 | mfd->instance = instance; | 96 | mfd->instance = instance; |
88 | list_add(&mfd->list, &sta2x11_mfd_list); | 97 | list_add(&mfd->list, &sta2x11_mfd_list); |
89 | return 0; | 98 | return 0; |
@@ -100,161 +109,276 @@ static int mfd_remove(struct pci_dev *pdev) | |||
100 | return 0; | 109 | return 0; |
101 | } | 110 | } |
102 | 111 | ||
103 | /* These two functions are exported and are not expected to fail */ | 112 | /* This function is exported and is not expected to fail */ |
104 | u32 sta2x11_sctl_mask(struct pci_dev *pdev, u32 reg, u32 mask, u32 val) | 113 | u32 __sta2x11_mfd_mask(struct pci_dev *pdev, u32 reg, u32 mask, u32 val, |
114 | enum sta2x11_mfd_plat_dev index) | ||
105 | { | 115 | { |
106 | struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev); | 116 | struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev); |
107 | u32 r; | 117 | u32 r; |
108 | unsigned long flags; | 118 | unsigned long flags; |
119 | void __iomem *regs; | ||
109 | 120 | ||
110 | if (!mfd) { | 121 | if (!mfd) { |
111 | dev_warn(&pdev->dev, ": can't access sctl regs\n"); | 122 | dev_warn(&pdev->dev, ": can't access sctl regs\n"); |
112 | return 0; | 123 | return 0; |
113 | } | 124 | } |
114 | if (!mfd->sctl_regs) { | 125 | |
126 | regs = mfd->regs[index]; | ||
127 | if (!regs) { | ||
115 | dev_warn(&pdev->dev, ": system ctl not initialized\n"); | 128 | dev_warn(&pdev->dev, ": system ctl not initialized\n"); |
116 | return 0; | 129 | return 0; |
117 | } | 130 | } |
118 | spin_lock_irqsave(&mfd->lock, flags); | 131 | spin_lock_irqsave(&mfd->lock[index], flags); |
119 | r = readl(mfd->sctl_regs + reg); | 132 | r = readl(regs + reg); |
120 | r &= ~mask; | 133 | r &= ~mask; |
121 | r |= val; | 134 | r |= val; |
122 | if (mask) | 135 | if (mask) |
123 | writel(r, mfd->sctl_regs + reg); | 136 | writel(r, regs + reg); |
124 | spin_unlock_irqrestore(&mfd->lock, flags); | 137 | spin_unlock_irqrestore(&mfd->lock[index], flags); |
125 | return r; | 138 | return r; |
126 | } | 139 | } |
127 | EXPORT_SYMBOL(sta2x11_sctl_mask); | 140 | EXPORT_SYMBOL(__sta2x11_mfd_mask); |
128 | 141 | ||
129 | u32 sta2x11_apbreg_mask(struct pci_dev *pdev, u32 reg, u32 mask, u32 val) | 142 | int sta2x11_mfd_get_regs_data(struct platform_device *dev, |
143 | enum sta2x11_mfd_plat_dev index, | ||
144 | void __iomem **regs, | ||
145 | spinlock_t **lock) | ||
130 | { | 146 | { |
131 | struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev); | 147 | struct pci_dev *pdev = *(struct pci_dev **)(dev->dev.platform_data); |
132 | u32 r; | 148 | struct sta2x11_mfd *mfd; |
133 | unsigned long flags; | ||
134 | 149 | ||
135 | if (!mfd) { | 150 | if (!pdev) |
136 | dev_warn(&pdev->dev, ": can't access apb regs\n"); | 151 | return -ENODEV; |
137 | return 0; | 152 | mfd = sta2x11_mfd_find(pdev); |
138 | } | 153 | if (!mfd) |
139 | if (!mfd->apbreg_regs) { | 154 | return -ENODEV; |
140 | dev_warn(&pdev->dev, ": apb bridge not initialized\n"); | 155 | if (index >= sta2x11_n_mfd_plat_devs) |
141 | return 0; | 156 | return -ENODEV; |
142 | } | 157 | *regs = mfd->regs[index]; |
143 | spin_lock_irqsave(&mfd->lock, flags); | 158 | *lock = &mfd->lock[index]; |
144 | r = readl(mfd->apbreg_regs + reg); | 159 | pr_debug("%s %d *regs = %p\n", __func__, __LINE__, *regs); |
145 | r &= ~mask; | 160 | return *regs ? 0 : -ENODEV; |
146 | r |= val; | ||
147 | if (mask) | ||
148 | writel(r, mfd->apbreg_regs + reg); | ||
149 | spin_unlock_irqrestore(&mfd->lock, flags); | ||
150 | return r; | ||
151 | } | 161 | } |
152 | EXPORT_SYMBOL(sta2x11_apbreg_mask); | 162 | EXPORT_SYMBOL(sta2x11_mfd_get_regs_data); |
153 | |||
154 | /* Two debugfs files, for our registers (FIXME: one instance only) */ | ||
155 | #define REG(regname) {.name = #regname, .offset = SCTL_ ## regname} | ||
156 | static struct debugfs_reg32 sta2x11_sctl_regs[] = { | ||
157 | REG(SCCTL), REG(ARMCFG), REG(SCPLLCTL), REG(SCPLLFCTRL), | ||
158 | REG(SCRESFRACT), REG(SCRESCTRL1), REG(SCRESXTRL2), REG(SCPEREN0), | ||
159 | REG(SCPEREN1), REG(SCPEREN2), REG(SCGRST), REG(SCPCIPMCR1), | ||
160 | REG(SCPCIPMCR2), REG(SCPCIPMSR1), REG(SCPCIPMSR2), REG(SCPCIPMSR3), | ||
161 | REG(SCINTREN), REG(SCRISR), REG(SCCLKSTAT0), REG(SCCLKSTAT1), | ||
162 | REG(SCCLKSTAT2), REG(SCRSTSTA), | ||
163 | }; | ||
164 | #undef REG | ||
165 | 163 | ||
166 | static struct debugfs_regset32 sctl_regset = { | 164 | /* |
167 | .regs = sta2x11_sctl_regs, | 165 | * Special sta2x11-mfd regmap lock/unlock functions |
168 | .nregs = ARRAY_SIZE(sta2x11_sctl_regs), | 166 | */ |
169 | }; | 167 | |
168 | static void sta2x11_regmap_lock(void *__lock) | ||
169 | { | ||
170 | spinlock_t *lock = __lock; | ||
171 | spin_lock(lock); | ||
172 | } | ||
170 | 173 | ||
171 | #define REG(regname) {.name = #regname, .offset = regname} | 174 | static void sta2x11_regmap_unlock(void *__lock) |
172 | static struct debugfs_reg32 sta2x11_apbreg_regs[] = { | 175 | { |
173 | REG(APBREG_BSR), REG(APBREG_PAER), REG(APBREG_PWAC), REG(APBREG_PRAC), | 176 | spinlock_t *lock = __lock; |
174 | REG(APBREG_PCG), REG(APBREG_PUR), REG(APBREG_EMU_PCG), | 177 | spin_unlock(lock); |
178 | } | ||
179 | |||
180 | /* OTP (one time programmable registers do not require locking */ | ||
181 | static void sta2x11_regmap_nolock(void *__lock) | ||
182 | { | ||
183 | } | ||
184 | |||
185 | static const char *sta2x11_mfd_names[sta2x11_n_mfd_plat_devs] = { | ||
186 | [sta2x11_sctl] = STA2X11_MFD_SCTL_NAME, | ||
187 | [sta2x11_apbreg] = STA2X11_MFD_APBREG_NAME, | ||
188 | [sta2x11_apb_soc_regs] = STA2X11_MFD_APB_SOC_REGS_NAME, | ||
189 | [sta2x11_scr] = STA2X11_MFD_SCR_NAME, | ||
175 | }; | 190 | }; |
176 | #undef REG | ||
177 | 191 | ||
178 | static struct debugfs_regset32 apbreg_regset = { | 192 | static bool sta2x11_sctl_writeable_reg(struct device *dev, unsigned int reg) |
179 | .regs = sta2x11_apbreg_regs, | 193 | { |
180 | .nregs = ARRAY_SIZE(sta2x11_apbreg_regs), | 194 | return !__reg_within_range(reg, SCTL_SCPCIECSBRST, SCTL_SCRSTSTA); |
195 | } | ||
196 | |||
197 | static struct regmap_config sta2x11_sctl_regmap_config = { | ||
198 | .reg_bits = 32, | ||
199 | .reg_stride = 4, | ||
200 | .val_bits = 32, | ||
201 | .lock = sta2x11_regmap_lock, | ||
202 | .unlock = sta2x11_regmap_unlock, | ||
203 | .max_register = SCTL_SCRSTSTA, | ||
204 | .writeable_reg = sta2x11_sctl_writeable_reg, | ||
181 | }; | 205 | }; |
182 | 206 | ||
183 | static struct dentry *sta2x11_sctl_debugfs; | 207 | static bool sta2x11_scr_readable_reg(struct device *dev, unsigned int reg) |
184 | static struct dentry *sta2x11_apbreg_debugfs; | 208 | { |
209 | return (reg == STA2X11_SECR_CR) || | ||
210 | __reg_within_range(reg, STA2X11_SECR_FVR0, STA2X11_SECR_FVR1); | ||
211 | } | ||
185 | 212 | ||
186 | /* Probe for the two platform devices */ | 213 | static bool sta2x11_scr_writeable_reg(struct device *dev, unsigned int reg) |
187 | static int sta2x11_sctl_probe(struct platform_device *dev) | ||
188 | { | 214 | { |
189 | struct pci_dev **pdev; | 215 | return false; |
190 | struct sta2x11_mfd *mfd; | 216 | } |
191 | struct resource *res; | ||
192 | 217 | ||
193 | pdev = dev->dev.platform_data; | 218 | static struct regmap_config sta2x11_scr_regmap_config = { |
194 | mfd = sta2x11_mfd_find(*pdev); | 219 | .reg_bits = 32, |
195 | if (!mfd) | 220 | .reg_stride = 4, |
196 | return -ENODEV; | 221 | .val_bits = 32, |
222 | .lock = sta2x11_regmap_nolock, | ||
223 | .unlock = sta2x11_regmap_nolock, | ||
224 | .max_register = STA2X11_SECR_FVR1, | ||
225 | .readable_reg = sta2x11_scr_readable_reg, | ||
226 | .writeable_reg = sta2x11_scr_writeable_reg, | ||
227 | }; | ||
197 | 228 | ||
198 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); | 229 | static bool sta2x11_apbreg_readable_reg(struct device *dev, unsigned int reg) |
199 | if (!res) | 230 | { |
200 | return -ENOMEM; | 231 | /* Two blocks (CAN and MLB, SARAC) 0x100 bytes apart */ |
232 | if (reg >= APBREG_BSR_SARAC) | ||
233 | reg -= APBREG_BSR_SARAC; | ||
234 | switch (reg) { | ||
235 | case APBREG_BSR: | ||
236 | case APBREG_PAER: | ||
237 | case APBREG_PWAC: | ||
238 | case APBREG_PRAC: | ||
239 | case APBREG_PCG: | ||
240 | case APBREG_PUR: | ||
241 | case APBREG_EMU_PCG: | ||
242 | return true; | ||
243 | default: | ||
244 | return false; | ||
245 | } | ||
246 | } | ||
201 | 247 | ||
202 | if (!request_mem_region(res->start, resource_size(res), | 248 | static bool sta2x11_apbreg_writeable_reg(struct device *dev, unsigned int reg) |
203 | "sta2x11-sctl")) | 249 | { |
204 | return -EBUSY; | 250 | if (reg >= APBREG_BSR_SARAC) |
251 | reg -= APBREG_BSR_SARAC; | ||
252 | if (!sta2x11_apbreg_readable_reg(dev, reg)) | ||
253 | return false; | ||
254 | return reg != APBREG_PAER; | ||
255 | } | ||
205 | 256 | ||
206 | mfd->sctl_regs = ioremap(res->start, resource_size(res)); | 257 | static struct regmap_config sta2x11_apbreg_regmap_config = { |
207 | if (!mfd->sctl_regs) { | 258 | .reg_bits = 32, |
208 | release_mem_region(res->start, resource_size(res)); | 259 | .reg_stride = 4, |
209 | return -ENOMEM; | 260 | .val_bits = 32, |
261 | .lock = sta2x11_regmap_lock, | ||
262 | .unlock = sta2x11_regmap_unlock, | ||
263 | .max_register = APBREG_EMU_PCG_SARAC, | ||
264 | .readable_reg = sta2x11_apbreg_readable_reg, | ||
265 | .writeable_reg = sta2x11_apbreg_writeable_reg, | ||
266 | }; | ||
267 | |||
268 | static bool sta2x11_apb_soc_regs_readable_reg(struct device *dev, | ||
269 | unsigned int reg) | ||
270 | { | ||
271 | return reg <= PCIE_SoC_INT_ROUTER_STATUS3_REG || | ||
272 | __reg_within_range(reg, DMA_IP_CTRL_REG, SPARE3_RESERVED) || | ||
273 | __reg_within_range(reg, MASTER_LOCK_REG, | ||
274 | SYSTEM_CONFIG_STATUS_REG) || | ||
275 | reg == MSP_CLK_CTRL_REG || | ||
276 | __reg_within_range(reg, COMPENSATION_REG1, TEST_CTL_REG); | ||
277 | } | ||
278 | |||
279 | static bool sta2x11_apb_soc_regs_writeable_reg(struct device *dev, | ||
280 | unsigned int reg) | ||
281 | { | ||
282 | if (!sta2x11_apb_soc_regs_readable_reg(dev, reg)) | ||
283 | return false; | ||
284 | switch (reg) { | ||
285 | case PCIE_COMMON_CLOCK_CONFIG_0_4_0: | ||
286 | case SYSTEM_CONFIG_STATUS_REG: | ||
287 | case COMPENSATION_REG1: | ||
288 | case PCIE_SoC_INT_ROUTER_STATUS0_REG...PCIE_SoC_INT_ROUTER_STATUS3_REG: | ||
289 | case PCIE_PM_STATUS_0_PORT_0_4...PCIE_PM_STATUS_7_0_EP4: | ||
290 | return false; | ||
291 | default: | ||
292 | return true; | ||
210 | } | 293 | } |
211 | sctl_regset.base = mfd->sctl_regs; | ||
212 | sta2x11_sctl_debugfs = debugfs_create_regset32("sta2x11-sctl", | ||
213 | S_IFREG | S_IRUGO, | ||
214 | NULL, &sctl_regset); | ||
215 | return 0; | ||
216 | } | 294 | } |
217 | 295 | ||
218 | static int sta2x11_apbreg_probe(struct platform_device *dev) | 296 | static struct regmap_config sta2x11_apb_soc_regs_regmap_config = { |
297 | .reg_bits = 32, | ||
298 | .reg_stride = 4, | ||
299 | .val_bits = 32, | ||
300 | .lock = sta2x11_regmap_lock, | ||
301 | .unlock = sta2x11_regmap_unlock, | ||
302 | .max_register = TEST_CTL_REG, | ||
303 | .readable_reg = sta2x11_apb_soc_regs_readable_reg, | ||
304 | .writeable_reg = sta2x11_apb_soc_regs_writeable_reg, | ||
305 | }; | ||
306 | |||
307 | static struct regmap_config * | ||
308 | sta2x11_mfd_regmap_configs[sta2x11_n_mfd_plat_devs] = { | ||
309 | [sta2x11_sctl] = &sta2x11_sctl_regmap_config, | ||
310 | [sta2x11_apbreg] = &sta2x11_apbreg_regmap_config, | ||
311 | [sta2x11_apb_soc_regs] = &sta2x11_apb_soc_regs_regmap_config, | ||
312 | [sta2x11_scr] = &sta2x11_scr_regmap_config, | ||
313 | }; | ||
314 | |||
315 | /* Probe for the four platform devices */ | ||
316 | |||
317 | static int sta2x11_mfd_platform_probe(struct platform_device *dev, | ||
318 | enum sta2x11_mfd_plat_dev index) | ||
219 | { | 319 | { |
220 | struct pci_dev **pdev; | 320 | struct pci_dev **pdev; |
221 | struct sta2x11_mfd *mfd; | 321 | struct sta2x11_mfd *mfd; |
222 | struct resource *res; | 322 | struct resource *res; |
323 | const char *name = sta2x11_mfd_names[index]; | ||
324 | struct regmap_config *regmap_config = sta2x11_mfd_regmap_configs[index]; | ||
223 | 325 | ||
224 | pdev = dev->dev.platform_data; | 326 | pdev = dev->dev.platform_data; |
225 | dev_dbg(&dev->dev, "%s: pdata is %p\n", __func__, pdev); | ||
226 | dev_dbg(&dev->dev, "%s: *pdata is %p\n", __func__, *pdev); | ||
227 | |||
228 | mfd = sta2x11_mfd_find(*pdev); | 327 | mfd = sta2x11_mfd_find(*pdev); |
229 | if (!mfd) | 328 | if (!mfd) |
230 | return -ENODEV; | 329 | return -ENODEV; |
330 | if (!regmap_config) | ||
331 | return -ENODEV; | ||
231 | 332 | ||
232 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); | 333 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); |
233 | if (!res) | 334 | if (!res) |
234 | return -ENOMEM; | 335 | return -ENOMEM; |
235 | 336 | ||
236 | if (!request_mem_region(res->start, resource_size(res), | 337 | if (!request_mem_region(res->start, resource_size(res), name)) |
237 | "sta2x11-apbreg")) | ||
238 | return -EBUSY; | 338 | return -EBUSY; |
239 | 339 | ||
240 | mfd->apbreg_regs = ioremap(res->start, resource_size(res)); | 340 | mfd->regs[index] = ioremap(res->start, resource_size(res)); |
241 | if (!mfd->apbreg_regs) { | 341 | if (!mfd->regs[index]) { |
242 | release_mem_region(res->start, resource_size(res)); | 342 | release_mem_region(res->start, resource_size(res)); |
243 | return -ENOMEM; | 343 | return -ENOMEM; |
244 | } | 344 | } |
245 | dev_dbg(&dev->dev, "%s: regbase %p\n", __func__, mfd->apbreg_regs); | 345 | regmap_config->lock_arg = &mfd->lock; |
346 | /* | ||
347 | No caching, registers could be reached both via regmap and via | ||
348 | void __iomem * | ||
349 | */ | ||
350 | regmap_config->cache_type = REGCACHE_NONE; | ||
351 | mfd->regmap[index] = devm_regmap_init_mmio(&dev->dev, mfd->regs[index], | ||
352 | regmap_config); | ||
353 | WARN_ON(!mfd->regmap[index]); | ||
246 | 354 | ||
247 | apbreg_regset.base = mfd->apbreg_regs; | ||
248 | sta2x11_apbreg_debugfs = debugfs_create_regset32("sta2x11-apbreg", | ||
249 | S_IFREG | S_IRUGO, | ||
250 | NULL, &apbreg_regset); | ||
251 | return 0; | 355 | return 0; |
252 | } | 356 | } |
253 | 357 | ||
254 | /* The two platform drivers */ | 358 | static int sta2x11_sctl_probe(struct platform_device *dev) |
359 | { | ||
360 | return sta2x11_mfd_platform_probe(dev, sta2x11_sctl); | ||
361 | } | ||
362 | |||
363 | static int sta2x11_apbreg_probe(struct platform_device *dev) | ||
364 | { | ||
365 | return sta2x11_mfd_platform_probe(dev, sta2x11_apbreg); | ||
366 | } | ||
367 | |||
368 | static int sta2x11_apb_soc_regs_probe(struct platform_device *dev) | ||
369 | { | ||
370 | return sta2x11_mfd_platform_probe(dev, sta2x11_apb_soc_regs); | ||
371 | } | ||
372 | |||
373 | static int sta2x11_scr_probe(struct platform_device *dev) | ||
374 | { | ||
375 | return sta2x11_mfd_platform_probe(dev, sta2x11_scr); | ||
376 | } | ||
377 | |||
378 | /* The three platform drivers */ | ||
255 | static struct platform_driver sta2x11_sctl_platform_driver = { | 379 | static struct platform_driver sta2x11_sctl_platform_driver = { |
256 | .driver = { | 380 | .driver = { |
257 | .name = "sta2x11-sctl", | 381 | .name = STA2X11_MFD_SCTL_NAME, |
258 | .owner = THIS_MODULE, | 382 | .owner = THIS_MODULE, |
259 | }, | 383 | }, |
260 | .probe = sta2x11_sctl_probe, | 384 | .probe = sta2x11_sctl_probe, |
@@ -268,7 +392,7 @@ static int __init sta2x11_sctl_init(void) | |||
268 | 392 | ||
269 | static struct platform_driver sta2x11_platform_driver = { | 393 | static struct platform_driver sta2x11_platform_driver = { |
270 | .driver = { | 394 | .driver = { |
271 | .name = "sta2x11-apbreg", | 395 | .name = STA2X11_MFD_APBREG_NAME, |
272 | .owner = THIS_MODULE, | 396 | .owner = THIS_MODULE, |
273 | }, | 397 | }, |
274 | .probe = sta2x11_apbreg_probe, | 398 | .probe = sta2x11_apbreg_probe, |
@@ -280,13 +404,44 @@ static int __init sta2x11_apbreg_init(void) | |||
280 | return platform_driver_register(&sta2x11_platform_driver); | 404 | return platform_driver_register(&sta2x11_platform_driver); |
281 | } | 405 | } |
282 | 406 | ||
407 | static struct platform_driver sta2x11_apb_soc_regs_platform_driver = { | ||
408 | .driver = { | ||
409 | .name = STA2X11_MFD_APB_SOC_REGS_NAME, | ||
410 | .owner = THIS_MODULE, | ||
411 | }, | ||
412 | .probe = sta2x11_apb_soc_regs_probe, | ||
413 | }; | ||
414 | |||
415 | static int __init sta2x11_apb_soc_regs_init(void) | ||
416 | { | ||
417 | pr_info("%s\n", __func__); | ||
418 | return platform_driver_register(&sta2x11_apb_soc_regs_platform_driver); | ||
419 | } | ||
420 | |||
421 | static struct platform_driver sta2x11_scr_platform_driver = { | ||
422 | .driver = { | ||
423 | .name = STA2X11_MFD_SCR_NAME, | ||
424 | .owner = THIS_MODULE, | ||
425 | }, | ||
426 | .probe = sta2x11_scr_probe, | ||
427 | }; | ||
428 | |||
429 | static int __init sta2x11_scr_init(void) | ||
430 | { | ||
431 | pr_info("%s\n", __func__); | ||
432 | return platform_driver_register(&sta2x11_scr_platform_driver); | ||
433 | } | ||
434 | |||
435 | |||
283 | /* | 436 | /* |
284 | * What follows is the PCI device that hosts the above two pdevs. | 437 | * What follows are the PCI devices that host the above pdevs. |
285 | * Each logic block is 4kB and they are all consecutive: we use this info. | 438 | * Each logic block is 4kB and they are all consecutive: we use this info. |
286 | */ | 439 | */ |
287 | 440 | ||
288 | /* Bar 0 */ | 441 | /* Mfd 0 device */ |
289 | enum bar0_cells { | 442 | |
443 | /* Mfd 0, Bar 0 */ | ||
444 | enum mfd0_bar0_cells { | ||
290 | STA2X11_GPIO_0 = 0, | 445 | STA2X11_GPIO_0 = 0, |
291 | STA2X11_GPIO_1, | 446 | STA2X11_GPIO_1, |
292 | STA2X11_GPIO_2, | 447 | STA2X11_GPIO_2, |
@@ -295,8 +450,8 @@ enum bar0_cells { | |||
295 | STA2X11_SCR, | 450 | STA2X11_SCR, |
296 | STA2X11_TIME, | 451 | STA2X11_TIME, |
297 | }; | 452 | }; |
298 | /* Bar 1 */ | 453 | /* Mfd 0 , Bar 1 */ |
299 | enum bar1_cells { | 454 | enum mfd0_bar1_cells { |
300 | STA2X11_APBREG = 0, | 455 | STA2X11_APBREG = 0, |
301 | }; | 456 | }; |
302 | #define CELL_4K(_name, _cell) { \ | 457 | #define CELL_4K(_name, _cell) { \ |
@@ -307,40 +462,71 @@ enum bar1_cells { | |||
307 | 462 | ||
308 | static const struct resource gpio_resources[] = { | 463 | static const struct resource gpio_resources[] = { |
309 | { | 464 | { |
310 | .name = "sta2x11_gpio", /* 4 consecutive cells, 1 driver */ | 465 | /* 4 consecutive cells, 1 driver */ |
466 | .name = STA2X11_MFD_GPIO_NAME, | ||
311 | .start = 0, | 467 | .start = 0, |
312 | .end = (4 * 4096) - 1, | 468 | .end = (4 * 4096) - 1, |
313 | .flags = IORESOURCE_MEM, | 469 | .flags = IORESOURCE_MEM, |
314 | } | 470 | } |
315 | }; | 471 | }; |
316 | static const struct resource sctl_resources[] = { | 472 | static const struct resource sctl_resources[] = { |
317 | CELL_4K("sta2x11-sctl", STA2X11_SCTL), | 473 | CELL_4K(STA2X11_MFD_SCTL_NAME, STA2X11_SCTL), |
318 | }; | 474 | }; |
319 | static const struct resource scr_resources[] = { | 475 | static const struct resource scr_resources[] = { |
320 | CELL_4K("sta2x11-scr", STA2X11_SCR), | 476 | CELL_4K(STA2X11_MFD_SCR_NAME, STA2X11_SCR), |
321 | }; | 477 | }; |
322 | static const struct resource time_resources[] = { | 478 | static const struct resource time_resources[] = { |
323 | CELL_4K("sta2x11-time", STA2X11_TIME), | 479 | CELL_4K(STA2X11_MFD_TIME_NAME, STA2X11_TIME), |
324 | }; | 480 | }; |
325 | 481 | ||
326 | static const struct resource apbreg_resources[] = { | 482 | static const struct resource apbreg_resources[] = { |
327 | CELL_4K("sta2x11-apbreg", STA2X11_APBREG), | 483 | CELL_4K(STA2X11_MFD_APBREG_NAME, STA2X11_APBREG), |
328 | }; | 484 | }; |
329 | 485 | ||
330 | #define DEV(_name, _r) \ | 486 | #define DEV(_name, _r) \ |
331 | { .name = _name, .num_resources = ARRAY_SIZE(_r), .resources = _r, } | 487 | { .name = _name, .num_resources = ARRAY_SIZE(_r), .resources = _r, } |
332 | 488 | ||
333 | static struct mfd_cell sta2x11_mfd_bar0[] = { | 489 | static struct mfd_cell sta2x11_mfd0_bar0[] = { |
334 | DEV("sta2x11-gpio", gpio_resources), /* offset 0: we add pdata later */ | 490 | /* offset 0: we add pdata later */ |
335 | DEV("sta2x11-sctl", sctl_resources), | 491 | DEV(STA2X11_MFD_GPIO_NAME, gpio_resources), |
336 | DEV("sta2x11-scr", scr_resources), | 492 | DEV(STA2X11_MFD_SCTL_NAME, sctl_resources), |
337 | DEV("sta2x11-time", time_resources), | 493 | DEV(STA2X11_MFD_SCR_NAME, scr_resources), |
494 | DEV(STA2X11_MFD_TIME_NAME, time_resources), | ||
338 | }; | 495 | }; |
339 | 496 | ||
340 | static struct mfd_cell sta2x11_mfd_bar1[] = { | 497 | static struct mfd_cell sta2x11_mfd0_bar1[] = { |
341 | DEV("sta2x11-apbreg", apbreg_resources), | 498 | DEV(STA2X11_MFD_APBREG_NAME, apbreg_resources), |
342 | }; | 499 | }; |
343 | 500 | ||
501 | /* Mfd 1 devices */ | ||
502 | |||
503 | /* Mfd 1, Bar 0 */ | ||
504 | enum mfd1_bar0_cells { | ||
505 | STA2X11_VIC = 0, | ||
506 | }; | ||
507 | |||
508 | /* Mfd 1, Bar 1 */ | ||
509 | enum mfd1_bar1_cells { | ||
510 | STA2X11_APB_SOC_REGS = 0, | ||
511 | }; | ||
512 | |||
513 | static const __devinitconst struct resource vic_resources[] = { | ||
514 | CELL_4K(STA2X11_MFD_VIC_NAME, STA2X11_VIC), | ||
515 | }; | ||
516 | |||
517 | static const __devinitconst struct resource apb_soc_regs_resources[] = { | ||
518 | CELL_4K(STA2X11_MFD_APB_SOC_REGS_NAME, STA2X11_APB_SOC_REGS), | ||
519 | }; | ||
520 | |||
521 | static __devinitdata struct mfd_cell sta2x11_mfd1_bar0[] = { | ||
522 | DEV(STA2X11_MFD_VIC_NAME, vic_resources), | ||
523 | }; | ||
524 | |||
525 | static __devinitdata struct mfd_cell sta2x11_mfd1_bar1[] = { | ||
526 | DEV(STA2X11_MFD_APB_SOC_REGS_NAME, apb_soc_regs_resources), | ||
527 | }; | ||
528 | |||
529 | |||
344 | static int sta2x11_mfd_suspend(struct pci_dev *pdev, pm_message_t state) | 530 | static int sta2x11_mfd_suspend(struct pci_dev *pdev, pm_message_t state) |
345 | { | 531 | { |
346 | pci_save_state(pdev); | 532 | pci_save_state(pdev); |
@@ -363,11 +549,63 @@ static int sta2x11_mfd_resume(struct pci_dev *pdev) | |||
363 | return 0; | 549 | return 0; |
364 | } | 550 | } |
365 | 551 | ||
552 | struct sta2x11_mfd_bar_setup_data { | ||
553 | struct mfd_cell *cells; | ||
554 | int ncells; | ||
555 | }; | ||
556 | |||
557 | struct sta2x11_mfd_setup_data { | ||
558 | struct sta2x11_mfd_bar_setup_data bars[2]; | ||
559 | }; | ||
560 | |||
561 | #define STA2X11_MFD0 0 | ||
562 | #define STA2X11_MFD1 1 | ||
563 | |||
564 | static struct sta2x11_mfd_setup_data mfd_setup_data[] = { | ||
565 | /* Mfd 0: gpio, sctl, scr, timers / apbregs */ | ||
566 | [STA2X11_MFD0] = { | ||
567 | .bars = { | ||
568 | [0] = { | ||
569 | .cells = sta2x11_mfd0_bar0, | ||
570 | .ncells = ARRAY_SIZE(sta2x11_mfd0_bar0), | ||
571 | }, | ||
572 | [1] = { | ||
573 | .cells = sta2x11_mfd0_bar1, | ||
574 | .ncells = ARRAY_SIZE(sta2x11_mfd0_bar1), | ||
575 | }, | ||
576 | }, | ||
577 | }, | ||
578 | /* Mfd 1: vic / apb-soc-regs */ | ||
579 | [STA2X11_MFD1] = { | ||
580 | .bars = { | ||
581 | [0] = { | ||
582 | .cells = sta2x11_mfd1_bar0, | ||
583 | .ncells = ARRAY_SIZE(sta2x11_mfd1_bar0), | ||
584 | }, | ||
585 | [1] = { | ||
586 | .cells = sta2x11_mfd1_bar1, | ||
587 | .ncells = ARRAY_SIZE(sta2x11_mfd1_bar1), | ||
588 | }, | ||
589 | }, | ||
590 | }, | ||
591 | }; | ||
592 | |||
593 | static void sta2x11_mfd_setup(struct pci_dev *pdev, | ||
594 | struct sta2x11_mfd_setup_data *sd) | ||
595 | { | ||
596 | int i, j; | ||
597 | for (i = 0; i < ARRAY_SIZE(sd->bars); i++) | ||
598 | for (j = 0; j < sd->bars[i].ncells; j++) { | ||
599 | sd->bars[i].cells[j].pdata_size = sizeof(pdev); | ||
600 | sd->bars[i].cells[j].platform_data = &pdev; | ||
601 | } | ||
602 | } | ||
603 | |||
366 | static int sta2x11_mfd_probe(struct pci_dev *pdev, | 604 | static int sta2x11_mfd_probe(struct pci_dev *pdev, |
367 | const struct pci_device_id *pci_id) | 605 | const struct pci_device_id *pci_id) |
368 | { | 606 | { |
369 | int err, i; | 607 | int err, i; |
370 | struct sta2x11_gpio_pdata *gpio_data; | 608 | struct sta2x11_mfd_setup_data *setup_data; |
371 | 609 | ||
372 | dev_info(&pdev->dev, "%s\n", __func__); | 610 | dev_info(&pdev->dev, "%s\n", __func__); |
373 | 611 | ||
@@ -381,46 +619,29 @@ static int sta2x11_mfd_probe(struct pci_dev *pdev, | |||
381 | if (err) | 619 | if (err) |
382 | dev_info(&pdev->dev, "Enable msi failed\n"); | 620 | dev_info(&pdev->dev, "Enable msi failed\n"); |
383 | 621 | ||
384 | /* Read gpio config data as pci device's platform data */ | 622 | setup_data = pci_id->device == PCI_DEVICE_ID_STMICRO_GPIO ? |
385 | gpio_data = dev_get_platdata(&pdev->dev); | 623 | &mfd_setup_data[STA2X11_MFD0] : |
386 | if (!gpio_data) | 624 | &mfd_setup_data[STA2X11_MFD1]; |
387 | dev_warn(&pdev->dev, "no gpio configuration\n"); | ||
388 | |||
389 | dev_dbg(&pdev->dev, "%s, gpio_data = %p (%p)\n", __func__, | ||
390 | gpio_data, &gpio_data); | ||
391 | dev_dbg(&pdev->dev, "%s, pdev = %p (%p)\n", __func__, | ||
392 | pdev, &pdev); | ||
393 | 625 | ||
394 | /* platform data is the pci device for all of them */ | 626 | /* platform data is the pci device for all of them */ |
395 | for (i = 0; i < ARRAY_SIZE(sta2x11_mfd_bar0); i++) { | 627 | sta2x11_mfd_setup(pdev, setup_data); |
396 | sta2x11_mfd_bar0[i].pdata_size = sizeof(pdev); | ||
397 | sta2x11_mfd_bar0[i].platform_data = &pdev; | ||
398 | } | ||
399 | sta2x11_mfd_bar1[0].pdata_size = sizeof(pdev); | ||
400 | sta2x11_mfd_bar1[0].platform_data = &pdev; | ||
401 | 628 | ||
402 | /* Record this pdev before mfd_add_devices: their probe looks for it */ | 629 | /* Record this pdev before mfd_add_devices: their probe looks for it */ |
403 | sta2x11_mfd_add(pdev, GFP_ATOMIC); | 630 | if (!sta2x11_mfd_find(pdev)) |
404 | 631 | sta2x11_mfd_add(pdev, GFP_ATOMIC); | |
405 | 632 | ||
406 | err = mfd_add_devices(&pdev->dev, -1, | 633 | /* Just 2 bars for all mfd's at present */ |
407 | sta2x11_mfd_bar0, | 634 | for (i = 0; i < 2; i++) { |
408 | ARRAY_SIZE(sta2x11_mfd_bar0), | 635 | err = mfd_add_devices(&pdev->dev, -1, |
409 | &pdev->resource[0], | 636 | setup_data->bars[i].cells, |
410 | 0, NULL); | 637 | setup_data->bars[i].ncells, |
411 | if (err) { | 638 | &pdev->resource[i], |
412 | dev_err(&pdev->dev, "mfd_add_devices[0] failed: %d\n", err); | 639 | 0, NULL); |
413 | goto err_disable; | 640 | if (err) { |
414 | } | 641 | dev_err(&pdev->dev, |
415 | 642 | "mfd_add_devices[%d] failed: %d\n", i, err); | |
416 | err = mfd_add_devices(&pdev->dev, -1, | 643 | goto err_disable; |
417 | sta2x11_mfd_bar1, | 644 | } |
418 | ARRAY_SIZE(sta2x11_mfd_bar1), | ||
419 | &pdev->resource[1], | ||
420 | 0, NULL); | ||
421 | if (err) { | ||
422 | dev_err(&pdev->dev, "mfd_add_devices[1] failed: %d\n", err); | ||
423 | goto err_disable; | ||
424 | } | 645 | } |
425 | 646 | ||
426 | return 0; | 647 | return 0; |
@@ -434,6 +655,7 @@ err_disable: | |||
434 | 655 | ||
435 | static DEFINE_PCI_DEVICE_TABLE(sta2x11_mfd_tbl) = { | 656 | static DEFINE_PCI_DEVICE_TABLE(sta2x11_mfd_tbl) = { |
436 | {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_GPIO)}, | 657 | {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_GPIO)}, |
658 | {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_VIC)}, | ||
437 | {0,}, | 659 | {0,}, |
438 | }; | 660 | }; |
439 | 661 | ||
@@ -459,6 +681,8 @@ static int __init sta2x11_mfd_init(void) | |||
459 | */ | 681 | */ |
460 | subsys_initcall(sta2x11_apbreg_init); | 682 | subsys_initcall(sta2x11_apbreg_init); |
461 | subsys_initcall(sta2x11_sctl_init); | 683 | subsys_initcall(sta2x11_sctl_init); |
684 | subsys_initcall(sta2x11_apb_soc_regs_init); | ||
685 | subsys_initcall(sta2x11_scr_init); | ||
462 | rootfs_initcall(sta2x11_mfd_init); | 686 | rootfs_initcall(sta2x11_mfd_init); |
463 | 687 | ||
464 | MODULE_LICENSE("GPL v2"); | 688 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c index 36df1877802..fd5fcb63068 100644 --- a/drivers/mfd/stmpe-i2c.c +++ b/drivers/mfd/stmpe-i2c.c | |||
@@ -82,11 +82,13 @@ static const struct i2c_device_id stmpe_i2c_id[] = { | |||
82 | MODULE_DEVICE_TABLE(i2c, stmpe_id); | 82 | MODULE_DEVICE_TABLE(i2c, stmpe_id); |
83 | 83 | ||
84 | static struct i2c_driver stmpe_i2c_driver = { | 84 | static struct i2c_driver stmpe_i2c_driver = { |
85 | .driver.name = "stmpe-i2c", | 85 | .driver = { |
86 | .driver.owner = THIS_MODULE, | 86 | .name = "stmpe-i2c", |
87 | .owner = THIS_MODULE, | ||
87 | #ifdef CONFIG_PM | 88 | #ifdef CONFIG_PM |
88 | .driver.pm = &stmpe_dev_pm_ops, | 89 | .pm = &stmpe_dev_pm_ops, |
89 | #endif | 90 | #endif |
91 | }, | ||
90 | .probe = stmpe_i2c_probe, | 92 | .probe = stmpe_i2c_probe, |
91 | .remove = stmpe_i2c_remove, | 93 | .remove = stmpe_i2c_remove, |
92 | .id_table = stmpe_i2c_id, | 94 | .id_table = stmpe_i2c_id, |
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 79e88d1fd99..19636199d7a 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c | |||
@@ -7,11 +7,15 @@ | |||
7 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson | 7 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/err.h> | ||
10 | #include <linux/gpio.h> | 11 | #include <linux/gpio.h> |
11 | #include <linux/export.h> | 12 | #include <linux/export.h> |
12 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
13 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
14 | #include <linux/irq.h> | 15 | #include <linux/irq.h> |
16 | #include <linux/irqdomain.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_gpio.h> | ||
15 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
16 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
17 | #include <linux/mfd/core.h> | 21 | #include <linux/mfd/core.h> |
@@ -312,14 +316,10 @@ static struct mfd_cell stmpe_gpio_cell_noirq = { | |||
312 | static struct resource stmpe_keypad_resources[] = { | 316 | static struct resource stmpe_keypad_resources[] = { |
313 | { | 317 | { |
314 | .name = "KEYPAD", | 318 | .name = "KEYPAD", |
315 | .start = 0, | ||
316 | .end = 0, | ||
317 | .flags = IORESOURCE_IRQ, | 319 | .flags = IORESOURCE_IRQ, |
318 | }, | 320 | }, |
319 | { | 321 | { |
320 | .name = "KEYPAD_OVER", | 322 | .name = "KEYPAD_OVER", |
321 | .start = 1, | ||
322 | .end = 1, | ||
323 | .flags = IORESOURCE_IRQ, | 323 | .flags = IORESOURCE_IRQ, |
324 | }, | 324 | }, |
325 | }; | 325 | }; |
@@ -399,14 +399,10 @@ static struct stmpe_variant_info stmpe801_noirq = { | |||
399 | static struct resource stmpe_ts_resources[] = { | 399 | static struct resource stmpe_ts_resources[] = { |
400 | { | 400 | { |
401 | .name = "TOUCH_DET", | 401 | .name = "TOUCH_DET", |
402 | .start = 0, | ||
403 | .end = 0, | ||
404 | .flags = IORESOURCE_IRQ, | 402 | .flags = IORESOURCE_IRQ, |
405 | }, | 403 | }, |
406 | { | 404 | { |
407 | .name = "FIFO_TH", | 405 | .name = "FIFO_TH", |
408 | .start = 1, | ||
409 | .end = 1, | ||
410 | .flags = IORESOURCE_IRQ, | 406 | .flags = IORESOURCE_IRQ, |
411 | }, | 407 | }, |
412 | }; | 408 | }; |
@@ -528,12 +524,12 @@ static const u8 stmpe1601_regs[] = { | |||
528 | static struct stmpe_variant_block stmpe1601_blocks[] = { | 524 | static struct stmpe_variant_block stmpe1601_blocks[] = { |
529 | { | 525 | { |
530 | .cell = &stmpe_gpio_cell, | 526 | .cell = &stmpe_gpio_cell, |
531 | .irq = STMPE24XX_IRQ_GPIOC, | 527 | .irq = STMPE1601_IRQ_GPIOC, |
532 | .block = STMPE_BLOCK_GPIO, | 528 | .block = STMPE_BLOCK_GPIO, |
533 | }, | 529 | }, |
534 | { | 530 | { |
535 | .cell = &stmpe_keypad_cell, | 531 | .cell = &stmpe_keypad_cell, |
536 | .irq = STMPE24XX_IRQ_KEYPAD, | 532 | .irq = STMPE1601_IRQ_KEYPAD, |
537 | .block = STMPE_BLOCK_KEYPAD, | 533 | .block = STMPE_BLOCK_KEYPAD, |
538 | }, | 534 | }, |
539 | }; | 535 | }; |
@@ -767,7 +763,9 @@ static irqreturn_t stmpe_irq(int irq, void *data) | |||
767 | int i; | 763 | int i; |
768 | 764 | ||
769 | if (variant->id_val == STMPE801_ID) { | 765 | if (variant->id_val == STMPE801_ID) { |
770 | handle_nested_irq(stmpe->irq_base); | 766 | int base = irq_create_mapping(stmpe->domain, 0); |
767 | |||
768 | handle_nested_irq(base); | ||
771 | return IRQ_HANDLED; | 769 | return IRQ_HANDLED; |
772 | } | 770 | } |
773 | 771 | ||
@@ -788,8 +786,9 @@ static irqreturn_t stmpe_irq(int irq, void *data) | |||
788 | while (status) { | 786 | while (status) { |
789 | int bit = __ffs(status); | 787 | int bit = __ffs(status); |
790 | int line = bank * 8 + bit; | 788 | int line = bank * 8 + bit; |
789 | int nestedirq = irq_create_mapping(stmpe->domain, line); | ||
791 | 790 | ||
792 | handle_nested_irq(stmpe->irq_base + line); | 791 | handle_nested_irq(nestedirq); |
793 | status &= ~(1 << bit); | 792 | status &= ~(1 << bit); |
794 | } | 793 | } |
795 | 794 | ||
@@ -830,7 +829,7 @@ static void stmpe_irq_sync_unlock(struct irq_data *data) | |||
830 | static void stmpe_irq_mask(struct irq_data *data) | 829 | static void stmpe_irq_mask(struct irq_data *data) |
831 | { | 830 | { |
832 | struct stmpe *stmpe = irq_data_get_irq_chip_data(data); | 831 | struct stmpe *stmpe = irq_data_get_irq_chip_data(data); |
833 | int offset = data->irq - stmpe->irq_base; | 832 | int offset = data->hwirq; |
834 | int regoffset = offset / 8; | 833 | int regoffset = offset / 8; |
835 | int mask = 1 << (offset % 8); | 834 | int mask = 1 << (offset % 8); |
836 | 835 | ||
@@ -840,7 +839,7 @@ static void stmpe_irq_mask(struct irq_data *data) | |||
840 | static void stmpe_irq_unmask(struct irq_data *data) | 839 | static void stmpe_irq_unmask(struct irq_data *data) |
841 | { | 840 | { |
842 | struct stmpe *stmpe = irq_data_get_irq_chip_data(data); | 841 | struct stmpe *stmpe = irq_data_get_irq_chip_data(data); |
843 | int offset = data->irq - stmpe->irq_base; | 842 | int offset = data->hwirq; |
844 | int regoffset = offset / 8; | 843 | int regoffset = offset / 8; |
845 | int mask = 1 << (offset % 8); | 844 | int mask = 1 << (offset % 8); |
846 | 845 | ||
@@ -855,43 +854,59 @@ static struct irq_chip stmpe_irq_chip = { | |||
855 | .irq_unmask = stmpe_irq_unmask, | 854 | .irq_unmask = stmpe_irq_unmask, |
856 | }; | 855 | }; |
857 | 856 | ||
858 | static int __devinit stmpe_irq_init(struct stmpe *stmpe) | 857 | static int stmpe_irq_map(struct irq_domain *d, unsigned int virq, |
858 | irq_hw_number_t hwirq) | ||
859 | { | 859 | { |
860 | struct stmpe *stmpe = d->host_data; | ||
860 | struct irq_chip *chip = NULL; | 861 | struct irq_chip *chip = NULL; |
861 | int num_irqs = stmpe->variant->num_irqs; | ||
862 | int base = stmpe->irq_base; | ||
863 | int irq; | ||
864 | 862 | ||
865 | if (stmpe->variant->id_val != STMPE801_ID) | 863 | if (stmpe->variant->id_val != STMPE801_ID) |
866 | chip = &stmpe_irq_chip; | 864 | chip = &stmpe_irq_chip; |
867 | 865 | ||
868 | for (irq = base; irq < base + num_irqs; irq++) { | 866 | irq_set_chip_data(virq, stmpe); |
869 | irq_set_chip_data(irq, stmpe); | 867 | irq_set_chip_and_handler(virq, chip, handle_edge_irq); |
870 | irq_set_chip_and_handler(irq, chip, handle_edge_irq); | 868 | irq_set_nested_thread(virq, 1); |
871 | irq_set_nested_thread(irq, 1); | ||
872 | #ifdef CONFIG_ARM | 869 | #ifdef CONFIG_ARM |
873 | set_irq_flags(irq, IRQF_VALID); | 870 | set_irq_flags(virq, IRQF_VALID); |
874 | #else | 871 | #else |
875 | irq_set_noprobe(irq); | 872 | irq_set_noprobe(virq); |
876 | #endif | 873 | #endif |
877 | } | ||
878 | 874 | ||
879 | return 0; | 875 | return 0; |
880 | } | 876 | } |
881 | 877 | ||
882 | static void stmpe_irq_remove(struct stmpe *stmpe) | 878 | static void stmpe_irq_unmap(struct irq_domain *d, unsigned int virq) |
883 | { | 879 | { |
884 | int num_irqs = stmpe->variant->num_irqs; | ||
885 | int base = stmpe->irq_base; | ||
886 | int irq; | ||
887 | |||
888 | for (irq = base; irq < base + num_irqs; irq++) { | ||
889 | #ifdef CONFIG_ARM | 880 | #ifdef CONFIG_ARM |
890 | set_irq_flags(irq, 0); | 881 | set_irq_flags(virq, 0); |
891 | #endif | 882 | #endif |
892 | irq_set_chip_and_handler(irq, NULL, NULL); | 883 | irq_set_chip_and_handler(virq, NULL, NULL); |
893 | irq_set_chip_data(irq, NULL); | 884 | irq_set_chip_data(virq, NULL); |
885 | } | ||
886 | |||
887 | static struct irq_domain_ops stmpe_irq_ops = { | ||
888 | .map = stmpe_irq_map, | ||
889 | .unmap = stmpe_irq_unmap, | ||
890 | .xlate = irq_domain_xlate_twocell, | ||
891 | }; | ||
892 | |||
893 | static int __devinit stmpe_irq_init(struct stmpe *stmpe, | ||
894 | struct device_node *np) | ||
895 | { | ||
896 | int base = 0; | ||
897 | int num_irqs = stmpe->variant->num_irqs; | ||
898 | |||
899 | if (!np) | ||
900 | base = stmpe->irq_base; | ||
901 | |||
902 | stmpe->domain = irq_domain_add_simple(np, num_irqs, base, | ||
903 | &stmpe_irq_ops, stmpe); | ||
904 | if (!stmpe->domain) { | ||
905 | dev_err(stmpe->dev, "Failed to create irqdomain\n"); | ||
906 | return -ENOSYS; | ||
894 | } | 907 | } |
908 | |||
909 | return 0; | ||
895 | } | 910 | } |
896 | 911 | ||
897 | static int __devinit stmpe_chip_init(struct stmpe *stmpe) | 912 | static int __devinit stmpe_chip_init(struct stmpe *stmpe) |
@@ -942,13 +957,6 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe) | |||
942 | else | 957 | else |
943 | icr |= STMPE_ICR_LSB_HIGH; | 958 | icr |= STMPE_ICR_LSB_HIGH; |
944 | } | 959 | } |
945 | |||
946 | if (stmpe->pdata->irq_invert_polarity) { | ||
947 | if (id == STMPE801_ID) | ||
948 | icr ^= STMPE801_REG_SYS_CTRL_INT_HI; | ||
949 | else | ||
950 | icr ^= STMPE_ICR_LSB_HIGH; | ||
951 | } | ||
952 | } | 960 | } |
953 | 961 | ||
954 | if (stmpe->pdata->autosleep) { | 962 | if (stmpe->pdata->autosleep) { |
@@ -961,10 +969,10 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe) | |||
961 | } | 969 | } |
962 | 970 | ||
963 | static int __devinit stmpe_add_device(struct stmpe *stmpe, | 971 | static int __devinit stmpe_add_device(struct stmpe *stmpe, |
964 | struct mfd_cell *cell, int irq) | 972 | struct mfd_cell *cell) |
965 | { | 973 | { |
966 | return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1, | 974 | return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1, |
967 | NULL, stmpe->irq_base + irq, NULL); | 975 | NULL, stmpe->irq_base, stmpe->domain); |
968 | } | 976 | } |
969 | 977 | ||
970 | static int __devinit stmpe_devices_init(struct stmpe *stmpe) | 978 | static int __devinit stmpe_devices_init(struct stmpe *stmpe) |
@@ -972,7 +980,7 @@ static int __devinit stmpe_devices_init(struct stmpe *stmpe) | |||
972 | struct stmpe_variant_info *variant = stmpe->variant; | 980 | struct stmpe_variant_info *variant = stmpe->variant; |
973 | unsigned int platform_blocks = stmpe->pdata->blocks; | 981 | unsigned int platform_blocks = stmpe->pdata->blocks; |
974 | int ret = -EINVAL; | 982 | int ret = -EINVAL; |
975 | int i; | 983 | int i, j; |
976 | 984 | ||
977 | for (i = 0; i < variant->num_blocks; i++) { | 985 | for (i = 0; i < variant->num_blocks; i++) { |
978 | struct stmpe_variant_block *block = &variant->blocks[i]; | 986 | struct stmpe_variant_block *block = &variant->blocks[i]; |
@@ -980,8 +988,17 @@ static int __devinit stmpe_devices_init(struct stmpe *stmpe) | |||
980 | if (!(platform_blocks & block->block)) | 988 | if (!(platform_blocks & block->block)) |
981 | continue; | 989 | continue; |
982 | 990 | ||
991 | for (j = 0; j < block->cell->num_resources; j++) { | ||
992 | struct resource *res = | ||
993 | (struct resource *) &block->cell->resources[j]; | ||
994 | |||
995 | /* Dynamically fill in a variant's IRQ. */ | ||
996 | if (res->flags & IORESOURCE_IRQ) | ||
997 | res->start = res->end = block->irq + j; | ||
998 | } | ||
999 | |||
983 | platform_blocks &= ~block->block; | 1000 | platform_blocks &= ~block->block; |
984 | ret = stmpe_add_device(stmpe, block->cell, block->irq); | 1001 | ret = stmpe_add_device(stmpe, block->cell); |
985 | if (ret) | 1002 | if (ret) |
986 | return ret; | 1003 | return ret; |
987 | } | 1004 | } |
@@ -994,17 +1011,56 @@ static int __devinit stmpe_devices_init(struct stmpe *stmpe) | |||
994 | return ret; | 1011 | return ret; |
995 | } | 1012 | } |
996 | 1013 | ||
1014 | void __devinit stmpe_of_probe(struct stmpe_platform_data *pdata, | ||
1015 | struct device_node *np) | ||
1016 | { | ||
1017 | struct device_node *child; | ||
1018 | |||
1019 | pdata->id = -1; | ||
1020 | pdata->irq_trigger = IRQF_TRIGGER_NONE; | ||
1021 | |||
1022 | of_property_read_u32(np, "st,autosleep-timeout", | ||
1023 | &pdata->autosleep_timeout); | ||
1024 | |||
1025 | pdata->autosleep = (pdata->autosleep_timeout) ? true : false; | ||
1026 | |||
1027 | for_each_child_of_node(np, child) { | ||
1028 | if (!strcmp(child->name, "stmpe_gpio")) { | ||
1029 | pdata->blocks |= STMPE_BLOCK_GPIO; | ||
1030 | } else if (!strcmp(child->name, "stmpe_keypad")) { | ||
1031 | pdata->blocks |= STMPE_BLOCK_KEYPAD; | ||
1032 | } else if (!strcmp(child->name, "stmpe_touchscreen")) { | ||
1033 | pdata->blocks |= STMPE_BLOCK_TOUCHSCREEN; | ||
1034 | } else if (!strcmp(child->name, "stmpe_adc")) { | ||
1035 | pdata->blocks |= STMPE_BLOCK_ADC; | ||
1036 | } else if (!strcmp(child->name, "stmpe_pwm")) { | ||
1037 | pdata->blocks |= STMPE_BLOCK_PWM; | ||
1038 | } else if (!strcmp(child->name, "stmpe_rotator")) { | ||
1039 | pdata->blocks |= STMPE_BLOCK_ROTATOR; | ||
1040 | } | ||
1041 | } | ||
1042 | } | ||
1043 | |||
997 | /* Called from client specific probe routines */ | 1044 | /* Called from client specific probe routines */ |
998 | int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum) | 1045 | int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum) |
999 | { | 1046 | { |
1000 | struct stmpe_platform_data *pdata = dev_get_platdata(ci->dev); | 1047 | struct stmpe_platform_data *pdata = dev_get_platdata(ci->dev); |
1048 | struct device_node *np = ci->dev->of_node; | ||
1001 | struct stmpe *stmpe; | 1049 | struct stmpe *stmpe; |
1002 | int ret; | 1050 | int ret; |
1003 | 1051 | ||
1004 | if (!pdata) | 1052 | if (!pdata) { |
1005 | return -EINVAL; | 1053 | if (!np) |
1054 | return -EINVAL; | ||
1055 | |||
1056 | pdata = devm_kzalloc(ci->dev, sizeof(*pdata), GFP_KERNEL); | ||
1057 | if (!pdata) | ||
1058 | return -ENOMEM; | ||
1059 | |||
1060 | stmpe_of_probe(pdata, np); | ||
1061 | } | ||
1006 | 1062 | ||
1007 | stmpe = kzalloc(sizeof(struct stmpe), GFP_KERNEL); | 1063 | stmpe = devm_kzalloc(ci->dev, sizeof(struct stmpe), GFP_KERNEL); |
1008 | if (!stmpe) | 1064 | if (!stmpe) |
1009 | return -ENOMEM; | 1065 | return -ENOMEM; |
1010 | 1066 | ||
@@ -1026,11 +1082,12 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum) | |||
1026 | ci->init(stmpe); | 1082 | ci->init(stmpe); |
1027 | 1083 | ||
1028 | if (pdata->irq_over_gpio) { | 1084 | if (pdata->irq_over_gpio) { |
1029 | ret = gpio_request_one(pdata->irq_gpio, GPIOF_DIR_IN, "stmpe"); | 1085 | ret = devm_gpio_request_one(ci->dev, pdata->irq_gpio, |
1086 | GPIOF_DIR_IN, "stmpe"); | ||
1030 | if (ret) { | 1087 | if (ret) { |
1031 | dev_err(stmpe->dev, "failed to request IRQ GPIO: %d\n", | 1088 | dev_err(stmpe->dev, "failed to request IRQ GPIO: %d\n", |
1032 | ret); | 1089 | ret); |
1033 | goto out_free; | 1090 | return ret; |
1034 | } | 1091 | } |
1035 | 1092 | ||
1036 | stmpe->irq = gpio_to_irq(pdata->irq_gpio); | 1093 | stmpe->irq = gpio_to_irq(pdata->irq_gpio); |
@@ -1047,51 +1104,40 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum) | |||
1047 | dev_err(stmpe->dev, | 1104 | dev_err(stmpe->dev, |
1048 | "%s does not support no-irq mode!\n", | 1105 | "%s does not support no-irq mode!\n", |
1049 | stmpe->variant->name); | 1106 | stmpe->variant->name); |
1050 | ret = -ENODEV; | 1107 | return -ENODEV; |
1051 | goto free_gpio; | ||
1052 | } | 1108 | } |
1053 | stmpe->variant = stmpe_noirq_variant_info[stmpe->partnum]; | 1109 | stmpe->variant = stmpe_noirq_variant_info[stmpe->partnum]; |
1110 | } else if (pdata->irq_trigger == IRQF_TRIGGER_NONE) { | ||
1111 | pdata->irq_trigger = | ||
1112 | irqd_get_trigger_type(irq_get_irq_data(stmpe->irq)); | ||
1054 | } | 1113 | } |
1055 | 1114 | ||
1056 | ret = stmpe_chip_init(stmpe); | 1115 | ret = stmpe_chip_init(stmpe); |
1057 | if (ret) | 1116 | if (ret) |
1058 | goto free_gpio; | 1117 | return ret; |
1059 | 1118 | ||
1060 | if (stmpe->irq >= 0) { | 1119 | if (stmpe->irq >= 0) { |
1061 | ret = stmpe_irq_init(stmpe); | 1120 | ret = stmpe_irq_init(stmpe, np); |
1062 | if (ret) | 1121 | if (ret) |
1063 | goto free_gpio; | 1122 | return ret; |
1064 | 1123 | ||
1065 | ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq, | 1124 | ret = devm_request_threaded_irq(ci->dev, stmpe->irq, NULL, |
1066 | pdata->irq_trigger | IRQF_ONESHOT, | 1125 | stmpe_irq, pdata->irq_trigger | IRQF_ONESHOT, |
1067 | "stmpe", stmpe); | 1126 | "stmpe", stmpe); |
1068 | if (ret) { | 1127 | if (ret) { |
1069 | dev_err(stmpe->dev, "failed to request IRQ: %d\n", | 1128 | dev_err(stmpe->dev, "failed to request IRQ: %d\n", |
1070 | ret); | 1129 | ret); |
1071 | goto out_removeirq; | 1130 | return ret; |
1072 | } | 1131 | } |
1073 | } | 1132 | } |
1074 | 1133 | ||
1075 | ret = stmpe_devices_init(stmpe); | 1134 | ret = stmpe_devices_init(stmpe); |
1076 | if (ret) { | 1135 | if (!ret) |
1077 | dev_err(stmpe->dev, "failed to add children\n"); | 1136 | return 0; |
1078 | goto out_removedevs; | ||
1079 | } | ||
1080 | |||
1081 | return 0; | ||
1082 | 1137 | ||
1083 | out_removedevs: | 1138 | dev_err(stmpe->dev, "failed to add children\n"); |
1084 | mfd_remove_devices(stmpe->dev); | 1139 | mfd_remove_devices(stmpe->dev); |
1085 | if (stmpe->irq >= 0) | 1140 | |
1086 | free_irq(stmpe->irq, stmpe); | ||
1087 | out_removeirq: | ||
1088 | if (stmpe->irq >= 0) | ||
1089 | stmpe_irq_remove(stmpe); | ||
1090 | free_gpio: | ||
1091 | if (pdata->irq_over_gpio) | ||
1092 | gpio_free(pdata->irq_gpio); | ||
1093 | out_free: | ||
1094 | kfree(stmpe); | ||
1095 | return ret; | 1141 | return ret; |
1096 | } | 1142 | } |
1097 | 1143 | ||
@@ -1099,16 +1145,6 @@ int stmpe_remove(struct stmpe *stmpe) | |||
1099 | { | 1145 | { |
1100 | mfd_remove_devices(stmpe->dev); | 1146 | mfd_remove_devices(stmpe->dev); |
1101 | 1147 | ||
1102 | if (stmpe->irq >= 0) { | ||
1103 | free_irq(stmpe->irq, stmpe); | ||
1104 | stmpe_irq_remove(stmpe); | ||
1105 | } | ||
1106 | |||
1107 | if (stmpe->pdata->irq_over_gpio) | ||
1108 | gpio_free(stmpe->pdata->irq_gpio); | ||
1109 | |||
1110 | kfree(stmpe); | ||
1111 | |||
1112 | return 0; | 1148 | return 0; |
1113 | } | 1149 | } |
1114 | 1150 | ||
diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c new file mode 100644 index 00000000000..8ca3bf023fb --- /dev/null +++ b/drivers/mfd/ti_am335x_tscadc.c | |||
@@ -0,0 +1,274 @@ | |||
1 | /* | ||
2 | * TI Touch Screen / ADC MFD driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation version 2. | ||
9 | * | ||
10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
11 | * kind, whether express or implied; without even the implied warranty | ||
12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/clk.h> | ||
22 | #include <linux/regmap.h> | ||
23 | #include <linux/mfd/core.h> | ||
24 | #include <linux/pm_runtime.h> | ||
25 | |||
26 | #include <linux/mfd/ti_am335x_tscadc.h> | ||
27 | #include <linux/input/ti_am335x_tsc.h> | ||
28 | #include <linux/platform_data/ti_am335x_adc.h> | ||
29 | |||
30 | static unsigned int tscadc_readl(struct ti_tscadc_dev *tsadc, unsigned int reg) | ||
31 | { | ||
32 | unsigned int val; | ||
33 | |||
34 | regmap_read(tsadc->regmap_tscadc, reg, &val); | ||
35 | return val; | ||
36 | } | ||
37 | |||
38 | static void tscadc_writel(struct ti_tscadc_dev *tsadc, unsigned int reg, | ||
39 | unsigned int val) | ||
40 | { | ||
41 | regmap_write(tsadc->regmap_tscadc, reg, val); | ||
42 | } | ||
43 | |||
44 | static const struct regmap_config tscadc_regmap_config = { | ||
45 | .name = "ti_tscadc", | ||
46 | .reg_bits = 32, | ||
47 | .reg_stride = 4, | ||
48 | .val_bits = 32, | ||
49 | }; | ||
50 | |||
51 | static void tscadc_idle_config(struct ti_tscadc_dev *config) | ||
52 | { | ||
53 | unsigned int idleconfig; | ||
54 | |||
55 | idleconfig = STEPCONFIG_YNN | STEPCONFIG_INM_ADCREFM | | ||
56 | STEPCONFIG_INP_ADCREFM | STEPCONFIG_YPN; | ||
57 | |||
58 | tscadc_writel(config, REG_IDLECONFIG, idleconfig); | ||
59 | } | ||
60 | |||
61 | static int __devinit ti_tscadc_probe(struct platform_device *pdev) | ||
62 | { | ||
63 | struct ti_tscadc_dev *tscadc; | ||
64 | struct resource *res; | ||
65 | struct clk *clk; | ||
66 | struct mfd_tscadc_board *pdata = pdev->dev.platform_data; | ||
67 | struct mfd_cell *cell; | ||
68 | int err, ctrl; | ||
69 | int clk_value, clock_rate; | ||
70 | int tsc_wires, adc_channels = 0, total_channels; | ||
71 | |||
72 | if (!pdata) { | ||
73 | dev_err(&pdev->dev, "Could not find platform data\n"); | ||
74 | return -EINVAL; | ||
75 | } | ||
76 | |||
77 | if (pdata->adc_init) | ||
78 | adc_channels = pdata->adc_init->adc_channels; | ||
79 | |||
80 | tsc_wires = pdata->tsc_init->wires; | ||
81 | total_channels = tsc_wires + adc_channels; | ||
82 | |||
83 | if (total_channels > 8) { | ||
84 | dev_err(&pdev->dev, "Number of i/p channels more than 8\n"); | ||
85 | return -EINVAL; | ||
86 | } | ||
87 | |||
88 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
89 | if (!res) { | ||
90 | dev_err(&pdev->dev, "no memory resource defined.\n"); | ||
91 | return -EINVAL; | ||
92 | } | ||
93 | |||
94 | /* Allocate memory for device */ | ||
95 | tscadc = devm_kzalloc(&pdev->dev, | ||
96 | sizeof(struct ti_tscadc_dev), GFP_KERNEL); | ||
97 | if (!tscadc) { | ||
98 | dev_err(&pdev->dev, "failed to allocate memory.\n"); | ||
99 | return -ENOMEM; | ||
100 | } | ||
101 | tscadc->dev = &pdev->dev; | ||
102 | |||
103 | err = platform_get_irq(pdev, 0); | ||
104 | if (err < 0) { | ||
105 | dev_err(&pdev->dev, "no irq ID is specified.\n"); | ||
106 | goto ret; | ||
107 | } else | ||
108 | tscadc->irq = err; | ||
109 | |||
110 | res = devm_request_mem_region(&pdev->dev, | ||
111 | res->start, resource_size(res), pdev->name); | ||
112 | if (!res) { | ||
113 | dev_err(&pdev->dev, "failed to reserve registers.\n"); | ||
114 | return -EBUSY; | ||
115 | } | ||
116 | |||
117 | tscadc->tscadc_base = devm_ioremap(&pdev->dev, | ||
118 | res->start, resource_size(res)); | ||
119 | if (!tscadc->tscadc_base) { | ||
120 | dev_err(&pdev->dev, "failed to map registers.\n"); | ||
121 | return -ENOMEM; | ||
122 | } | ||
123 | |||
124 | tscadc->regmap_tscadc = devm_regmap_init_mmio(&pdev->dev, | ||
125 | tscadc->tscadc_base, &tscadc_regmap_config); | ||
126 | if (IS_ERR(tscadc->regmap_tscadc)) { | ||
127 | dev_err(&pdev->dev, "regmap init failed\n"); | ||
128 | err = PTR_ERR(tscadc->regmap_tscadc); | ||
129 | goto ret; | ||
130 | } | ||
131 | |||
132 | pm_runtime_enable(&pdev->dev); | ||
133 | pm_runtime_get_sync(&pdev->dev); | ||
134 | |||
135 | /* | ||
136 | * The TSC_ADC_Subsystem has 2 clock domains | ||
137 | * OCP_CLK and ADC_CLK. | ||
138 | * The ADC clock is expected to run at target of 3MHz, | ||
139 | * and expected to capture 12-bit data at a rate of 200 KSPS. | ||
140 | * The TSC_ADC_SS controller design assumes the OCP clock is | ||
141 | * at least 6x faster than the ADC clock. | ||
142 | */ | ||
143 | clk = clk_get(&pdev->dev, "adc_tsc_fck"); | ||
144 | if (IS_ERR(clk)) { | ||
145 | dev_err(&pdev->dev, "failed to get TSC fck\n"); | ||
146 | err = PTR_ERR(clk); | ||
147 | goto err_disable_clk; | ||
148 | } | ||
149 | clock_rate = clk_get_rate(clk); | ||
150 | clk_put(clk); | ||
151 | clk_value = clock_rate / ADC_CLK; | ||
152 | if (clk_value < MAX_CLK_DIV) { | ||
153 | dev_err(&pdev->dev, "clock input less than min clock requirement\n"); | ||
154 | err = -EINVAL; | ||
155 | goto err_disable_clk; | ||
156 | } | ||
157 | /* TSCADC_CLKDIV needs to be configured to the value minus 1 */ | ||
158 | clk_value = clk_value - 1; | ||
159 | tscadc_writel(tscadc, REG_CLKDIV, clk_value); | ||
160 | |||
161 | /* Set the control register bits */ | ||
162 | ctrl = CNTRLREG_STEPCONFIGWRT | | ||
163 | CNTRLREG_TSCENB | | ||
164 | CNTRLREG_STEPID | | ||
165 | CNTRLREG_4WIRE; | ||
166 | tscadc_writel(tscadc, REG_CTRL, ctrl); | ||
167 | |||
168 | /* Set register bits for Idle Config Mode */ | ||
169 | tscadc_idle_config(tscadc); | ||
170 | |||
171 | /* Enable the TSC module enable bit */ | ||
172 | ctrl = tscadc_readl(tscadc, REG_CTRL); | ||
173 | ctrl |= CNTRLREG_TSCSSENB; | ||
174 | tscadc_writel(tscadc, REG_CTRL, ctrl); | ||
175 | |||
176 | /* TSC Cell */ | ||
177 | cell = &tscadc->cells[TSC_CELL]; | ||
178 | cell->name = "tsc"; | ||
179 | cell->platform_data = tscadc; | ||
180 | cell->pdata_size = sizeof(*tscadc); | ||
181 | |||
182 | /* ADC Cell */ | ||
183 | cell = &tscadc->cells[ADC_CELL]; | ||
184 | cell->name = "tiadc"; | ||
185 | cell->platform_data = tscadc; | ||
186 | cell->pdata_size = sizeof(*tscadc); | ||
187 | |||
188 | err = mfd_add_devices(&pdev->dev, pdev->id, tscadc->cells, | ||
189 | TSCADC_CELLS, NULL, 0, NULL); | ||
190 | if (err < 0) | ||
191 | goto err_disable_clk; | ||
192 | |||
193 | device_init_wakeup(&pdev->dev, true); | ||
194 | platform_set_drvdata(pdev, tscadc); | ||
195 | |||
196 | return 0; | ||
197 | |||
198 | err_disable_clk: | ||
199 | pm_runtime_put_sync(&pdev->dev); | ||
200 | pm_runtime_disable(&pdev->dev); | ||
201 | ret: | ||
202 | return err; | ||
203 | } | ||
204 | |||
205 | static int __devexit ti_tscadc_remove(struct platform_device *pdev) | ||
206 | { | ||
207 | struct ti_tscadc_dev *tscadc = platform_get_drvdata(pdev); | ||
208 | |||
209 | tscadc_writel(tscadc, REG_SE, 0x00); | ||
210 | |||
211 | pm_runtime_put_sync(&pdev->dev); | ||
212 | pm_runtime_disable(&pdev->dev); | ||
213 | |||
214 | mfd_remove_devices(tscadc->dev); | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | #ifdef CONFIG_PM | ||
220 | static int tscadc_suspend(struct device *dev) | ||
221 | { | ||
222 | struct ti_tscadc_dev *tscadc_dev = dev_get_drvdata(dev); | ||
223 | |||
224 | tscadc_writel(tscadc_dev, REG_SE, 0x00); | ||
225 | pm_runtime_put_sync(dev); | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static int tscadc_resume(struct device *dev) | ||
231 | { | ||
232 | struct ti_tscadc_dev *tscadc_dev = dev_get_drvdata(dev); | ||
233 | unsigned int restore, ctrl; | ||
234 | |||
235 | pm_runtime_get_sync(dev); | ||
236 | |||
237 | /* context restore */ | ||
238 | ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_TSCENB | | ||
239 | CNTRLREG_STEPID | CNTRLREG_4WIRE; | ||
240 | tscadc_writel(tscadc_dev, REG_CTRL, ctrl); | ||
241 | tscadc_idle_config(tscadc_dev); | ||
242 | tscadc_writel(tscadc_dev, REG_SE, STPENB_STEPENB); | ||
243 | restore = tscadc_readl(tscadc_dev, REG_CTRL); | ||
244 | tscadc_writel(tscadc_dev, REG_CTRL, | ||
245 | (restore | CNTRLREG_TSCSSENB)); | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | static const struct dev_pm_ops tscadc_pm_ops = { | ||
251 | .suspend = tscadc_suspend, | ||
252 | .resume = tscadc_resume, | ||
253 | }; | ||
254 | #define TSCADC_PM_OPS (&tscadc_pm_ops) | ||
255 | #else | ||
256 | #define TSCADC_PM_OPS NULL | ||
257 | #endif | ||
258 | |||
259 | static struct platform_driver ti_tscadc_driver = { | ||
260 | .driver = { | ||
261 | .name = "ti_tscadc", | ||
262 | .owner = THIS_MODULE, | ||
263 | .pm = TSCADC_PM_OPS, | ||
264 | }, | ||
265 | .probe = ti_tscadc_probe, | ||
266 | .remove = __devexit_p(ti_tscadc_remove), | ||
267 | |||
268 | }; | ||
269 | |||
270 | module_platform_driver(ti_tscadc_driver); | ||
271 | |||
272 | MODULE_DESCRIPTION("TI touchscreen / ADC MFD controller driver"); | ||
273 | MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); | ||
274 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/tps6507x.c b/drivers/mfd/tps6507x.c index 1b203499c74..409afa23d5d 100644 --- a/drivers/mfd/tps6507x.c +++ b/drivers/mfd/tps6507x.c | |||
@@ -86,9 +86,9 @@ static int tps6507x_i2c_probe(struct i2c_client *i2c, | |||
86 | const struct i2c_device_id *id) | 86 | const struct i2c_device_id *id) |
87 | { | 87 | { |
88 | struct tps6507x_dev *tps6507x; | 88 | struct tps6507x_dev *tps6507x; |
89 | int ret = 0; | ||
90 | 89 | ||
91 | tps6507x = kzalloc(sizeof(struct tps6507x_dev), GFP_KERNEL); | 90 | tps6507x = devm_kzalloc(&i2c->dev, sizeof(struct tps6507x_dev), |
91 | GFP_KERNEL); | ||
92 | if (tps6507x == NULL) | 92 | if (tps6507x == NULL) |
93 | return -ENOMEM; | 93 | return -ENOMEM; |
94 | 94 | ||
@@ -98,19 +98,8 @@ static int tps6507x_i2c_probe(struct i2c_client *i2c, | |||
98 | tps6507x->read_dev = tps6507x_i2c_read_device; | 98 | tps6507x->read_dev = tps6507x_i2c_read_device; |
99 | tps6507x->write_dev = tps6507x_i2c_write_device; | 99 | tps6507x->write_dev = tps6507x_i2c_write_device; |
100 | 100 | ||
101 | ret = mfd_add_devices(tps6507x->dev, -1, | 101 | return mfd_add_devices(tps6507x->dev, -1, tps6507x_devs, |
102 | tps6507x_devs, ARRAY_SIZE(tps6507x_devs), | 102 | ARRAY_SIZE(tps6507x_devs), NULL, 0, NULL); |
103 | NULL, 0, NULL); | ||
104 | |||
105 | if (ret < 0) | ||
106 | goto err; | ||
107 | |||
108 | return ret; | ||
109 | |||
110 | err: | ||
111 | mfd_remove_devices(tps6507x->dev); | ||
112 | kfree(tps6507x); | ||
113 | return ret; | ||
114 | } | 103 | } |
115 | 104 | ||
116 | static int tps6507x_i2c_remove(struct i2c_client *i2c) | 105 | static int tps6507x_i2c_remove(struct i2c_client *i2c) |
@@ -118,8 +107,6 @@ static int tps6507x_i2c_remove(struct i2c_client *i2c) | |||
118 | struct tps6507x_dev *tps6507x = i2c_get_clientdata(i2c); | 107 | struct tps6507x_dev *tps6507x = i2c_get_clientdata(i2c); |
119 | 108 | ||
120 | mfd_remove_devices(tps6507x->dev); | 109 | mfd_remove_devices(tps6507x->dev); |
121 | kfree(tps6507x); | ||
122 | |||
123 | return 0; | 110 | return 0; |
124 | } | 111 | } |
125 | 112 | ||
diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index 382a857b0dd..8d12a8e00d9 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/i2c.h> | 25 | #include <linux/i2c.h> |
26 | #include <linux/mfd/core.h> | 26 | #include <linux/mfd/core.h> |
27 | #include <linux/mfd/tps65090.h> | 27 | #include <linux/mfd/tps65090.h> |
28 | #include <linux/regmap.h> | ||
29 | #include <linux/err.h> | 28 | #include <linux/err.h> |
30 | 29 | ||
31 | #define NUM_INT_REG 2 | 30 | #define NUM_INT_REG 2 |
@@ -39,204 +38,102 @@ | |||
39 | #define TPS65090_INT_MSK 0x2 | 38 | #define TPS65090_INT_MSK 0x2 |
40 | #define TPS65090_INT_MSK2 0x3 | 39 | #define TPS65090_INT_MSK2 0x3 |
41 | 40 | ||
42 | struct tps65090_irq_data { | 41 | #define TPS65090_INT1_MASK_VAC_STATUS_CHANGE 1 |
43 | u8 mask_reg; | 42 | #define TPS65090_INT1_MASK_VSYS_STATUS_CHANGE 2 |
44 | u8 mask_pos; | 43 | #define TPS65090_INT1_MASK_BAT_STATUS_CHANGE 3 |
45 | }; | 44 | #define TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE 4 |
46 | 45 | #define TPS65090_INT1_MASK_CHARGING_COMPLETE 5 | |
47 | #define TPS65090_IRQ(_reg, _mask_pos) \ | 46 | #define TPS65090_INT1_MASK_OVERLOAD_DCDC1 6 |
48 | { \ | 47 | #define TPS65090_INT1_MASK_OVERLOAD_DCDC2 7 |
49 | .mask_reg = (_reg), \ | 48 | #define TPS65090_INT2_MASK_OVERLOAD_DCDC3 0 |
50 | .mask_pos = (_mask_pos), \ | 49 | #define TPS65090_INT2_MASK_OVERLOAD_FET1 1 |
51 | } | 50 | #define TPS65090_INT2_MASK_OVERLOAD_FET2 2 |
52 | 51 | #define TPS65090_INT2_MASK_OVERLOAD_FET3 3 | |
53 | static const struct tps65090_irq_data tps65090_irqs[] = { | 52 | #define TPS65090_INT2_MASK_OVERLOAD_FET4 4 |
54 | [0] = TPS65090_IRQ(0, 0), | 53 | #define TPS65090_INT2_MASK_OVERLOAD_FET5 5 |
55 | [1] = TPS65090_IRQ(0, 1), | 54 | #define TPS65090_INT2_MASK_OVERLOAD_FET6 6 |
56 | [2] = TPS65090_IRQ(0, 2), | 55 | #define TPS65090_INT2_MASK_OVERLOAD_FET7 7 |
57 | [3] = TPS65090_IRQ(0, 3), | ||
58 | [4] = TPS65090_IRQ(0, 4), | ||
59 | [5] = TPS65090_IRQ(0, 5), | ||
60 | [6] = TPS65090_IRQ(0, 6), | ||
61 | [7] = TPS65090_IRQ(0, 7), | ||
62 | [8] = TPS65090_IRQ(1, 0), | ||
63 | [9] = TPS65090_IRQ(1, 1), | ||
64 | [10] = TPS65090_IRQ(1, 2), | ||
65 | [11] = TPS65090_IRQ(1, 3), | ||
66 | [12] = TPS65090_IRQ(1, 4), | ||
67 | [13] = TPS65090_IRQ(1, 5), | ||
68 | [14] = TPS65090_IRQ(1, 6), | ||
69 | [15] = TPS65090_IRQ(1, 7), | ||
70 | }; | ||
71 | 56 | ||
72 | static struct mfd_cell tps65090s[] = { | 57 | static struct mfd_cell tps65090s[] = { |
73 | { | 58 | { |
74 | .name = "tps65090-pmic", | 59 | .name = "tps65090-pmic", |
75 | }, | 60 | }, |
76 | { | 61 | { |
77 | .name = "tps65090-regulator", | 62 | .name = "tps65090-charger", |
78 | }, | 63 | }, |
79 | }; | 64 | }; |
80 | 65 | ||
81 | int tps65090_write(struct device *dev, int reg, uint8_t val) | 66 | static const struct regmap_irq tps65090_irqs[] = { |
82 | { | 67 | /* INT1 IRQs*/ |
83 | struct tps65090 *tps = dev_get_drvdata(dev); | 68 | [TPS65090_IRQ_VAC_STATUS_CHANGE] = { |
84 | return regmap_write(tps->rmap, reg, val); | 69 | .mask = TPS65090_INT1_MASK_VAC_STATUS_CHANGE, |
85 | } | 70 | }, |
86 | EXPORT_SYMBOL_GPL(tps65090_write); | 71 | [TPS65090_IRQ_VSYS_STATUS_CHANGE] = { |
87 | 72 | .mask = TPS65090_INT1_MASK_VSYS_STATUS_CHANGE, | |
88 | int tps65090_read(struct device *dev, int reg, uint8_t *val) | 73 | }, |
89 | { | 74 | [TPS65090_IRQ_BAT_STATUS_CHANGE] = { |
90 | struct tps65090 *tps = dev_get_drvdata(dev); | 75 | .mask = TPS65090_INT1_MASK_BAT_STATUS_CHANGE, |
91 | unsigned int temp_val; | 76 | }, |
92 | int ret; | 77 | [TPS65090_IRQ_CHARGING_STATUS_CHANGE] = { |
93 | ret = regmap_read(tps->rmap, reg, &temp_val); | 78 | .mask = TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE, |
94 | if (!ret) | 79 | }, |
95 | *val = temp_val; | 80 | [TPS65090_IRQ_CHARGING_COMPLETE] = { |
96 | return ret; | 81 | .mask = TPS65090_INT1_MASK_CHARGING_COMPLETE, |
97 | } | 82 | }, |
98 | EXPORT_SYMBOL_GPL(tps65090_read); | 83 | [TPS65090_IRQ_OVERLOAD_DCDC1] = { |
99 | 84 | .mask = TPS65090_INT1_MASK_OVERLOAD_DCDC1, | |
100 | int tps65090_set_bits(struct device *dev, int reg, uint8_t bit_num) | 85 | }, |
101 | { | 86 | [TPS65090_IRQ_OVERLOAD_DCDC2] = { |
102 | struct tps65090 *tps = dev_get_drvdata(dev); | 87 | .mask = TPS65090_INT1_MASK_OVERLOAD_DCDC2, |
103 | return regmap_update_bits(tps->rmap, reg, BIT(bit_num), ~0u); | 88 | }, |
104 | } | 89 | /* INT2 IRQs*/ |
105 | EXPORT_SYMBOL_GPL(tps65090_set_bits); | 90 | [TPS65090_IRQ_OVERLOAD_DCDC3] = { |
106 | 91 | .reg_offset = 1, | |
107 | int tps65090_clr_bits(struct device *dev, int reg, uint8_t bit_num) | 92 | .mask = TPS65090_INT2_MASK_OVERLOAD_DCDC3, |
108 | { | 93 | }, |
109 | struct tps65090 *tps = dev_get_drvdata(dev); | 94 | [TPS65090_IRQ_OVERLOAD_FET1] = { |
110 | return regmap_update_bits(tps->rmap, reg, BIT(bit_num), 0u); | 95 | .reg_offset = 1, |
111 | } | 96 | .mask = TPS65090_INT2_MASK_OVERLOAD_FET1, |
112 | EXPORT_SYMBOL_GPL(tps65090_clr_bits); | 97 | }, |
113 | 98 | [TPS65090_IRQ_OVERLOAD_FET2] = { | |
114 | static void tps65090_irq_lock(struct irq_data *data) | 99 | .reg_offset = 1, |
115 | { | 100 | .mask = TPS65090_INT2_MASK_OVERLOAD_FET2, |
116 | struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data); | 101 | }, |
117 | 102 | [TPS65090_IRQ_OVERLOAD_FET3] = { | |
118 | mutex_lock(&tps65090->irq_lock); | 103 | .reg_offset = 1, |
119 | } | 104 | .mask = TPS65090_INT2_MASK_OVERLOAD_FET3, |
120 | 105 | }, | |
121 | static void tps65090_irq_mask(struct irq_data *irq_data) | 106 | [TPS65090_IRQ_OVERLOAD_FET4] = { |
122 | { | 107 | .reg_offset = 1, |
123 | struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data); | 108 | .mask = TPS65090_INT2_MASK_OVERLOAD_FET4, |
124 | unsigned int __irq = irq_data->hwirq; | 109 | }, |
125 | const struct tps65090_irq_data *data = &tps65090_irqs[__irq]; | 110 | [TPS65090_IRQ_OVERLOAD_FET5] = { |
126 | 111 | .reg_offset = 1, | |
127 | tps65090_set_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg), | 112 | .mask = TPS65090_INT2_MASK_OVERLOAD_FET5, |
128 | data->mask_pos); | 113 | }, |
129 | } | 114 | [TPS65090_IRQ_OVERLOAD_FET6] = { |
130 | 115 | .reg_offset = 1, | |
131 | static void tps65090_irq_unmask(struct irq_data *irq_data) | 116 | .mask = TPS65090_INT2_MASK_OVERLOAD_FET6, |
132 | { | 117 | }, |
133 | struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data); | 118 | [TPS65090_IRQ_OVERLOAD_FET7] = { |
134 | unsigned int __irq = irq_data->irq - tps65090->irq_base; | 119 | .reg_offset = 1, |
135 | const struct tps65090_irq_data *data = &tps65090_irqs[__irq]; | 120 | .mask = TPS65090_INT2_MASK_OVERLOAD_FET7, |
136 | 121 | }, | |
137 | tps65090_clr_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg), | 122 | }; |
138 | data->mask_pos); | ||
139 | } | ||
140 | |||
141 | static void tps65090_irq_sync_unlock(struct irq_data *data) | ||
142 | { | ||
143 | struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data); | ||
144 | |||
145 | mutex_unlock(&tps65090->irq_lock); | ||
146 | } | ||
147 | |||
148 | static irqreturn_t tps65090_irq(int irq, void *data) | ||
149 | { | ||
150 | struct tps65090 *tps65090 = data; | ||
151 | int ret = 0; | ||
152 | u8 status, mask; | ||
153 | unsigned long int acks = 0; | ||
154 | int i; | ||
155 | |||
156 | for (i = 0; i < NUM_INT_REG; i++) { | ||
157 | ret = tps65090_read(tps65090->dev, TPS65090_INT_MSK + i, &mask); | ||
158 | if (ret < 0) { | ||
159 | dev_err(tps65090->dev, | ||
160 | "failed to read mask reg [addr:%d]\n", | ||
161 | TPS65090_INT_MSK + i); | ||
162 | return IRQ_NONE; | ||
163 | } | ||
164 | ret = tps65090_read(tps65090->dev, TPS65090_INT_STS + i, | ||
165 | &status); | ||
166 | if (ret < 0) { | ||
167 | dev_err(tps65090->dev, | ||
168 | "failed to read status reg [addr:%d]\n", | ||
169 | TPS65090_INT_STS + i); | ||
170 | return IRQ_NONE; | ||
171 | } | ||
172 | if (status) { | ||
173 | /* Ack only those interrupts which are not masked */ | ||
174 | status &= (~mask); | ||
175 | ret = tps65090_write(tps65090->dev, | ||
176 | TPS65090_INT_STS + i, status); | ||
177 | if (ret < 0) { | ||
178 | dev_err(tps65090->dev, | ||
179 | "failed to write interrupt status\n"); | ||
180 | return IRQ_NONE; | ||
181 | } | ||
182 | acks |= (status << (i * 8)); | ||
183 | } | ||
184 | } | ||
185 | |||
186 | for_each_set_bit(i, &acks, ARRAY_SIZE(tps65090_irqs)) | ||
187 | handle_nested_irq(tps65090->irq_base + i); | ||
188 | return acks ? IRQ_HANDLED : IRQ_NONE; | ||
189 | } | ||
190 | |||
191 | static int tps65090_irq_init(struct tps65090 *tps65090, int irq, | ||
192 | int irq_base) | ||
193 | { | ||
194 | int i, ret; | ||
195 | |||
196 | if (!irq_base) { | ||
197 | dev_err(tps65090->dev, "IRQ base not set\n"); | ||
198 | return -EINVAL; | ||
199 | } | ||
200 | |||
201 | mutex_init(&tps65090->irq_lock); | ||
202 | |||
203 | for (i = 0; i < NUM_INT_REG; i++) | ||
204 | tps65090_write(tps65090->dev, TPS65090_INT_MSK + i, 0xFF); | ||
205 | |||
206 | for (i = 0; i < NUM_INT_REG; i++) | ||
207 | tps65090_write(tps65090->dev, TPS65090_INT_STS + i, 0xff); | ||
208 | |||
209 | tps65090->irq_base = irq_base; | ||
210 | tps65090->irq_chip.name = "tps65090"; | ||
211 | tps65090->irq_chip.irq_mask = tps65090_irq_mask; | ||
212 | tps65090->irq_chip.irq_unmask = tps65090_irq_unmask; | ||
213 | tps65090->irq_chip.irq_bus_lock = tps65090_irq_lock; | ||
214 | tps65090->irq_chip.irq_bus_sync_unlock = tps65090_irq_sync_unlock; | ||
215 | |||
216 | for (i = 0; i < ARRAY_SIZE(tps65090_irqs); i++) { | ||
217 | int __irq = i + tps65090->irq_base; | ||
218 | irq_set_chip_data(__irq, tps65090); | ||
219 | irq_set_chip_and_handler(__irq, &tps65090->irq_chip, | ||
220 | handle_simple_irq); | ||
221 | irq_set_nested_thread(__irq, 1); | ||
222 | #ifdef CONFIG_ARM | ||
223 | set_irq_flags(__irq, IRQF_VALID); | ||
224 | #endif | ||
225 | } | ||
226 | |||
227 | ret = request_threaded_irq(irq, NULL, tps65090_irq, IRQF_ONESHOT, | ||
228 | "tps65090", tps65090); | ||
229 | if (!ret) { | ||
230 | device_init_wakeup(tps65090->dev, 1); | ||
231 | enable_irq_wake(irq); | ||
232 | } | ||
233 | 123 | ||
234 | return ret; | 124 | static struct regmap_irq_chip tps65090_irq_chip = { |
235 | } | 125 | .name = "tps65090", |
126 | .irqs = tps65090_irqs, | ||
127 | .num_irqs = ARRAY_SIZE(tps65090_irqs), | ||
128 | .num_regs = NUM_INT_REG, | ||
129 | .status_base = TPS65090_INT_STS, | ||
130 | .mask_base = TPS65090_INT_MSK, | ||
131 | .mask_invert = true, | ||
132 | }; | ||
236 | 133 | ||
237 | static bool is_volatile_reg(struct device *dev, unsigned int reg) | 134 | static bool is_volatile_reg(struct device *dev, unsigned int reg) |
238 | { | 135 | { |
239 | if (reg == TPS65090_INT_STS) | 136 | if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS2)) |
240 | return true; | 137 | return true; |
241 | else | 138 | else |
242 | return false; | 139 | return false; |
@@ -263,36 +160,36 @@ static int tps65090_i2c_probe(struct i2c_client *client, | |||
263 | return -EINVAL; | 160 | return -EINVAL; |
264 | } | 161 | } |
265 | 162 | ||
266 | tps65090 = devm_kzalloc(&client->dev, sizeof(struct tps65090), | 163 | tps65090 = devm_kzalloc(&client->dev, sizeof(*tps65090), GFP_KERNEL); |
267 | GFP_KERNEL); | 164 | if (!tps65090) { |
268 | if (tps65090 == NULL) | 165 | dev_err(&client->dev, "mem alloc for tps65090 failed\n"); |
269 | return -ENOMEM; | 166 | return -ENOMEM; |
167 | } | ||
270 | 168 | ||
271 | tps65090->client = client; | ||
272 | tps65090->dev = &client->dev; | 169 | tps65090->dev = &client->dev; |
273 | i2c_set_clientdata(client, tps65090); | 170 | i2c_set_clientdata(client, tps65090); |
274 | 171 | ||
275 | mutex_init(&tps65090->lock); | 172 | tps65090->rmap = devm_regmap_init_i2c(client, &tps65090_regmap_config); |
276 | |||
277 | if (client->irq) { | ||
278 | ret = tps65090_irq_init(tps65090, client->irq, pdata->irq_base); | ||
279 | if (ret) { | ||
280 | dev_err(&client->dev, "IRQ init failed with err: %d\n", | ||
281 | ret); | ||
282 | goto err_exit; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | tps65090->rmap = devm_regmap_init_i2c(tps65090->client, | ||
287 | &tps65090_regmap_config); | ||
288 | if (IS_ERR(tps65090->rmap)) { | 173 | if (IS_ERR(tps65090->rmap)) { |
289 | ret = PTR_ERR(tps65090->rmap); | 174 | ret = PTR_ERR(tps65090->rmap); |
290 | dev_err(&client->dev, "regmap_init failed with err: %d\n", ret); | 175 | dev_err(&client->dev, "regmap_init failed with err: %d\n", ret); |
291 | goto err_irq_exit; | 176 | return ret; |
177 | } | ||
178 | |||
179 | if (client->irq) { | ||
180 | ret = regmap_add_irq_chip(tps65090->rmap, client->irq, | ||
181 | IRQF_ONESHOT | IRQF_TRIGGER_LOW, pdata->irq_base, | ||
182 | &tps65090_irq_chip, &tps65090->irq_data); | ||
183 | if (ret) { | ||
184 | dev_err(&client->dev, | ||
185 | "IRQ init failed with err: %d\n", ret); | ||
186 | return ret; | ||
187 | } | ||
292 | } | 188 | } |
293 | 189 | ||
294 | ret = mfd_add_devices(tps65090->dev, -1, tps65090s, | 190 | ret = mfd_add_devices(tps65090->dev, -1, tps65090s, |
295 | ARRAY_SIZE(tps65090s), NULL, 0, NULL); | 191 | ARRAY_SIZE(tps65090s), NULL, |
192 | regmap_irq_chip_get_base(tps65090->irq_data), NULL); | ||
296 | if (ret) { | 193 | if (ret) { |
297 | dev_err(&client->dev, "add mfd devices failed with err: %d\n", | 194 | dev_err(&client->dev, "add mfd devices failed with err: %d\n", |
298 | ret); | 195 | ret); |
@@ -303,8 +200,7 @@ static int tps65090_i2c_probe(struct i2c_client *client, | |||
303 | 200 | ||
304 | err_irq_exit: | 201 | err_irq_exit: |
305 | if (client->irq) | 202 | if (client->irq) |
306 | free_irq(client->irq, tps65090); | 203 | regmap_del_irq_chip(client->irq, tps65090->irq_data); |
307 | err_exit: | ||
308 | return ret; | 204 | return ret; |
309 | } | 205 | } |
310 | 206 | ||
@@ -314,7 +210,7 @@ static int tps65090_i2c_remove(struct i2c_client *client) | |||
314 | 210 | ||
315 | mfd_remove_devices(tps65090->dev); | 211 | mfd_remove_devices(tps65090->dev); |
316 | if (client->irq) | 212 | if (client->irq) |
317 | free_irq(client->irq, tps65090); | 213 | regmap_del_irq_chip(client->irq, tps65090->irq_data); |
318 | 214 | ||
319 | return 0; | 215 | return 0; |
320 | } | 216 | } |
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index e14e252e347..b8f48647661 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c | |||
@@ -160,6 +160,7 @@ static int tps65217_probe(struct i2c_client *client, | |||
160 | unsigned int version; | 160 | unsigned int version; |
161 | unsigned int chip_id = ids->driver_data; | 161 | unsigned int chip_id = ids->driver_data; |
162 | const struct of_device_id *match; | 162 | const struct of_device_id *match; |
163 | bool status_off = false; | ||
163 | int ret; | 164 | int ret; |
164 | 165 | ||
165 | if (client->dev.of_node) { | 166 | if (client->dev.of_node) { |
@@ -170,6 +171,8 @@ static int tps65217_probe(struct i2c_client *client, | |||
170 | return -EINVAL; | 171 | return -EINVAL; |
171 | } | 172 | } |
172 | chip_id = (unsigned int)match->data; | 173 | chip_id = (unsigned int)match->data; |
174 | status_off = of_property_read_bool(client->dev.of_node, | ||
175 | "ti,pmic-shutdown-controller"); | ||
173 | } | 176 | } |
174 | 177 | ||
175 | if (!chip_id) { | 178 | if (!chip_id) { |
@@ -207,6 +210,15 @@ static int tps65217_probe(struct i2c_client *client, | |||
207 | return ret; | 210 | return ret; |
208 | } | 211 | } |
209 | 212 | ||
213 | /* Set the PMIC to shutdown on PWR_EN toggle */ | ||
214 | if (status_off) { | ||
215 | ret = tps65217_set_bits(tps, TPS65217_REG_STATUS, | ||
216 | TPS65217_STATUS_OFF, TPS65217_STATUS_OFF, | ||
217 | TPS65217_PROTECT_NONE); | ||
218 | if (ret) | ||
219 | dev_warn(tps->dev, "unable to set the status OFF\n"); | ||
220 | } | ||
221 | |||
210 | dev_info(tps->dev, "TPS65217 ID %#x version 1.%d\n", | 222 | dev_info(tps->dev, "TPS65217 ID %#x version 1.%d\n", |
211 | (version & TPS65217_CHIPID_CHIP_MASK) >> 4, | 223 | (version & TPS65217_CHIPID_CHIP_MASK) >> 4, |
212 | version & TPS65217_CHIPID_REV_MASK); | 224 | version & TPS65217_CHIPID_REV_MASK); |
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 87ba7ada3bb..721b9186a5d 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c | |||
@@ -17,12 +17,14 @@ | |||
17 | 17 | ||
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | #include <linux/irq.h> | 19 | #include <linux/irq.h> |
20 | #include <linux/irqdomain.h> | ||
20 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
21 | #include <linux/module.h> | 22 | #include <linux/module.h> |
22 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
23 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
24 | #include <linux/err.h> | 25 | #include <linux/err.h> |
25 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
27 | #include <linux/platform_device.h> | ||
26 | #include <linux/regmap.h> | 28 | #include <linux/regmap.h> |
27 | 29 | ||
28 | #include <linux/mfd/core.h> | 30 | #include <linux/mfd/core.h> |
@@ -92,6 +94,14 @@ static const struct tps6586x_irq_data tps6586x_irqs[] = { | |||
92 | [TPS6586X_INT_RTC_ALM2] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 1), | 94 | [TPS6586X_INT_RTC_ALM2] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 1), |
93 | }; | 95 | }; |
94 | 96 | ||
97 | static struct resource tps6586x_rtc_resources[] = { | ||
98 | { | ||
99 | .start = TPS6586X_INT_RTC_ALM1, | ||
100 | .end = TPS6586X_INT_RTC_ALM1, | ||
101 | .flags = IORESOURCE_IRQ, | ||
102 | }, | ||
103 | }; | ||
104 | |||
95 | static struct mfd_cell tps6586x_cell[] = { | 105 | static struct mfd_cell tps6586x_cell[] = { |
96 | { | 106 | { |
97 | .name = "tps6586x-gpio", | 107 | .name = "tps6586x-gpio", |
@@ -101,6 +111,8 @@ static struct mfd_cell tps6586x_cell[] = { | |||
101 | }, | 111 | }, |
102 | { | 112 | { |
103 | .name = "tps6586x-rtc", | 113 | .name = "tps6586x-rtc", |
114 | .num_resources = ARRAY_SIZE(tps6586x_rtc_resources), | ||
115 | .resources = &tps6586x_rtc_resources[0], | ||
104 | }, | 116 | }, |
105 | { | 117 | { |
106 | .name = "tps6586x-onkey", | 118 | .name = "tps6586x-onkey", |
@@ -117,6 +129,7 @@ struct tps6586x { | |||
117 | int irq_base; | 129 | int irq_base; |
118 | u32 irq_en; | 130 | u32 irq_en; |
119 | u8 mask_reg[5]; | 131 | u8 mask_reg[5]; |
132 | struct irq_domain *irq_domain; | ||
120 | }; | 133 | }; |
121 | 134 | ||
122 | static inline struct tps6586x *dev_to_tps6586x(struct device *dev) | 135 | static inline struct tps6586x *dev_to_tps6586x(struct device *dev) |
@@ -185,6 +198,14 @@ int tps6586x_update(struct device *dev, int reg, uint8_t val, uint8_t mask) | |||
185 | } | 198 | } |
186 | EXPORT_SYMBOL_GPL(tps6586x_update); | 199 | EXPORT_SYMBOL_GPL(tps6586x_update); |
187 | 200 | ||
201 | int tps6586x_irq_get_virq(struct device *dev, int irq) | ||
202 | { | ||
203 | struct tps6586x *tps6586x = dev_to_tps6586x(dev); | ||
204 | |||
205 | return irq_create_mapping(tps6586x->irq_domain, irq); | ||
206 | } | ||
207 | EXPORT_SYMBOL_GPL(tps6586x_irq_get_virq); | ||
208 | |||
188 | static int __remove_subdev(struct device *dev, void *unused) | 209 | static int __remove_subdev(struct device *dev, void *unused) |
189 | { | 210 | { |
190 | platform_device_unregister(to_platform_device(dev)); | 211 | platform_device_unregister(to_platform_device(dev)); |
@@ -206,7 +227,7 @@ static void tps6586x_irq_lock(struct irq_data *data) | |||
206 | static void tps6586x_irq_enable(struct irq_data *irq_data) | 227 | static void tps6586x_irq_enable(struct irq_data *irq_data) |
207 | { | 228 | { |
208 | struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data); | 229 | struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data); |
209 | unsigned int __irq = irq_data->irq - tps6586x->irq_base; | 230 | unsigned int __irq = irq_data->hwirq; |
210 | const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq]; | 231 | const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq]; |
211 | 232 | ||
212 | tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask; | 233 | tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask; |
@@ -217,7 +238,7 @@ static void tps6586x_irq_disable(struct irq_data *irq_data) | |||
217 | { | 238 | { |
218 | struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data); | 239 | struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data); |
219 | 240 | ||
220 | unsigned int __irq = irq_data->irq - tps6586x->irq_base; | 241 | unsigned int __irq = irq_data->hwirq; |
221 | const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq]; | 242 | const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq]; |
222 | 243 | ||
223 | tps6586x->mask_reg[data->mask_reg] |= data->mask_mask; | 244 | tps6586x->mask_reg[data->mask_reg] |= data->mask_mask; |
@@ -240,6 +261,39 @@ static void tps6586x_irq_sync_unlock(struct irq_data *data) | |||
240 | mutex_unlock(&tps6586x->irq_lock); | 261 | mutex_unlock(&tps6586x->irq_lock); |
241 | } | 262 | } |
242 | 263 | ||
264 | static struct irq_chip tps6586x_irq_chip = { | ||
265 | .name = "tps6586x", | ||
266 | .irq_bus_lock = tps6586x_irq_lock, | ||
267 | .irq_bus_sync_unlock = tps6586x_irq_sync_unlock, | ||
268 | .irq_disable = tps6586x_irq_disable, | ||
269 | .irq_enable = tps6586x_irq_enable, | ||
270 | }; | ||
271 | |||
272 | static int tps6586x_irq_map(struct irq_domain *h, unsigned int virq, | ||
273 | irq_hw_number_t hw) | ||
274 | { | ||
275 | struct tps6586x *tps6586x = h->host_data; | ||
276 | |||
277 | irq_set_chip_data(virq, tps6586x); | ||
278 | irq_set_chip_and_handler(virq, &tps6586x_irq_chip, handle_simple_irq); | ||
279 | irq_set_nested_thread(virq, 1); | ||
280 | |||
281 | /* ARM needs us to explicitly flag the IRQ as valid | ||
282 | * and will set them noprobe when we do so. */ | ||
283 | #ifdef CONFIG_ARM | ||
284 | set_irq_flags(virq, IRQF_VALID); | ||
285 | #else | ||
286 | irq_set_noprobe(virq); | ||
287 | #endif | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static struct irq_domain_ops tps6586x_domain_ops = { | ||
293 | .map = tps6586x_irq_map, | ||
294 | .xlate = irq_domain_xlate_twocell, | ||
295 | }; | ||
296 | |||
243 | static irqreturn_t tps6586x_irq(int irq, void *data) | 297 | static irqreturn_t tps6586x_irq(int irq, void *data) |
244 | { | 298 | { |
245 | struct tps6586x *tps6586x = data; | 299 | struct tps6586x *tps6586x = data; |
@@ -260,7 +314,8 @@ static irqreturn_t tps6586x_irq(int irq, void *data) | |||
260 | int i = __ffs(acks); | 314 | int i = __ffs(acks); |
261 | 315 | ||
262 | if (tps6586x->irq_en & (1 << i)) | 316 | if (tps6586x->irq_en & (1 << i)) |
263 | handle_nested_irq(tps6586x->irq_base + i); | 317 | handle_nested_irq( |
318 | irq_find_mapping(tps6586x->irq_domain, i)); | ||
264 | 319 | ||
265 | acks &= ~(1 << i); | 320 | acks &= ~(1 << i); |
266 | } | 321 | } |
@@ -273,11 +328,8 @@ static int tps6586x_irq_init(struct tps6586x *tps6586x, int irq, | |||
273 | { | 328 | { |
274 | int i, ret; | 329 | int i, ret; |
275 | u8 tmp[4]; | 330 | u8 tmp[4]; |
276 | 331 | int new_irq_base; | |
277 | if (!irq_base) { | 332 | int irq_num = ARRAY_SIZE(tps6586x_irqs); |
278 | dev_warn(tps6586x->dev, "No interrupt support on IRQ base\n"); | ||
279 | return -EINVAL; | ||
280 | } | ||
281 | 333 | ||
282 | mutex_init(&tps6586x->irq_lock); | 334 | mutex_init(&tps6586x->irq_lock); |
283 | for (i = 0; i < 5; i++) { | 335 | for (i = 0; i < 5; i++) { |
@@ -287,25 +339,24 @@ static int tps6586x_irq_init(struct tps6586x *tps6586x, int irq, | |||
287 | 339 | ||
288 | tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1, sizeof(tmp), tmp); | 340 | tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1, sizeof(tmp), tmp); |
289 | 341 | ||
290 | tps6586x->irq_base = irq_base; | 342 | if (irq_base > 0) { |
291 | 343 | new_irq_base = irq_alloc_descs(irq_base, 0, irq_num, -1); | |
292 | tps6586x->irq_chip.name = "tps6586x"; | 344 | if (new_irq_base < 0) { |
293 | tps6586x->irq_chip.irq_enable = tps6586x_irq_enable; | 345 | dev_err(tps6586x->dev, |
294 | tps6586x->irq_chip.irq_disable = tps6586x_irq_disable; | 346 | "Failed to alloc IRQs: %d\n", new_irq_base); |
295 | tps6586x->irq_chip.irq_bus_lock = tps6586x_irq_lock; | 347 | return new_irq_base; |
296 | tps6586x->irq_chip.irq_bus_sync_unlock = tps6586x_irq_sync_unlock; | 348 | } |
297 | 349 | } else { | |
298 | for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) { | 350 | new_irq_base = 0; |
299 | int __irq = i + tps6586x->irq_base; | ||
300 | irq_set_chip_data(__irq, tps6586x); | ||
301 | irq_set_chip_and_handler(__irq, &tps6586x->irq_chip, | ||
302 | handle_simple_irq); | ||
303 | irq_set_nested_thread(__irq, 1); | ||
304 | #ifdef CONFIG_ARM | ||
305 | set_irq_flags(__irq, IRQF_VALID); | ||
306 | #endif | ||
307 | } | 351 | } |
308 | 352 | ||
353 | tps6586x->irq_domain = irq_domain_add_simple(tps6586x->dev->of_node, | ||
354 | irq_num, new_irq_base, &tps6586x_domain_ops, | ||
355 | tps6586x); | ||
356 | if (!tps6586x->irq_domain) { | ||
357 | dev_err(tps6586x->dev, "Failed to create IRQ domain\n"); | ||
358 | return -ENOMEM; | ||
359 | } | ||
309 | ret = request_threaded_irq(irq, NULL, tps6586x_irq, IRQF_ONESHOT, | 360 | ret = request_threaded_irq(irq, NULL, tps6586x_irq, IRQF_ONESHOT, |
310 | "tps6586x", tps6586x); | 361 | "tps6586x", tps6586x); |
311 | 362 | ||
@@ -461,7 +512,7 @@ static int tps6586x_i2c_probe(struct i2c_client *client, | |||
461 | 512 | ||
462 | ret = mfd_add_devices(tps6586x->dev, -1, | 513 | ret = mfd_add_devices(tps6586x->dev, -1, |
463 | tps6586x_cell, ARRAY_SIZE(tps6586x_cell), | 514 | tps6586x_cell, ARRAY_SIZE(tps6586x_cell), |
464 | NULL, 0, NULL); | 515 | NULL, 0, tps6586x->irq_domain); |
465 | if (ret < 0) { | 516 | if (ret < 0) { |
466 | dev_err(&client->dev, "mfd_add_devices failed: %d\n", ret); | 517 | dev_err(&client->dev, "mfd_add_devices failed: %d\n", ret); |
467 | goto err_mfd_add; | 518 | goto err_mfd_add; |
diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c deleted file mode 100644 index 09aab3e4776..00000000000 --- a/drivers/mfd/tps65910-irq.c +++ /dev/null | |||
@@ -1,260 +0,0 @@ | |||
1 | /* | ||
2 | * tps65910-irq.c -- TI TPS6591x | ||
3 | * | ||
4 | * Copyright 2010 Texas Instruments Inc. | ||
5 | * | ||
6 | * Author: Graeme Gregory <gg@slimlogic.co.uk> | ||
7 | * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/bug.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/irq.h> | ||
23 | #include <linux/irqdomain.h> | ||
24 | #include <linux/gpio.h> | ||
25 | #include <linux/mfd/tps65910.h> | ||
26 | |||
27 | /* | ||
28 | * This is a threaded IRQ handler so can access I2C/SPI. Since all | ||
29 | * interrupts are clear on read the IRQ line will be reasserted and | ||
30 | * the physical IRQ will be handled again if another interrupt is | ||
31 | * asserted while we run - in the normal course of events this is a | ||
32 | * rare occurrence so we save I2C/SPI reads. We're also assuming that | ||
33 | * it's rare to get lots of interrupts firing simultaneously so try to | ||
34 | * minimise I/O. | ||
35 | */ | ||
36 | static irqreturn_t tps65910_irq(int irq, void *irq_data) | ||
37 | { | ||
38 | struct tps65910 *tps65910 = irq_data; | ||
39 | unsigned int reg; | ||
40 | u32 irq_sts; | ||
41 | u32 irq_mask; | ||
42 | int i; | ||
43 | |||
44 | tps65910_reg_read(tps65910, TPS65910_INT_STS, ®); | ||
45 | irq_sts = reg; | ||
46 | tps65910_reg_read(tps65910, TPS65910_INT_STS2, ®); | ||
47 | irq_sts |= reg << 8; | ||
48 | switch (tps65910_chip_id(tps65910)) { | ||
49 | case TPS65911: | ||
50 | tps65910_reg_read(tps65910, TPS65910_INT_STS3, ®); | ||
51 | irq_sts |= reg << 16; | ||
52 | } | ||
53 | |||
54 | tps65910_reg_read(tps65910, TPS65910_INT_MSK, ®); | ||
55 | irq_mask = reg; | ||
56 | tps65910_reg_read(tps65910, TPS65910_INT_MSK2, ®); | ||
57 | irq_mask |= reg << 8; | ||
58 | switch (tps65910_chip_id(tps65910)) { | ||
59 | case TPS65911: | ||
60 | tps65910_reg_read(tps65910, TPS65910_INT_MSK3, ®); | ||
61 | irq_mask |= reg << 16; | ||
62 | } | ||
63 | |||
64 | irq_sts &= ~irq_mask; | ||
65 | |||
66 | if (!irq_sts) | ||
67 | return IRQ_NONE; | ||
68 | |||
69 | for (i = 0; i < tps65910->irq_num; i++) { | ||
70 | |||
71 | if (!(irq_sts & (1 << i))) | ||
72 | continue; | ||
73 | |||
74 | handle_nested_irq(irq_find_mapping(tps65910->domain, i)); | ||
75 | } | ||
76 | |||
77 | /* Write the STS register back to clear IRQs we handled */ | ||
78 | reg = irq_sts & 0xFF; | ||
79 | irq_sts >>= 8; | ||
80 | tps65910_reg_write(tps65910, TPS65910_INT_STS, reg); | ||
81 | reg = irq_sts & 0xFF; | ||
82 | tps65910_reg_write(tps65910, TPS65910_INT_STS2, reg); | ||
83 | switch (tps65910_chip_id(tps65910)) { | ||
84 | case TPS65911: | ||
85 | reg = irq_sts >> 8; | ||
86 | tps65910_reg_write(tps65910, TPS65910_INT_STS3, reg); | ||
87 | } | ||
88 | |||
89 | return IRQ_HANDLED; | ||
90 | } | ||
91 | |||
92 | static void tps65910_irq_lock(struct irq_data *data) | ||
93 | { | ||
94 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); | ||
95 | |||
96 | mutex_lock(&tps65910->irq_lock); | ||
97 | } | ||
98 | |||
99 | static void tps65910_irq_sync_unlock(struct irq_data *data) | ||
100 | { | ||
101 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); | ||
102 | u32 reg_mask; | ||
103 | unsigned int reg; | ||
104 | |||
105 | tps65910_reg_read(tps65910, TPS65910_INT_MSK, ®); | ||
106 | reg_mask = reg; | ||
107 | tps65910_reg_read(tps65910, TPS65910_INT_MSK2, ®); | ||
108 | reg_mask |= reg << 8; | ||
109 | switch (tps65910_chip_id(tps65910)) { | ||
110 | case TPS65911: | ||
111 | tps65910_reg_read(tps65910, TPS65910_INT_MSK3, ®); | ||
112 | reg_mask |= reg << 16; | ||
113 | } | ||
114 | |||
115 | if (tps65910->irq_mask != reg_mask) { | ||
116 | reg = tps65910->irq_mask & 0xFF; | ||
117 | tps65910_reg_write(tps65910, TPS65910_INT_MSK, reg); | ||
118 | reg = tps65910->irq_mask >> 8 & 0xFF; | ||
119 | tps65910_reg_write(tps65910, TPS65910_INT_MSK2, reg); | ||
120 | switch (tps65910_chip_id(tps65910)) { | ||
121 | case TPS65911: | ||
122 | reg = tps65910->irq_mask >> 16; | ||
123 | tps65910_reg_write(tps65910, TPS65910_INT_MSK3, reg); | ||
124 | } | ||
125 | } | ||
126 | mutex_unlock(&tps65910->irq_lock); | ||
127 | } | ||
128 | |||
129 | static void tps65910_irq_enable(struct irq_data *data) | ||
130 | { | ||
131 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); | ||
132 | |||
133 | tps65910->irq_mask &= ~(1 << data->hwirq); | ||
134 | } | ||
135 | |||
136 | static void tps65910_irq_disable(struct irq_data *data) | ||
137 | { | ||
138 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); | ||
139 | |||
140 | tps65910->irq_mask |= (1 << data->hwirq); | ||
141 | } | ||
142 | |||
143 | #ifdef CONFIG_PM_SLEEP | ||
144 | static int tps65910_irq_set_wake(struct irq_data *data, unsigned int enable) | ||
145 | { | ||
146 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); | ||
147 | return irq_set_irq_wake(tps65910->chip_irq, enable); | ||
148 | } | ||
149 | #else | ||
150 | #define tps65910_irq_set_wake NULL | ||
151 | #endif | ||
152 | |||
153 | static struct irq_chip tps65910_irq_chip = { | ||
154 | .name = "tps65910", | ||
155 | .irq_bus_lock = tps65910_irq_lock, | ||
156 | .irq_bus_sync_unlock = tps65910_irq_sync_unlock, | ||
157 | .irq_disable = tps65910_irq_disable, | ||
158 | .irq_enable = tps65910_irq_enable, | ||
159 | .irq_set_wake = tps65910_irq_set_wake, | ||
160 | }; | ||
161 | |||
162 | static int tps65910_irq_map(struct irq_domain *h, unsigned int virq, | ||
163 | irq_hw_number_t hw) | ||
164 | { | ||
165 | struct tps65910 *tps65910 = h->host_data; | ||
166 | |||
167 | irq_set_chip_data(virq, tps65910); | ||
168 | irq_set_chip_and_handler(virq, &tps65910_irq_chip, handle_edge_irq); | ||
169 | irq_set_nested_thread(virq, 1); | ||
170 | |||
171 | /* ARM needs us to explicitly flag the IRQ as valid | ||
172 | * and will set them noprobe when we do so. */ | ||
173 | #ifdef CONFIG_ARM | ||
174 | set_irq_flags(virq, IRQF_VALID); | ||
175 | #else | ||
176 | irq_set_noprobe(virq); | ||
177 | #endif | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static struct irq_domain_ops tps65910_domain_ops = { | ||
183 | .map = tps65910_irq_map, | ||
184 | .xlate = irq_domain_xlate_twocell, | ||
185 | }; | ||
186 | |||
187 | int tps65910_irq_init(struct tps65910 *tps65910, int irq, | ||
188 | struct tps65910_platform_data *pdata) | ||
189 | { | ||
190 | int ret; | ||
191 | int flags = IRQF_ONESHOT; | ||
192 | |||
193 | if (!irq) { | ||
194 | dev_warn(tps65910->dev, "No interrupt support, no core IRQ\n"); | ||
195 | return -EINVAL; | ||
196 | } | ||
197 | |||
198 | if (!pdata) { | ||
199 | dev_warn(tps65910->dev, "No interrupt support, no pdata\n"); | ||
200 | return -EINVAL; | ||
201 | } | ||
202 | |||
203 | switch (tps65910_chip_id(tps65910)) { | ||
204 | case TPS65910: | ||
205 | tps65910->irq_num = TPS65910_NUM_IRQ; | ||
206 | break; | ||
207 | case TPS65911: | ||
208 | tps65910->irq_num = TPS65911_NUM_IRQ; | ||
209 | break; | ||
210 | } | ||
211 | |||
212 | if (pdata->irq_base > 0) { | ||
213 | pdata->irq_base = irq_alloc_descs(pdata->irq_base, 0, | ||
214 | tps65910->irq_num, -1); | ||
215 | if (pdata->irq_base < 0) { | ||
216 | dev_warn(tps65910->dev, "Failed to alloc IRQs: %d\n", | ||
217 | pdata->irq_base); | ||
218 | return pdata->irq_base; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | tps65910->irq_mask = 0xFFFFFF; | ||
223 | |||
224 | mutex_init(&tps65910->irq_lock); | ||
225 | tps65910->chip_irq = irq; | ||
226 | tps65910->irq_base = pdata->irq_base; | ||
227 | |||
228 | if (pdata->irq_base > 0) | ||
229 | tps65910->domain = irq_domain_add_legacy(tps65910->dev->of_node, | ||
230 | tps65910->irq_num, | ||
231 | pdata->irq_base, | ||
232 | 0, | ||
233 | &tps65910_domain_ops, tps65910); | ||
234 | else | ||
235 | tps65910->domain = irq_domain_add_linear(tps65910->dev->of_node, | ||
236 | tps65910->irq_num, | ||
237 | &tps65910_domain_ops, tps65910); | ||
238 | |||
239 | if (!tps65910->domain) { | ||
240 | dev_err(tps65910->dev, "Failed to create IRQ domain\n"); | ||
241 | return -ENOMEM; | ||
242 | } | ||
243 | |||
244 | ret = request_threaded_irq(irq, NULL, tps65910_irq, flags, | ||
245 | "tps65910", tps65910); | ||
246 | |||
247 | irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW); | ||
248 | |||
249 | if (ret != 0) | ||
250 | dev_err(tps65910->dev, "Failed to request IRQ: %d\n", ret); | ||
251 | |||
252 | return ret; | ||
253 | } | ||
254 | |||
255 | int tps65910_irq_exit(struct tps65910 *tps65910) | ||
256 | { | ||
257 | if (tps65910->chip_irq) | ||
258 | free_irq(tps65910->chip_irq, tps65910); | ||
259 | return 0; | ||
260 | } | ||
diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index ce054654f5b..d7927720483 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c | |||
@@ -19,6 +19,9 @@ | |||
19 | #include <linux/err.h> | 19 | #include <linux/err.h> |
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/i2c.h> | 21 | #include <linux/i2c.h> |
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/irq.h> | ||
24 | #include <linux/irqdomain.h> | ||
22 | #include <linux/mfd/core.h> | 25 | #include <linux/mfd/core.h> |
23 | #include <linux/regmap.h> | 26 | #include <linux/regmap.h> |
24 | #include <linux/mfd/tps65910.h> | 27 | #include <linux/mfd/tps65910.h> |
@@ -50,6 +53,219 @@ static struct mfd_cell tps65910s[] = { | |||
50 | }; | 53 | }; |
51 | 54 | ||
52 | 55 | ||
56 | static const struct regmap_irq tps65911_irqs[] = { | ||
57 | /* INT_STS */ | ||
58 | [TPS65911_IRQ_PWRHOLD_F] = { | ||
59 | .mask = INT_MSK_PWRHOLD_F_IT_MSK_MASK, | ||
60 | .reg_offset = 0, | ||
61 | }, | ||
62 | [TPS65911_IRQ_VBAT_VMHI] = { | ||
63 | .mask = INT_MSK_VMBHI_IT_MSK_MASK, | ||
64 | .reg_offset = 0, | ||
65 | }, | ||
66 | [TPS65911_IRQ_PWRON] = { | ||
67 | .mask = INT_MSK_PWRON_IT_MSK_MASK, | ||
68 | .reg_offset = 0, | ||
69 | }, | ||
70 | [TPS65911_IRQ_PWRON_LP] = { | ||
71 | .mask = INT_MSK_PWRON_LP_IT_MSK_MASK, | ||
72 | .reg_offset = 0, | ||
73 | }, | ||
74 | [TPS65911_IRQ_PWRHOLD_R] = { | ||
75 | .mask = INT_MSK_PWRHOLD_R_IT_MSK_MASK, | ||
76 | .reg_offset = 0, | ||
77 | }, | ||
78 | [TPS65911_IRQ_HOTDIE] = { | ||
79 | .mask = INT_MSK_HOTDIE_IT_MSK_MASK, | ||
80 | .reg_offset = 0, | ||
81 | }, | ||
82 | [TPS65911_IRQ_RTC_ALARM] = { | ||
83 | .mask = INT_MSK_RTC_ALARM_IT_MSK_MASK, | ||
84 | .reg_offset = 0, | ||
85 | }, | ||
86 | [TPS65911_IRQ_RTC_PERIOD] = { | ||
87 | .mask = INT_MSK_RTC_PERIOD_IT_MSK_MASK, | ||
88 | .reg_offset = 0, | ||
89 | }, | ||
90 | |||
91 | /* INT_STS2 */ | ||
92 | [TPS65911_IRQ_GPIO0_R] = { | ||
93 | .mask = INT_MSK2_GPIO0_R_IT_MSK_MASK, | ||
94 | .reg_offset = 1, | ||
95 | }, | ||
96 | [TPS65911_IRQ_GPIO0_F] = { | ||
97 | .mask = INT_MSK2_GPIO0_F_IT_MSK_MASK, | ||
98 | .reg_offset = 1, | ||
99 | }, | ||
100 | [TPS65911_IRQ_GPIO1_R] = { | ||
101 | .mask = INT_MSK2_GPIO1_R_IT_MSK_MASK, | ||
102 | .reg_offset = 1, | ||
103 | }, | ||
104 | [TPS65911_IRQ_GPIO1_F] = { | ||
105 | .mask = INT_MSK2_GPIO1_F_IT_MSK_MASK, | ||
106 | .reg_offset = 1, | ||
107 | }, | ||
108 | [TPS65911_IRQ_GPIO2_R] = { | ||
109 | .mask = INT_MSK2_GPIO2_R_IT_MSK_MASK, | ||
110 | .reg_offset = 1, | ||
111 | }, | ||
112 | [TPS65911_IRQ_GPIO2_F] = { | ||
113 | .mask = INT_MSK2_GPIO2_F_IT_MSK_MASK, | ||
114 | .reg_offset = 1, | ||
115 | }, | ||
116 | [TPS65911_IRQ_GPIO3_R] = { | ||
117 | .mask = INT_MSK2_GPIO3_R_IT_MSK_MASK, | ||
118 | .reg_offset = 1, | ||
119 | }, | ||
120 | [TPS65911_IRQ_GPIO3_F] = { | ||
121 | .mask = INT_MSK2_GPIO3_F_IT_MSK_MASK, | ||
122 | .reg_offset = 1, | ||
123 | }, | ||
124 | |||
125 | /* INT_STS2 */ | ||
126 | [TPS65911_IRQ_GPIO4_R] = { | ||
127 | .mask = INT_MSK3_GPIO4_R_IT_MSK_MASK, | ||
128 | .reg_offset = 2, | ||
129 | }, | ||
130 | [TPS65911_IRQ_GPIO4_F] = { | ||
131 | .mask = INT_MSK3_GPIO4_F_IT_MSK_MASK, | ||
132 | .reg_offset = 2, | ||
133 | }, | ||
134 | [TPS65911_IRQ_GPIO5_R] = { | ||
135 | .mask = INT_MSK3_GPIO5_R_IT_MSK_MASK, | ||
136 | .reg_offset = 2, | ||
137 | }, | ||
138 | [TPS65911_IRQ_GPIO5_F] = { | ||
139 | .mask = INT_MSK3_GPIO5_F_IT_MSK_MASK, | ||
140 | .reg_offset = 2, | ||
141 | }, | ||
142 | [TPS65911_IRQ_WTCHDG] = { | ||
143 | .mask = INT_MSK3_WTCHDG_IT_MSK_MASK, | ||
144 | .reg_offset = 2, | ||
145 | }, | ||
146 | [TPS65911_IRQ_VMBCH2_H] = { | ||
147 | .mask = INT_MSK3_VMBCH2_H_IT_MSK_MASK, | ||
148 | .reg_offset = 2, | ||
149 | }, | ||
150 | [TPS65911_IRQ_VMBCH2_L] = { | ||
151 | .mask = INT_MSK3_VMBCH2_L_IT_MSK_MASK, | ||
152 | .reg_offset = 2, | ||
153 | }, | ||
154 | [TPS65911_IRQ_PWRDN] = { | ||
155 | .mask = INT_MSK3_PWRDN_IT_MSK_MASK, | ||
156 | .reg_offset = 2, | ||
157 | }, | ||
158 | }; | ||
159 | |||
160 | static const struct regmap_irq tps65910_irqs[] = { | ||
161 | /* INT_STS */ | ||
162 | [TPS65910_IRQ_VBAT_VMBDCH] = { | ||
163 | .mask = TPS65910_INT_MSK_VMBDCH_IT_MSK_MASK, | ||
164 | .reg_offset = 0, | ||
165 | }, | ||
166 | [TPS65910_IRQ_VBAT_VMHI] = { | ||
167 | .mask = TPS65910_INT_MSK_VMBHI_IT_MSK_MASK, | ||
168 | .reg_offset = 0, | ||
169 | }, | ||
170 | [TPS65910_IRQ_PWRON] = { | ||
171 | .mask = TPS65910_INT_MSK_PWRON_IT_MSK_MASK, | ||
172 | .reg_offset = 0, | ||
173 | }, | ||
174 | [TPS65910_IRQ_PWRON_LP] = { | ||
175 | .mask = TPS65910_INT_MSK_PWRON_LP_IT_MSK_MASK, | ||
176 | .reg_offset = 0, | ||
177 | }, | ||
178 | [TPS65910_IRQ_PWRHOLD] = { | ||
179 | .mask = TPS65910_INT_MSK_PWRHOLD_IT_MSK_MASK, | ||
180 | .reg_offset = 0, | ||
181 | }, | ||
182 | [TPS65910_IRQ_HOTDIE] = { | ||
183 | .mask = TPS65910_INT_MSK_HOTDIE_IT_MSK_MASK, | ||
184 | .reg_offset = 0, | ||
185 | }, | ||
186 | [TPS65910_IRQ_RTC_ALARM] = { | ||
187 | .mask = TPS65910_INT_MSK_RTC_ALARM_IT_MSK_MASK, | ||
188 | .reg_offset = 0, | ||
189 | }, | ||
190 | [TPS65910_IRQ_RTC_PERIOD] = { | ||
191 | .mask = TPS65910_INT_MSK_RTC_PERIOD_IT_MSK_MASK, | ||
192 | .reg_offset = 0, | ||
193 | }, | ||
194 | |||
195 | /* INT_STS2 */ | ||
196 | [TPS65910_IRQ_GPIO_R] = { | ||
197 | .mask = TPS65910_INT_MSK2_GPIO0_F_IT_MSK_MASK, | ||
198 | .reg_offset = 1, | ||
199 | }, | ||
200 | [TPS65910_IRQ_GPIO_F] = { | ||
201 | .mask = TPS65910_INT_MSK2_GPIO0_R_IT_MSK_MASK, | ||
202 | .reg_offset = 1, | ||
203 | }, | ||
204 | }; | ||
205 | |||
206 | static struct regmap_irq_chip tps65911_irq_chip = { | ||
207 | .name = "tps65910", | ||
208 | .irqs = tps65911_irqs, | ||
209 | .num_irqs = ARRAY_SIZE(tps65911_irqs), | ||
210 | .num_regs = 3, | ||
211 | .irq_reg_stride = 2, | ||
212 | .status_base = TPS65910_INT_STS, | ||
213 | .mask_base = TPS65910_INT_MSK, | ||
214 | .ack_base = TPS65910_INT_STS, | ||
215 | }; | ||
216 | |||
217 | static struct regmap_irq_chip tps65910_irq_chip = { | ||
218 | .name = "tps65910", | ||
219 | .irqs = tps65910_irqs, | ||
220 | .num_irqs = ARRAY_SIZE(tps65910_irqs), | ||
221 | .num_regs = 2, | ||
222 | .irq_reg_stride = 2, | ||
223 | .status_base = TPS65910_INT_STS, | ||
224 | .mask_base = TPS65910_INT_MSK, | ||
225 | .ack_base = TPS65910_INT_STS, | ||
226 | }; | ||
227 | |||
228 | static int tps65910_irq_init(struct tps65910 *tps65910, int irq, | ||
229 | struct tps65910_platform_data *pdata) | ||
230 | { | ||
231 | int ret = 0; | ||
232 | static struct regmap_irq_chip *tps6591x_irqs_chip; | ||
233 | |||
234 | if (!irq) { | ||
235 | dev_warn(tps65910->dev, "No interrupt support, no core IRQ\n"); | ||
236 | return -EINVAL; | ||
237 | } | ||
238 | |||
239 | if (!pdata) { | ||
240 | dev_warn(tps65910->dev, "No interrupt support, no pdata\n"); | ||
241 | return -EINVAL; | ||
242 | } | ||
243 | |||
244 | switch (tps65910_chip_id(tps65910)) { | ||
245 | case TPS65910: | ||
246 | tps6591x_irqs_chip = &tps65910_irq_chip; | ||
247 | break; | ||
248 | case TPS65911: | ||
249 | tps6591x_irqs_chip = &tps65911_irq_chip; | ||
250 | break; | ||
251 | } | ||
252 | |||
253 | tps65910->chip_irq = irq; | ||
254 | ret = regmap_add_irq_chip(tps65910->regmap, tps65910->chip_irq, | ||
255 | IRQF_ONESHOT, pdata->irq_base, | ||
256 | tps6591x_irqs_chip, &tps65910->irq_data); | ||
257 | if (ret < 0) | ||
258 | dev_warn(tps65910->dev, "Failed to add irq_chip %d\n", ret); | ||
259 | return ret; | ||
260 | } | ||
261 | |||
262 | static int tps65910_irq_exit(struct tps65910 *tps65910) | ||
263 | { | ||
264 | if (tps65910->chip_irq > 0) | ||
265 | regmap_del_irq_chip(tps65910->chip_irq, tps65910->irq_data); | ||
266 | return 0; | ||
267 | } | ||
268 | |||
53 | static bool is_volatile_reg(struct device *dev, unsigned int reg) | 269 | static bool is_volatile_reg(struct device *dev, unsigned int reg) |
54 | { | 270 | { |
55 | struct tps65910 *tps65910 = dev_get_drvdata(dev); | 271 | struct tps65910 *tps65910 = dev_get_drvdata(dev); |
@@ -270,7 +486,6 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, | |||
270 | tps65910->dev = &i2c->dev; | 486 | tps65910->dev = &i2c->dev; |
271 | tps65910->i2c_client = i2c; | 487 | tps65910->i2c_client = i2c; |
272 | tps65910->id = chip_id; | 488 | tps65910->id = chip_id; |
273 | mutex_init(&tps65910->io_mutex); | ||
274 | 489 | ||
275 | tps65910->regmap = devm_regmap_init_i2c(i2c, &tps65910_regmap_config); | 490 | tps65910->regmap = devm_regmap_init_i2c(i2c, &tps65910_regmap_config); |
276 | if (IS_ERR(tps65910->regmap)) { | 491 | if (IS_ERR(tps65910->regmap)) { |
@@ -279,14 +494,6 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, | |||
279 | return ret; | 494 | return ret; |
280 | } | 495 | } |
281 | 496 | ||
282 | ret = mfd_add_devices(tps65910->dev, -1, | ||
283 | tps65910s, ARRAY_SIZE(tps65910s), | ||
284 | NULL, 0, NULL); | ||
285 | if (ret < 0) { | ||
286 | dev_err(&i2c->dev, "mfd_add_devices failed: %d\n", ret); | ||
287 | return ret; | ||
288 | } | ||
289 | |||
290 | init_data->irq = pmic_plat_data->irq; | 497 | init_data->irq = pmic_plat_data->irq; |
291 | init_data->irq_base = pmic_plat_data->irq_base; | 498 | init_data->irq_base = pmic_plat_data->irq_base; |
292 | 499 | ||
@@ -299,6 +506,15 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, | |||
299 | pm_power_off = tps65910_power_off; | 506 | pm_power_off = tps65910_power_off; |
300 | } | 507 | } |
301 | 508 | ||
509 | ret = mfd_add_devices(tps65910->dev, -1, | ||
510 | tps65910s, ARRAY_SIZE(tps65910s), | ||
511 | NULL, 0, | ||
512 | regmap_irq_get_domain(tps65910->irq_data)); | ||
513 | if (ret < 0) { | ||
514 | dev_err(&i2c->dev, "mfd_add_devices failed: %d\n", ret); | ||
515 | return ret; | ||
516 | } | ||
517 | |||
302 | return ret; | 518 | return ret; |
303 | } | 519 | } |
304 | 520 | ||
diff --git a/drivers/mfd/tps80031.c b/drivers/mfd/tps80031.c new file mode 100644 index 00000000000..10b51f7dfff --- /dev/null +++ b/drivers/mfd/tps80031.c | |||
@@ -0,0 +1,574 @@ | |||
1 | /* | ||
2 | * tps80031.c -- TI TPS80031/TPS80032 mfd core driver. | ||
3 | * | ||
4 | * MFD core driver for TI TPS80031/TPS80032 Fully Integrated | ||
5 | * Power Management with Power Path and Battery Charger | ||
6 | * | ||
7 | * Copyright (c) 2012, NVIDIA Corporation. | ||
8 | * | ||
9 | * Author: Laxman Dewangan <ldewangan@nvidia.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation version 2. | ||
14 | * | ||
15 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, | ||
16 | * whether express or implied; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | ||
23 | * 02111-1307, USA | ||
24 | */ | ||
25 | |||
26 | #include <linux/err.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/irq.h> | ||
31 | #include <linux/mfd/core.h> | ||
32 | #include <linux/mfd/tps80031.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/pm.h> | ||
35 | #include <linux/regmap.h> | ||
36 | #include <linux/slab.h> | ||
37 | |||
38 | static struct resource tps80031_rtc_resources[] = { | ||
39 | { | ||
40 | .start = TPS80031_INT_RTC_ALARM, | ||
41 | .end = TPS80031_INT_RTC_ALARM, | ||
42 | .flags = IORESOURCE_IRQ, | ||
43 | }, | ||
44 | }; | ||
45 | |||
46 | /* TPS80031 sub mfd devices */ | ||
47 | static struct mfd_cell tps80031_cell[] = { | ||
48 | { | ||
49 | .name = "tps80031-pmic", | ||
50 | }, | ||
51 | { | ||
52 | .name = "tps80031-clock", | ||
53 | }, | ||
54 | { | ||
55 | .name = "tps80031-rtc", | ||
56 | .num_resources = ARRAY_SIZE(tps80031_rtc_resources), | ||
57 | .resources = tps80031_rtc_resources, | ||
58 | }, | ||
59 | { | ||
60 | .name = "tps80031-gpadc", | ||
61 | }, | ||
62 | { | ||
63 | .name = "tps80031-fuel-gauge", | ||
64 | }, | ||
65 | { | ||
66 | .name = "tps80031-charger", | ||
67 | }, | ||
68 | }; | ||
69 | |||
70 | static int tps80031_slave_address[TPS80031_NUM_SLAVES] = { | ||
71 | TPS80031_I2C_ID0_ADDR, | ||
72 | TPS80031_I2C_ID1_ADDR, | ||
73 | TPS80031_I2C_ID2_ADDR, | ||
74 | TPS80031_I2C_ID3_ADDR, | ||
75 | }; | ||
76 | |||
77 | struct tps80031_pupd_data { | ||
78 | u8 reg; | ||
79 | u8 pullup_bit; | ||
80 | u8 pulldown_bit; | ||
81 | }; | ||
82 | |||
83 | #define TPS80031_IRQ(_reg, _mask) \ | ||
84 | { \ | ||
85 | .reg_offset = (TPS80031_INT_MSK_LINE_##_reg) - \ | ||
86 | TPS80031_INT_MSK_LINE_A, \ | ||
87 | .mask = BIT(_mask), \ | ||
88 | } | ||
89 | |||
90 | static const struct regmap_irq tps80031_main_irqs[] = { | ||
91 | [TPS80031_INT_PWRON] = TPS80031_IRQ(A, 0), | ||
92 | [TPS80031_INT_RPWRON] = TPS80031_IRQ(A, 1), | ||
93 | [TPS80031_INT_SYS_VLOW] = TPS80031_IRQ(A, 2), | ||
94 | [TPS80031_INT_RTC_ALARM] = TPS80031_IRQ(A, 3), | ||
95 | [TPS80031_INT_RTC_PERIOD] = TPS80031_IRQ(A, 4), | ||
96 | [TPS80031_INT_HOT_DIE] = TPS80031_IRQ(A, 5), | ||
97 | [TPS80031_INT_VXX_SHORT] = TPS80031_IRQ(A, 6), | ||
98 | [TPS80031_INT_SPDURATION] = TPS80031_IRQ(A, 7), | ||
99 | [TPS80031_INT_WATCHDOG] = TPS80031_IRQ(B, 0), | ||
100 | [TPS80031_INT_BAT] = TPS80031_IRQ(B, 1), | ||
101 | [TPS80031_INT_SIM] = TPS80031_IRQ(B, 2), | ||
102 | [TPS80031_INT_MMC] = TPS80031_IRQ(B, 3), | ||
103 | [TPS80031_INT_RES] = TPS80031_IRQ(B, 4), | ||
104 | [TPS80031_INT_GPADC_RT] = TPS80031_IRQ(B, 5), | ||
105 | [TPS80031_INT_GPADC_SW2_EOC] = TPS80031_IRQ(B, 6), | ||
106 | [TPS80031_INT_CC_AUTOCAL] = TPS80031_IRQ(B, 7), | ||
107 | [TPS80031_INT_ID_WKUP] = TPS80031_IRQ(C, 0), | ||
108 | [TPS80031_INT_VBUSS_WKUP] = TPS80031_IRQ(C, 1), | ||
109 | [TPS80031_INT_ID] = TPS80031_IRQ(C, 2), | ||
110 | [TPS80031_INT_VBUS] = TPS80031_IRQ(C, 3), | ||
111 | [TPS80031_INT_CHRG_CTRL] = TPS80031_IRQ(C, 4), | ||
112 | [TPS80031_INT_EXT_CHRG] = TPS80031_IRQ(C, 5), | ||
113 | [TPS80031_INT_INT_CHRG] = TPS80031_IRQ(C, 6), | ||
114 | [TPS80031_INT_RES2] = TPS80031_IRQ(C, 7), | ||
115 | }; | ||
116 | |||
117 | static struct regmap_irq_chip tps80031_irq_chip = { | ||
118 | .name = "tps80031", | ||
119 | .irqs = tps80031_main_irqs, | ||
120 | .num_irqs = ARRAY_SIZE(tps80031_main_irqs), | ||
121 | .num_regs = 3, | ||
122 | .status_base = TPS80031_INT_STS_A, | ||
123 | .mask_base = TPS80031_INT_MSK_LINE_A, | ||
124 | }; | ||
125 | |||
126 | #define PUPD_DATA(_reg, _pulldown_bit, _pullup_bit) \ | ||
127 | { \ | ||
128 | .reg = TPS80031_CFG_INPUT_PUPD##_reg, \ | ||
129 | .pulldown_bit = _pulldown_bit, \ | ||
130 | .pullup_bit = _pullup_bit, \ | ||
131 | } | ||
132 | |||
133 | static const struct tps80031_pupd_data tps80031_pupds[] = { | ||
134 | [TPS80031_PREQ1] = PUPD_DATA(1, BIT(0), BIT(1)), | ||
135 | [TPS80031_PREQ2A] = PUPD_DATA(1, BIT(2), BIT(3)), | ||
136 | [TPS80031_PREQ2B] = PUPD_DATA(1, BIT(4), BIT(5)), | ||
137 | [TPS80031_PREQ2C] = PUPD_DATA(1, BIT(6), BIT(7)), | ||
138 | [TPS80031_PREQ3] = PUPD_DATA(2, BIT(0), BIT(1)), | ||
139 | [TPS80031_NRES_WARM] = PUPD_DATA(2, 0, BIT(2)), | ||
140 | [TPS80031_PWM_FORCE] = PUPD_DATA(2, BIT(5), 0), | ||
141 | [TPS80031_CHRG_EXT_CHRG_STATZ] = PUPD_DATA(2, 0, BIT(6)), | ||
142 | [TPS80031_SIM] = PUPD_DATA(3, BIT(0), BIT(1)), | ||
143 | [TPS80031_MMC] = PUPD_DATA(3, BIT(2), BIT(3)), | ||
144 | [TPS80031_GPADC_START] = PUPD_DATA(3, BIT(4), 0), | ||
145 | [TPS80031_DVSI2C_SCL] = PUPD_DATA(4, 0, BIT(0)), | ||
146 | [TPS80031_DVSI2C_SDA] = PUPD_DATA(4, 0, BIT(1)), | ||
147 | [TPS80031_CTLI2C_SCL] = PUPD_DATA(4, 0, BIT(2)), | ||
148 | [TPS80031_CTLI2C_SDA] = PUPD_DATA(4, 0, BIT(3)), | ||
149 | }; | ||
150 | static struct tps80031 *tps80031_power_off_dev; | ||
151 | |||
152 | int tps80031_ext_power_req_config(struct device *dev, | ||
153 | unsigned long ext_ctrl_flag, int preq_bit, | ||
154 | int state_reg_add, int trans_reg_add) | ||
155 | { | ||
156 | u8 res_ass_reg = 0; | ||
157 | int preq_mask_bit = 0; | ||
158 | int ret; | ||
159 | |||
160 | if (!(ext_ctrl_flag & TPS80031_EXT_PWR_REQ)) | ||
161 | return 0; | ||
162 | |||
163 | if (ext_ctrl_flag & TPS80031_PWR_REQ_INPUT_PREQ1) { | ||
164 | res_ass_reg = TPS80031_PREQ1_RES_ASS_A + (preq_bit >> 3); | ||
165 | preq_mask_bit = 5; | ||
166 | } else if (ext_ctrl_flag & TPS80031_PWR_REQ_INPUT_PREQ2) { | ||
167 | res_ass_reg = TPS80031_PREQ2_RES_ASS_A + (preq_bit >> 3); | ||
168 | preq_mask_bit = 6; | ||
169 | } else if (ext_ctrl_flag & TPS80031_PWR_REQ_INPUT_PREQ3) { | ||
170 | res_ass_reg = TPS80031_PREQ3_RES_ASS_A + (preq_bit >> 3); | ||
171 | preq_mask_bit = 7; | ||
172 | } | ||
173 | |||
174 | /* Configure REQ_ASS registers */ | ||
175 | ret = tps80031_set_bits(dev, TPS80031_SLAVE_ID1, res_ass_reg, | ||
176 | BIT(preq_bit & 0x7)); | ||
177 | if (ret < 0) { | ||
178 | dev_err(dev, "reg 0x%02x setbit failed, err = %d\n", | ||
179 | res_ass_reg, ret); | ||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | /* Unmask the PREQ */ | ||
184 | ret = tps80031_clr_bits(dev, TPS80031_SLAVE_ID1, | ||
185 | TPS80031_PHOENIX_MSK_TRANSITION, BIT(preq_mask_bit)); | ||
186 | if (ret < 0) { | ||
187 | dev_err(dev, "reg 0x%02x clrbit failed, err = %d\n", | ||
188 | TPS80031_PHOENIX_MSK_TRANSITION, ret); | ||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | /* Switch regulator control to resource now */ | ||
193 | if (ext_ctrl_flag & (TPS80031_PWR_REQ_INPUT_PREQ2 | | ||
194 | TPS80031_PWR_REQ_INPUT_PREQ3)) { | ||
195 | ret = tps80031_update(dev, TPS80031_SLAVE_ID1, state_reg_add, | ||
196 | 0x0, TPS80031_STATE_MASK); | ||
197 | if (ret < 0) | ||
198 | dev_err(dev, "reg 0x%02x update failed, err = %d\n", | ||
199 | state_reg_add, ret); | ||
200 | } else { | ||
201 | ret = tps80031_update(dev, TPS80031_SLAVE_ID1, trans_reg_add, | ||
202 | TPS80031_TRANS_SLEEP_OFF, | ||
203 | TPS80031_TRANS_SLEEP_MASK); | ||
204 | if (ret < 0) | ||
205 | dev_err(dev, "reg 0x%02x update failed, err = %d\n", | ||
206 | trans_reg_add, ret); | ||
207 | } | ||
208 | return ret; | ||
209 | } | ||
210 | EXPORT_SYMBOL_GPL(tps80031_ext_power_req_config); | ||
211 | |||
212 | static void tps80031_power_off(void) | ||
213 | { | ||
214 | dev_info(tps80031_power_off_dev->dev, "switching off PMU\n"); | ||
215 | tps80031_write(tps80031_power_off_dev->dev, TPS80031_SLAVE_ID1, | ||
216 | TPS80031_PHOENIX_DEV_ON, TPS80031_DEVOFF); | ||
217 | } | ||
218 | |||
219 | static void tps80031_pupd_init(struct tps80031 *tps80031, | ||
220 | struct tps80031_platform_data *pdata) | ||
221 | { | ||
222 | struct tps80031_pupd_init_data *pupd_init_data = pdata->pupd_init_data; | ||
223 | int data_size = pdata->pupd_init_data_size; | ||
224 | int i; | ||
225 | |||
226 | for (i = 0; i < data_size; ++i) { | ||
227 | struct tps80031_pupd_init_data *pupd_init = &pupd_init_data[i]; | ||
228 | const struct tps80031_pupd_data *pupd = | ||
229 | &tps80031_pupds[pupd_init->input_pin]; | ||
230 | u8 update_value = 0; | ||
231 | u8 update_mask = pupd->pulldown_bit | pupd->pullup_bit; | ||
232 | |||
233 | if (pupd_init->setting == TPS80031_PUPD_PULLDOWN) | ||
234 | update_value = pupd->pulldown_bit; | ||
235 | else if (pupd_init->setting == TPS80031_PUPD_PULLUP) | ||
236 | update_value = pupd->pullup_bit; | ||
237 | |||
238 | tps80031_update(tps80031->dev, TPS80031_SLAVE_ID1, pupd->reg, | ||
239 | update_value, update_mask); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | static int tps80031_init_ext_control(struct tps80031 *tps80031, | ||
244 | struct tps80031_platform_data *pdata) | ||
245 | { | ||
246 | struct device *dev = tps80031->dev; | ||
247 | int ret; | ||
248 | int i; | ||
249 | |||
250 | /* Clear all external control for this rail */ | ||
251 | for (i = 0; i < 9; ++i) { | ||
252 | ret = tps80031_write(dev, TPS80031_SLAVE_ID1, | ||
253 | TPS80031_PREQ1_RES_ASS_A + i, 0); | ||
254 | if (ret < 0) { | ||
255 | dev_err(dev, "reg 0x%02x write failed, err = %d\n", | ||
256 | TPS80031_PREQ1_RES_ASS_A + i, ret); | ||
257 | return ret; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | /* Mask the PREQ */ | ||
262 | ret = tps80031_set_bits(dev, TPS80031_SLAVE_ID1, | ||
263 | TPS80031_PHOENIX_MSK_TRANSITION, 0x7 << 5); | ||
264 | if (ret < 0) { | ||
265 | dev_err(dev, "reg 0x%02x set_bits failed, err = %d\n", | ||
266 | TPS80031_PHOENIX_MSK_TRANSITION, ret); | ||
267 | return ret; | ||
268 | } | ||
269 | return ret; | ||
270 | } | ||
271 | |||
272 | static int __devinit tps80031_irq_init(struct tps80031 *tps80031, int irq, | ||
273 | int irq_base) | ||
274 | { | ||
275 | struct device *dev = tps80031->dev; | ||
276 | int i, ret; | ||
277 | |||
278 | /* | ||
279 | * The MASK register used for updating status register when | ||
280 | * interrupt occurs and LINE register used to pass the status | ||
281 | * to actual interrupt line. As per datasheet: | ||
282 | * When INT_MSK_LINE [i] is set to 1, the associated interrupt | ||
283 | * number i is INT line masked, which means that no interrupt is | ||
284 | * generated on the INT line. | ||
285 | * When INT_MSK_LINE [i] is set to 0, the associated interrupt | ||
286 | * number i is line enabled: An interrupt is generated on the | ||
287 | * INT line. | ||
288 | * In any case, the INT_STS [i] status bit may or may not be updated, | ||
289 | * only linked to the INT_MSK_STS [i] configuration register bit. | ||
290 | * | ||
291 | * When INT_MSK_STS [i] is set to 1, the associated interrupt number | ||
292 | * i is status masked, which means that no interrupt is stored in | ||
293 | * the INT_STS[i] status bit. Note that no interrupt number i is | ||
294 | * generated on the INT line, even if the INT_MSK_LINE [i] register | ||
295 | * bit is set to 0. | ||
296 | * When INT_MSK_STS [i] is set to 0, the associated interrupt number i | ||
297 | * is status enabled: An interrupt status is updated in the INT_STS [i] | ||
298 | * register. The interrupt may or may not be generated on the INT line, | ||
299 | * depending on the INT_MSK_LINE [i] configuration register bit. | ||
300 | */ | ||
301 | for (i = 0; i < 3; i++) | ||
302 | tps80031_write(dev, TPS80031_SLAVE_ID2, | ||
303 | TPS80031_INT_MSK_STS_A + i, 0x00); | ||
304 | |||
305 | ret = regmap_add_irq_chip(tps80031->regmap[TPS80031_SLAVE_ID2], irq, | ||
306 | IRQF_ONESHOT, irq_base, | ||
307 | &tps80031_irq_chip, &tps80031->irq_data); | ||
308 | if (ret < 0) { | ||
309 | dev_err(dev, "add irq failed, err = %d\n", ret); | ||
310 | return ret; | ||
311 | } | ||
312 | return ret; | ||
313 | } | ||
314 | |||
315 | static bool rd_wr_reg_id0(struct device *dev, unsigned int reg) | ||
316 | { | ||
317 | switch (reg) { | ||
318 | case TPS80031_SMPS1_CFG_FORCE ... TPS80031_SMPS2_CFG_VOLTAGE: | ||
319 | return true; | ||
320 | default: | ||
321 | return false; | ||
322 | } | ||
323 | } | ||
324 | |||
325 | static bool rd_wr_reg_id1(struct device *dev, unsigned int reg) | ||
326 | { | ||
327 | switch (reg) { | ||
328 | case TPS80031_SECONDS_REG ... TPS80031_RTC_RESET_STATUS_REG: | ||
329 | case TPS80031_VALIDITY0 ... TPS80031_VALIDITY7: | ||
330 | case TPS80031_PHOENIX_START_CONDITION ... TPS80031_KEY_PRESS_DUR_CFG: | ||
331 | case TPS80031_SMPS4_CFG_TRANS ... TPS80031_SMPS3_CFG_VOLTAGE: | ||
332 | case TPS80031_BROADCAST_ADDR_ALL ... TPS80031_BROADCAST_ADDR_CLK_RST: | ||
333 | case TPS80031_VANA_CFG_TRANS ... TPS80031_LDO7_CFG_VOLTAGE: | ||
334 | case TPS80031_REGEN1_CFG_TRANS ... TPS80031_TMP_CFG_STATE: | ||
335 | case TPS80031_PREQ1_RES_ASS_A ... TPS80031_PREQ3_RES_ASS_C: | ||
336 | case TPS80031_SMPS_OFFSET ... TPS80031_BATDEBOUNCING: | ||
337 | case TPS80031_CFG_INPUT_PUPD1 ... TPS80031_CFG_SMPS_PD: | ||
338 | case TPS80031_BACKUP_REG: | ||
339 | return true; | ||
340 | default: | ||
341 | return false; | ||
342 | } | ||
343 | } | ||
344 | |||
345 | static bool is_volatile_reg_id1(struct device *dev, unsigned int reg) | ||
346 | { | ||
347 | switch (reg) { | ||
348 | case TPS80031_SMPS4_CFG_TRANS ... TPS80031_SMPS3_CFG_VOLTAGE: | ||
349 | case TPS80031_VANA_CFG_TRANS ... TPS80031_LDO7_CFG_VOLTAGE: | ||
350 | case TPS80031_REGEN1_CFG_TRANS ... TPS80031_TMP_CFG_STATE: | ||
351 | case TPS80031_PREQ1_RES_ASS_A ... TPS80031_PREQ3_RES_ASS_C: | ||
352 | case TPS80031_SMPS_OFFSET ... TPS80031_BATDEBOUNCING: | ||
353 | case TPS80031_CFG_INPUT_PUPD1 ... TPS80031_CFG_SMPS_PD: | ||
354 | return true; | ||
355 | default: | ||
356 | return false; | ||
357 | } | ||
358 | } | ||
359 | |||
360 | static bool rd_wr_reg_id2(struct device *dev, unsigned int reg) | ||
361 | { | ||
362 | switch (reg) { | ||
363 | case TPS80031_USB_VENDOR_ID_LSB ... TPS80031_USB_OTG_REVISION: | ||
364 | case TPS80031_GPADC_CTRL ... TPS80031_CTRL_P1: | ||
365 | case TPS80031_RTCH0_LSB ... TPS80031_GPCH0_MSB: | ||
366 | case TPS80031_TOGGLE1 ... TPS80031_VIBMODE: | ||
367 | case TPS80031_PWM1ON ... TPS80031_PWM2OFF: | ||
368 | case TPS80031_FG_REG_00 ... TPS80031_FG_REG_11: | ||
369 | case TPS80031_INT_STS_A ... TPS80031_INT_MSK_STS_C: | ||
370 | case TPS80031_CONTROLLER_CTRL2 ... TPS80031_LED_PWM_CTRL2: | ||
371 | return true; | ||
372 | default: | ||
373 | return false; | ||
374 | } | ||
375 | } | ||
376 | |||
377 | static bool rd_wr_reg_id3(struct device *dev, unsigned int reg) | ||
378 | { | ||
379 | switch (reg) { | ||
380 | case TPS80031_GPADC_TRIM0 ... TPS80031_GPADC_TRIM18: | ||
381 | return true; | ||
382 | default: | ||
383 | return false; | ||
384 | } | ||
385 | } | ||
386 | |||
387 | static const struct regmap_config tps80031_regmap_configs[] = { | ||
388 | { | ||
389 | .reg_bits = 8, | ||
390 | .val_bits = 8, | ||
391 | .writeable_reg = rd_wr_reg_id0, | ||
392 | .readable_reg = rd_wr_reg_id0, | ||
393 | .max_register = TPS80031_MAX_REGISTER, | ||
394 | }, | ||
395 | { | ||
396 | .reg_bits = 8, | ||
397 | .val_bits = 8, | ||
398 | .writeable_reg = rd_wr_reg_id1, | ||
399 | .readable_reg = rd_wr_reg_id1, | ||
400 | .volatile_reg = is_volatile_reg_id1, | ||
401 | .max_register = TPS80031_MAX_REGISTER, | ||
402 | }, | ||
403 | { | ||
404 | .reg_bits = 8, | ||
405 | .val_bits = 8, | ||
406 | .writeable_reg = rd_wr_reg_id2, | ||
407 | .readable_reg = rd_wr_reg_id2, | ||
408 | .max_register = TPS80031_MAX_REGISTER, | ||
409 | }, | ||
410 | { | ||
411 | .reg_bits = 8, | ||
412 | .val_bits = 8, | ||
413 | .writeable_reg = rd_wr_reg_id3, | ||
414 | .readable_reg = rd_wr_reg_id3, | ||
415 | .max_register = TPS80031_MAX_REGISTER, | ||
416 | }, | ||
417 | }; | ||
418 | |||
419 | static int __devinit tps80031_probe(struct i2c_client *client, | ||
420 | const struct i2c_device_id *id) | ||
421 | { | ||
422 | struct tps80031_platform_data *pdata = client->dev.platform_data; | ||
423 | struct tps80031 *tps80031; | ||
424 | int ret; | ||
425 | uint8_t es_version; | ||
426 | uint8_t ep_ver; | ||
427 | int i; | ||
428 | |||
429 | if (!pdata) { | ||
430 | dev_err(&client->dev, "tps80031 requires platform data\n"); | ||
431 | return -EINVAL; | ||
432 | } | ||
433 | |||
434 | tps80031 = devm_kzalloc(&client->dev, sizeof(*tps80031), GFP_KERNEL); | ||
435 | if (!tps80031) { | ||
436 | dev_err(&client->dev, "Malloc failed for tps80031\n"); | ||
437 | return -ENOMEM; | ||
438 | } | ||
439 | |||
440 | for (i = 0; i < TPS80031_NUM_SLAVES; i++) { | ||
441 | if (tps80031_slave_address[i] == client->addr) | ||
442 | tps80031->clients[i] = client; | ||
443 | else | ||
444 | tps80031->clients[i] = i2c_new_dummy(client->adapter, | ||
445 | tps80031_slave_address[i]); | ||
446 | if (!tps80031->clients[i]) { | ||
447 | dev_err(&client->dev, "can't attach client %d\n", i); | ||
448 | ret = -ENOMEM; | ||
449 | goto fail_client_reg; | ||
450 | } | ||
451 | |||
452 | i2c_set_clientdata(tps80031->clients[i], tps80031); | ||
453 | tps80031->regmap[i] = devm_regmap_init_i2c(tps80031->clients[i], | ||
454 | &tps80031_regmap_configs[i]); | ||
455 | if (IS_ERR(tps80031->regmap[i])) { | ||
456 | ret = PTR_ERR(tps80031->regmap[i]); | ||
457 | dev_err(&client->dev, | ||
458 | "regmap %d init failed, err %d\n", i, ret); | ||
459 | goto fail_client_reg; | ||
460 | } | ||
461 | } | ||
462 | |||
463 | ret = tps80031_read(&client->dev, TPS80031_SLAVE_ID3, | ||
464 | TPS80031_JTAGVERNUM, &es_version); | ||
465 | if (ret < 0) { | ||
466 | dev_err(&client->dev, | ||
467 | "Silicon version number read failed: %d\n", ret); | ||
468 | goto fail_client_reg; | ||
469 | } | ||
470 | |||
471 | ret = tps80031_read(&client->dev, TPS80031_SLAVE_ID3, | ||
472 | TPS80031_EPROM_REV, &ep_ver); | ||
473 | if (ret < 0) { | ||
474 | dev_err(&client->dev, | ||
475 | "Silicon eeprom version read failed: %d\n", ret); | ||
476 | goto fail_client_reg; | ||
477 | } | ||
478 | |||
479 | dev_info(&client->dev, "ES version 0x%02x and EPROM version 0x%02x\n", | ||
480 | es_version, ep_ver); | ||
481 | tps80031->es_version = es_version; | ||
482 | tps80031->dev = &client->dev; | ||
483 | i2c_set_clientdata(client, tps80031); | ||
484 | tps80031->chip_info = id->driver_data; | ||
485 | |||
486 | ret = tps80031_irq_init(tps80031, client->irq, pdata->irq_base); | ||
487 | if (ret) { | ||
488 | dev_err(&client->dev, "IRQ init failed: %d\n", ret); | ||
489 | goto fail_client_reg; | ||
490 | } | ||
491 | |||
492 | tps80031_pupd_init(tps80031, pdata); | ||
493 | |||
494 | tps80031_init_ext_control(tps80031, pdata); | ||
495 | |||
496 | ret = mfd_add_devices(tps80031->dev, -1, | ||
497 | tps80031_cell, ARRAY_SIZE(tps80031_cell), | ||
498 | NULL, 0, | ||
499 | regmap_irq_get_domain(tps80031->irq_data)); | ||
500 | if (ret < 0) { | ||
501 | dev_err(&client->dev, "mfd_add_devices failed: %d\n", ret); | ||
502 | goto fail_mfd_add; | ||
503 | } | ||
504 | |||
505 | if (pdata->use_power_off && !pm_power_off) { | ||
506 | tps80031_power_off_dev = tps80031; | ||
507 | pm_power_off = tps80031_power_off; | ||
508 | } | ||
509 | return 0; | ||
510 | |||
511 | fail_mfd_add: | ||
512 | regmap_del_irq_chip(client->irq, tps80031->irq_data); | ||
513 | |||
514 | fail_client_reg: | ||
515 | for (i = 0; i < TPS80031_NUM_SLAVES; i++) { | ||
516 | if (tps80031->clients[i] && (tps80031->clients[i] != client)) | ||
517 | i2c_unregister_device(tps80031->clients[i]); | ||
518 | } | ||
519 | return ret; | ||
520 | } | ||
521 | |||
522 | static int __devexit tps80031_remove(struct i2c_client *client) | ||
523 | { | ||
524 | struct tps80031 *tps80031 = i2c_get_clientdata(client); | ||
525 | int i; | ||
526 | |||
527 | if (tps80031_power_off_dev == tps80031) { | ||
528 | tps80031_power_off_dev = NULL; | ||
529 | pm_power_off = NULL; | ||
530 | } | ||
531 | |||
532 | mfd_remove_devices(tps80031->dev); | ||
533 | |||
534 | regmap_del_irq_chip(client->irq, tps80031->irq_data); | ||
535 | |||
536 | for (i = 0; i < TPS80031_NUM_SLAVES; i++) { | ||
537 | if (tps80031->clients[i] != client) | ||
538 | i2c_unregister_device(tps80031->clients[i]); | ||
539 | } | ||
540 | return 0; | ||
541 | } | ||
542 | |||
543 | static const struct i2c_device_id tps80031_id_table[] = { | ||
544 | { "tps80031", TPS80031 }, | ||
545 | { "tps80032", TPS80032 }, | ||
546 | { } | ||
547 | }; | ||
548 | MODULE_DEVICE_TABLE(i2c, tps80031_id_table); | ||
549 | |||
550 | static struct i2c_driver tps80031_driver = { | ||
551 | .driver = { | ||
552 | .name = "tps80031", | ||
553 | .owner = THIS_MODULE, | ||
554 | }, | ||
555 | .probe = tps80031_probe, | ||
556 | .remove = __devexit_p(tps80031_remove), | ||
557 | .id_table = tps80031_id_table, | ||
558 | }; | ||
559 | |||
560 | static int __init tps80031_init(void) | ||
561 | { | ||
562 | return i2c_add_driver(&tps80031_driver); | ||
563 | } | ||
564 | subsys_initcall(tps80031_init); | ||
565 | |||
566 | static void __exit tps80031_exit(void) | ||
567 | { | ||
568 | i2c_del_driver(&tps80031_driver); | ||
569 | } | ||
570 | module_exit(tps80031_exit); | ||
571 | |||
572 | MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); | ||
573 | MODULE_DESCRIPTION("TPS80031 core driver"); | ||
574 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 11b76c0109f..4f3baadd003 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/mutex.h> | 32 | #include <linux/mutex.h> |
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #include <linux/platform_device.h> | 34 | #include <linux/platform_device.h> |
35 | #include <linux/regmap.h> | ||
35 | #include <linux/clk.h> | 36 | #include <linux/clk.h> |
36 | #include <linux/err.h> | 37 | #include <linux/err.h> |
37 | #include <linux/device.h> | 38 | #include <linux/device.h> |
@@ -65,9 +66,6 @@ | |||
65 | 66 | ||
66 | /* Triton Core internal information (BEGIN) */ | 67 | /* Triton Core internal information (BEGIN) */ |
67 | 68 | ||
68 | /* Last - for index max*/ | ||
69 | #define TWL4030_MODULE_LAST TWL4030_MODULE_SECURED_REG | ||
70 | |||
71 | #define TWL_NUM_SLAVES 4 | 69 | #define TWL_NUM_SLAVES 4 |
72 | 70 | ||
73 | #define SUB_CHIP_ID0 0 | 71 | #define SUB_CHIP_ID0 0 |
@@ -171,13 +169,7 @@ EXPORT_SYMBOL(twl_rev); | |||
171 | /* Structure for each TWL4030/TWL6030 Slave */ | 169 | /* Structure for each TWL4030/TWL6030 Slave */ |
172 | struct twl_client { | 170 | struct twl_client { |
173 | struct i2c_client *client; | 171 | struct i2c_client *client; |
174 | u8 address; | 172 | struct regmap *regmap; |
175 | |||
176 | /* max numb of i2c_msg required is for read =2 */ | ||
177 | struct i2c_msg xfer_msg[2]; | ||
178 | |||
179 | /* To lock access to xfer_msg */ | ||
180 | struct mutex xfer_lock; | ||
181 | }; | 173 | }; |
182 | 174 | ||
183 | static struct twl_client twl_modules[TWL_NUM_SLAVES]; | 175 | static struct twl_client twl_modules[TWL_NUM_SLAVES]; |
@@ -189,7 +181,7 @@ struct twl_mapping { | |||
189 | }; | 181 | }; |
190 | static struct twl_mapping *twl_map; | 182 | static struct twl_mapping *twl_map; |
191 | 183 | ||
192 | static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { | 184 | static struct twl_mapping twl4030_map[] = { |
193 | /* | 185 | /* |
194 | * NOTE: don't change this table without updating the | 186 | * NOTE: don't change this table without updating the |
195 | * <linux/i2c/twl.h> defines for TWL4030_MODULE_* | 187 | * <linux/i2c/twl.h> defines for TWL4030_MODULE_* |
@@ -197,34 +189,62 @@ static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { | |||
197 | */ | 189 | */ |
198 | 190 | ||
199 | { 0, TWL4030_BASEADD_USB }, | 191 | { 0, TWL4030_BASEADD_USB }, |
200 | |||
201 | { 1, TWL4030_BASEADD_AUDIO_VOICE }, | 192 | { 1, TWL4030_BASEADD_AUDIO_VOICE }, |
202 | { 1, TWL4030_BASEADD_GPIO }, | 193 | { 1, TWL4030_BASEADD_GPIO }, |
203 | { 1, TWL4030_BASEADD_INTBR }, | 194 | { 1, TWL4030_BASEADD_INTBR }, |
204 | { 1, TWL4030_BASEADD_PIH }, | 195 | { 1, TWL4030_BASEADD_PIH }, |
205 | { 1, TWL4030_BASEADD_TEST }, | ||
206 | 196 | ||
197 | { 1, TWL4030_BASEADD_TEST }, | ||
207 | { 2, TWL4030_BASEADD_KEYPAD }, | 198 | { 2, TWL4030_BASEADD_KEYPAD }, |
208 | { 2, TWL4030_BASEADD_MADC }, | 199 | { 2, TWL4030_BASEADD_MADC }, |
209 | { 2, TWL4030_BASEADD_INTERRUPTS }, | 200 | { 2, TWL4030_BASEADD_INTERRUPTS }, |
210 | { 2, TWL4030_BASEADD_LED }, | 201 | { 2, TWL4030_BASEADD_LED }, |
202 | |||
211 | { 2, TWL4030_BASEADD_MAIN_CHARGE }, | 203 | { 2, TWL4030_BASEADD_MAIN_CHARGE }, |
212 | { 2, TWL4030_BASEADD_PRECHARGE }, | 204 | { 2, TWL4030_BASEADD_PRECHARGE }, |
213 | { 2, TWL4030_BASEADD_PWM0 }, | 205 | { 2, TWL4030_BASEADD_PWM0 }, |
214 | { 2, TWL4030_BASEADD_PWM1 }, | 206 | { 2, TWL4030_BASEADD_PWM1 }, |
215 | { 2, TWL4030_BASEADD_PWMA }, | 207 | { 2, TWL4030_BASEADD_PWMA }, |
208 | |||
216 | { 2, TWL4030_BASEADD_PWMB }, | 209 | { 2, TWL4030_BASEADD_PWMB }, |
217 | { 2, TWL5031_BASEADD_ACCESSORY }, | 210 | { 2, TWL5031_BASEADD_ACCESSORY }, |
218 | { 2, TWL5031_BASEADD_INTERRUPTS }, | 211 | { 2, TWL5031_BASEADD_INTERRUPTS }, |
219 | |||
220 | { 3, TWL4030_BASEADD_BACKUP }, | 212 | { 3, TWL4030_BASEADD_BACKUP }, |
221 | { 3, TWL4030_BASEADD_INT }, | 213 | { 3, TWL4030_BASEADD_INT }, |
214 | |||
222 | { 3, TWL4030_BASEADD_PM_MASTER }, | 215 | { 3, TWL4030_BASEADD_PM_MASTER }, |
223 | { 3, TWL4030_BASEADD_PM_RECEIVER }, | 216 | { 3, TWL4030_BASEADD_PM_RECEIVER }, |
224 | { 3, TWL4030_BASEADD_RTC }, | 217 | { 3, TWL4030_BASEADD_RTC }, |
225 | { 3, TWL4030_BASEADD_SECURED_REG }, | 218 | { 3, TWL4030_BASEADD_SECURED_REG }, |
226 | }; | 219 | }; |
227 | 220 | ||
221 | static struct regmap_config twl4030_regmap_config[4] = { | ||
222 | { | ||
223 | /* Address 0x48 */ | ||
224 | .reg_bits = 8, | ||
225 | .val_bits = 8, | ||
226 | .max_register = 0xff, | ||
227 | }, | ||
228 | { | ||
229 | /* Address 0x49 */ | ||
230 | .reg_bits = 8, | ||
231 | .val_bits = 8, | ||
232 | .max_register = 0xff, | ||
233 | }, | ||
234 | { | ||
235 | /* Address 0x4a */ | ||
236 | .reg_bits = 8, | ||
237 | .val_bits = 8, | ||
238 | .max_register = 0xff, | ||
239 | }, | ||
240 | { | ||
241 | /* Address 0x4b */ | ||
242 | .reg_bits = 8, | ||
243 | .val_bits = 8, | ||
244 | .max_register = 0xff, | ||
245 | }, | ||
246 | }; | ||
247 | |||
228 | static struct twl_mapping twl6030_map[] = { | 248 | static struct twl_mapping twl6030_map[] = { |
229 | /* | 249 | /* |
230 | * NOTE: don't change this table without updating the | 250 | * NOTE: don't change this table without updating the |
@@ -254,14 +274,35 @@ static struct twl_mapping twl6030_map[] = { | |||
254 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | 274 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, |
255 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | 275 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, |
256 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | 276 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, |
277 | |||
257 | { SUB_CHIP_ID0, TWL6030_BASEADD_PM_MASTER }, | 278 | { SUB_CHIP_ID0, TWL6030_BASEADD_PM_MASTER }, |
258 | { SUB_CHIP_ID0, TWL6030_BASEADD_PM_SLAVE_MISC }, | 279 | { SUB_CHIP_ID0, TWL6030_BASEADD_PM_SLAVE_MISC }, |
259 | |||
260 | { SUB_CHIP_ID0, TWL6030_BASEADD_RTC }, | 280 | { SUB_CHIP_ID0, TWL6030_BASEADD_RTC }, |
261 | { SUB_CHIP_ID0, TWL6030_BASEADD_MEM }, | 281 | { SUB_CHIP_ID0, TWL6030_BASEADD_MEM }, |
262 | { SUB_CHIP_ID1, TWL6025_BASEADD_CHARGER }, | 282 | { SUB_CHIP_ID1, TWL6025_BASEADD_CHARGER }, |
263 | }; | 283 | }; |
264 | 284 | ||
285 | static struct regmap_config twl6030_regmap_config[3] = { | ||
286 | { | ||
287 | /* Address 0x48 */ | ||
288 | .reg_bits = 8, | ||
289 | .val_bits = 8, | ||
290 | .max_register = 0xff, | ||
291 | }, | ||
292 | { | ||
293 | /* Address 0x49 */ | ||
294 | .reg_bits = 8, | ||
295 | .val_bits = 8, | ||
296 | .max_register = 0xff, | ||
297 | }, | ||
298 | { | ||
299 | /* Address 0x4a */ | ||
300 | .reg_bits = 8, | ||
301 | .val_bits = 8, | ||
302 | .max_register = 0xff, | ||
303 | }, | ||
304 | }; | ||
305 | |||
265 | /*----------------------------------------------------------------------*/ | 306 | /*----------------------------------------------------------------------*/ |
266 | 307 | ||
267 | /* Exported Functions */ | 308 | /* Exported Functions */ |
@@ -283,9 +324,8 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | |||
283 | int ret; | 324 | int ret; |
284 | int sid; | 325 | int sid; |
285 | struct twl_client *twl; | 326 | struct twl_client *twl; |
286 | struct i2c_msg *msg; | ||
287 | 327 | ||
288 | if (unlikely(mod_no > TWL_MODULE_LAST)) { | 328 | if (unlikely(mod_no >= TWL_MODULE_LAST)) { |
289 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); | 329 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); |
290 | return -EPERM; | 330 | return -EPERM; |
291 | } | 331 | } |
@@ -301,32 +341,14 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | |||
301 | } | 341 | } |
302 | twl = &twl_modules[sid]; | 342 | twl = &twl_modules[sid]; |
303 | 343 | ||
304 | mutex_lock(&twl->xfer_lock); | 344 | ret = regmap_bulk_write(twl->regmap, twl_map[mod_no].base + reg, |
305 | /* | 345 | value, num_bytes); |
306 | * [MSG1]: fill the register address data | 346 | |
307 | * fill the data Tx buffer | 347 | if (ret) |
308 | */ | 348 | pr_err("%s: Write failed (mod %d, reg 0x%02x count %d)\n", |
309 | msg = &twl->xfer_msg[0]; | 349 | DRIVER_NAME, mod_no, reg, num_bytes); |
310 | msg->addr = twl->address; | 350 | |
311 | msg->len = num_bytes + 1; | 351 | return ret; |
312 | msg->flags = 0; | ||
313 | msg->buf = value; | ||
314 | /* over write the first byte of buffer with the register address */ | ||
315 | *value = twl_map[mod_no].base + reg; | ||
316 | ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 1); | ||
317 | mutex_unlock(&twl->xfer_lock); | ||
318 | |||
319 | /* i2c_transfer returns number of messages transferred */ | ||
320 | if (ret != 1) { | ||
321 | pr_err("%s: i2c_write failed to transfer all messages\n", | ||
322 | DRIVER_NAME); | ||
323 | if (ret < 0) | ||
324 | return ret; | ||
325 | else | ||
326 | return -EIO; | ||
327 | } else { | ||
328 | return 0; | ||
329 | } | ||
330 | } | 352 | } |
331 | EXPORT_SYMBOL(twl_i2c_write); | 353 | EXPORT_SYMBOL(twl_i2c_write); |
332 | 354 | ||
@@ -342,12 +364,10 @@ EXPORT_SYMBOL(twl_i2c_write); | |||
342 | int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | 364 | int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) |
343 | { | 365 | { |
344 | int ret; | 366 | int ret; |
345 | u8 val; | ||
346 | int sid; | 367 | int sid; |
347 | struct twl_client *twl; | 368 | struct twl_client *twl; |
348 | struct i2c_msg *msg; | ||
349 | 369 | ||
350 | if (unlikely(mod_no > TWL_MODULE_LAST)) { | 370 | if (unlikely(mod_no >= TWL_MODULE_LAST)) { |
351 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); | 371 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); |
352 | return -EPERM; | 372 | return -EPERM; |
353 | } | 373 | } |
@@ -363,34 +383,14 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | |||
363 | } | 383 | } |
364 | twl = &twl_modules[sid]; | 384 | twl = &twl_modules[sid]; |
365 | 385 | ||
366 | mutex_lock(&twl->xfer_lock); | 386 | ret = regmap_bulk_read(twl->regmap, twl_map[mod_no].base + reg, |
367 | /* [MSG1] fill the register address data */ | 387 | value, num_bytes); |
368 | msg = &twl->xfer_msg[0]; | 388 | |
369 | msg->addr = twl->address; | 389 | if (ret) |
370 | msg->len = 1; | 390 | pr_err("%s: Read failed (mod %d, reg 0x%02x count %d)\n", |
371 | msg->flags = 0; /* Read the register value */ | 391 | DRIVER_NAME, mod_no, reg, num_bytes); |
372 | val = twl_map[mod_no].base + reg; | 392 | |
373 | msg->buf = &val; | 393 | return ret; |
374 | /* [MSG2] fill the data rx buffer */ | ||
375 | msg = &twl->xfer_msg[1]; | ||
376 | msg->addr = twl->address; | ||
377 | msg->flags = I2C_M_RD; /* Read the register value */ | ||
378 | msg->len = num_bytes; /* only n bytes */ | ||
379 | msg->buf = value; | ||
380 | ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 2); | ||
381 | mutex_unlock(&twl->xfer_lock); | ||
382 | |||
383 | /* i2c_transfer returns number of messages transferred */ | ||
384 | if (ret != 2) { | ||
385 | pr_err("%s: i2c_read failed to transfer all messages\n", | ||
386 | DRIVER_NAME); | ||
387 | if (ret < 0) | ||
388 | return ret; | ||
389 | else | ||
390 | return -EIO; | ||
391 | } else { | ||
392 | return 0; | ||
393 | } | ||
394 | } | 394 | } |
395 | EXPORT_SYMBOL(twl_i2c_read); | 395 | EXPORT_SYMBOL(twl_i2c_read); |
396 | 396 | ||
@@ -404,12 +404,7 @@ EXPORT_SYMBOL(twl_i2c_read); | |||
404 | */ | 404 | */ |
405 | int twl_i2c_write_u8(u8 mod_no, u8 value, u8 reg) | 405 | int twl_i2c_write_u8(u8 mod_no, u8 value, u8 reg) |
406 | { | 406 | { |
407 | 407 | return twl_i2c_write(mod_no, &value, reg, 1); | |
408 | /* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */ | ||
409 | u8 temp_buffer[2] = { 0 }; | ||
410 | /* offset 1 contains the data */ | ||
411 | temp_buffer[1] = value; | ||
412 | return twl_i2c_write(mod_no, temp_buffer, reg, 1); | ||
413 | } | 408 | } |
414 | EXPORT_SYMBOL(twl_i2c_write_u8); | 409 | EXPORT_SYMBOL(twl_i2c_write_u8); |
415 | 410 | ||
@@ -646,8 +641,9 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
646 | return PTR_ERR(child); | 641 | return PTR_ERR(child); |
647 | } | 642 | } |
648 | 643 | ||
649 | if (IS_ENABLED(CONFIG_TWL4030_MADC) && pdata->madc) { | 644 | if (IS_ENABLED(CONFIG_TWL4030_MADC) && pdata->madc && |
650 | child = add_child(2, "twl4030_madc", | 645 | twl_class_is_4030()) { |
646 | child = add_child(SUB_CHIP_ID2, "twl4030_madc", | ||
651 | pdata->madc, sizeof(*pdata->madc), | 647 | pdata->madc, sizeof(*pdata->madc), |
652 | true, irq_base + MADC_INTR_OFFSET, 0); | 648 | true, irq_base + MADC_INTR_OFFSET, 0); |
653 | if (IS_ERR(child)) | 649 | if (IS_ERR(child)) |
@@ -663,15 +659,21 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
663 | * HW security concerns, and "least privilege". | 659 | * HW security concerns, and "least privilege". |
664 | */ | 660 | */ |
665 | sub_chip_id = twl_map[TWL_MODULE_RTC].sid; | 661 | sub_chip_id = twl_map[TWL_MODULE_RTC].sid; |
666 | child = add_child(sub_chip_id, "twl_rtc", | 662 | child = add_child(sub_chip_id, "twl_rtc", NULL, 0, |
667 | NULL, 0, | ||
668 | true, irq_base + RTC_INTR_OFFSET, 0); | 663 | true, irq_base + RTC_INTR_OFFSET, 0); |
669 | if (IS_ERR(child)) | 664 | if (IS_ERR(child)) |
670 | return PTR_ERR(child); | 665 | return PTR_ERR(child); |
671 | } | 666 | } |
672 | 667 | ||
673 | if (IS_ENABLED(CONFIG_PWM_TWL6030) && twl_class_is_6030()) { | 668 | if (IS_ENABLED(CONFIG_PWM_TWL)) { |
674 | child = add_child(SUB_CHIP_ID1, "twl6030-pwm", NULL, 0, | 669 | child = add_child(SUB_CHIP_ID1, "twl-pwm", NULL, 0, |
670 | false, 0, 0); | ||
671 | if (IS_ERR(child)) | ||
672 | return PTR_ERR(child); | ||
673 | } | ||
674 | |||
675 | if (IS_ENABLED(CONFIG_PWM_TWL_LED)) { | ||
676 | child = add_child(SUB_CHIP_ID1, "twl-pwmled", NULL, 0, | ||
675 | false, 0, 0); | 677 | false, 0, 0); |
676 | if (IS_ERR(child)) | 678 | if (IS_ERR(child)) |
677 | return PTR_ERR(child); | 679 | return PTR_ERR(child); |
@@ -723,9 +725,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
723 | 725 | ||
724 | } | 726 | } |
725 | 727 | ||
726 | child = add_child(0, "twl4030_usb", | 728 | child = add_child(SUB_CHIP_ID0, "twl4030_usb", |
727 | pdata->usb, sizeof(*pdata->usb), | 729 | pdata->usb, sizeof(*pdata->usb), true, |
728 | true, | ||
729 | /* irq0 = USB_PRES, irq1 = USB */ | 730 | /* irq0 = USB_PRES, irq1 = USB */ |
730 | irq_base + USB_PRES_INTR_OFFSET, | 731 | irq_base + USB_PRES_INTR_OFFSET, |
731 | irq_base + USB_INTR_OFFSET); | 732 | irq_base + USB_INTR_OFFSET); |
@@ -773,9 +774,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
773 | 774 | ||
774 | pdata->usb->features = features; | 775 | pdata->usb->features = features; |
775 | 776 | ||
776 | child = add_child(0, "twl6030_usb", | 777 | child = add_child(SUB_CHIP_ID0, "twl6030_usb", |
777 | pdata->usb, sizeof(*pdata->usb), | 778 | pdata->usb, sizeof(*pdata->usb), true, |
778 | true, | ||
779 | /* irq1 = VBUS_PRES, irq0 = USB ID */ | 779 | /* irq1 = VBUS_PRES, irq0 = USB ID */ |
780 | irq_base + USBOTG_INTR_OFFSET, | 780 | irq_base + USBOTG_INTR_OFFSET, |
781 | irq_base + USB_PRES_INTR_OFFSET); | 781 | irq_base + USB_PRES_INTR_OFFSET); |
@@ -799,22 +799,22 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
799 | } | 799 | } |
800 | 800 | ||
801 | if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) { | 801 | if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) { |
802 | child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0); | 802 | child = add_child(SUB_CHIP_ID3, "twl4030_wdt", NULL, 0, |
803 | false, 0, 0); | ||
803 | if (IS_ERR(child)) | 804 | if (IS_ERR(child)) |
804 | return PTR_ERR(child); | 805 | return PTR_ERR(child); |
805 | } | 806 | } |
806 | 807 | ||
807 | if (IS_ENABLED(CONFIG_INPUT_TWL4030_PWRBUTTON) && twl_class_is_4030()) { | 808 | if (IS_ENABLED(CONFIG_INPUT_TWL4030_PWRBUTTON) && twl_class_is_4030()) { |
808 | child = add_child(1, "twl4030_pwrbutton", | 809 | child = add_child(SUB_CHIP_ID3, "twl4030_pwrbutton", NULL, 0, |
809 | NULL, 0, true, irq_base + 8 + 0, 0); | 810 | true, irq_base + 8 + 0, 0); |
810 | if (IS_ERR(child)) | 811 | if (IS_ERR(child)) |
811 | return PTR_ERR(child); | 812 | return PTR_ERR(child); |
812 | } | 813 | } |
813 | 814 | ||
814 | if (IS_ENABLED(CONFIG_MFD_TWL4030_AUDIO) && pdata->audio && | 815 | if (IS_ENABLED(CONFIG_MFD_TWL4030_AUDIO) && pdata->audio && |
815 | twl_class_is_4030()) { | 816 | twl_class_is_4030()) { |
816 | sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid; | 817 | child = add_child(SUB_CHIP_ID1, "twl4030-audio", |
817 | child = add_child(sub_chip_id, "twl4030-audio", | ||
818 | pdata->audio, sizeof(*pdata->audio), | 818 | pdata->audio, sizeof(*pdata->audio), |
819 | false, 0, 0); | 819 | false, 0, 0); |
820 | if (IS_ERR(child)) | 820 | if (IS_ERR(child)) |
@@ -1054,7 +1054,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, | |||
1054 | 1054 | ||
1055 | if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci && | 1055 | if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci && |
1056 | !(features & (TPS_SUBSET | TWL5031))) { | 1056 | !(features & (TPS_SUBSET | TWL5031))) { |
1057 | child = add_child(3, "twl4030_bci", | 1057 | child = add_child(SUB_CHIP_ID3, "twl4030_bci", |
1058 | pdata->bci, sizeof(*pdata->bci), false, | 1058 | pdata->bci, sizeof(*pdata->bci), false, |
1059 | /* irq0 = CHG_PRES, irq1 = BCI */ | 1059 | /* irq0 = CHG_PRES, irq1 = BCI */ |
1060 | irq_base + BCI_PRES_INTR_OFFSET, | 1060 | irq_base + BCI_PRES_INTR_OFFSET, |
@@ -1077,8 +1077,8 @@ static inline int __init protect_pm_master(void) | |||
1077 | { | 1077 | { |
1078 | int e = 0; | 1078 | int e = 0; |
1079 | 1079 | ||
1080 | e = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, | 1080 | e = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0, |
1081 | TWL4030_PM_MASTER_PROTECT_KEY); | 1081 | TWL4030_PM_MASTER_PROTECT_KEY); |
1082 | return e; | 1082 | return e; |
1083 | } | 1083 | } |
1084 | 1084 | ||
@@ -1086,12 +1086,10 @@ static inline int __init unprotect_pm_master(void) | |||
1086 | { | 1086 | { |
1087 | int e = 0; | 1087 | int e = 0; |
1088 | 1088 | ||
1089 | e |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, | 1089 | e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1, |
1090 | TWL4030_PM_MASTER_KEY_CFG1, | 1090 | TWL4030_PM_MASTER_PROTECT_KEY); |
1091 | TWL4030_PM_MASTER_PROTECT_KEY); | 1091 | e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2, |
1092 | e |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, | 1092 | TWL4030_PM_MASTER_PROTECT_KEY); |
1093 | TWL4030_PM_MASTER_KEY_CFG2, | ||
1094 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
1095 | 1093 | ||
1096 | return e; | 1094 | return e; |
1097 | } | 1095 | } |
@@ -1176,6 +1174,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
1176 | struct twl4030_platform_data *pdata = client->dev.platform_data; | 1174 | struct twl4030_platform_data *pdata = client->dev.platform_data; |
1177 | struct device_node *node = client->dev.of_node; | 1175 | struct device_node *node = client->dev.of_node; |
1178 | struct platform_device *pdev; | 1176 | struct platform_device *pdev; |
1177 | struct regmap_config *twl_regmap_config; | ||
1179 | int irq_base = 0; | 1178 | int irq_base = 0; |
1180 | int status; | 1179 | int status; |
1181 | unsigned i, num_slaves; | 1180 | unsigned i, num_slaves; |
@@ -1229,22 +1228,23 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
1229 | if ((id->driver_data) & TWL6030_CLASS) { | 1228 | if ((id->driver_data) & TWL6030_CLASS) { |
1230 | twl_id = TWL6030_CLASS_ID; | 1229 | twl_id = TWL6030_CLASS_ID; |
1231 | twl_map = &twl6030_map[0]; | 1230 | twl_map = &twl6030_map[0]; |
1231 | twl_regmap_config = twl6030_regmap_config; | ||
1232 | num_slaves = TWL_NUM_SLAVES - 1; | 1232 | num_slaves = TWL_NUM_SLAVES - 1; |
1233 | } else { | 1233 | } else { |
1234 | twl_id = TWL4030_CLASS_ID; | 1234 | twl_id = TWL4030_CLASS_ID; |
1235 | twl_map = &twl4030_map[0]; | 1235 | twl_map = &twl4030_map[0]; |
1236 | twl_regmap_config = twl4030_regmap_config; | ||
1236 | num_slaves = TWL_NUM_SLAVES; | 1237 | num_slaves = TWL_NUM_SLAVES; |
1237 | } | 1238 | } |
1238 | 1239 | ||
1239 | for (i = 0; i < num_slaves; i++) { | 1240 | for (i = 0; i < num_slaves; i++) { |
1240 | struct twl_client *twl = &twl_modules[i]; | 1241 | struct twl_client *twl = &twl_modules[i]; |
1241 | 1242 | ||
1242 | twl->address = client->addr + i; | ||
1243 | if (i == 0) { | 1243 | if (i == 0) { |
1244 | twl->client = client; | 1244 | twl->client = client; |
1245 | } else { | 1245 | } else { |
1246 | twl->client = i2c_new_dummy(client->adapter, | 1246 | twl->client = i2c_new_dummy(client->adapter, |
1247 | twl->address); | 1247 | client->addr + i); |
1248 | if (!twl->client) { | 1248 | if (!twl->client) { |
1249 | dev_err(&client->dev, | 1249 | dev_err(&client->dev, |
1250 | "can't attach client %d\n", i); | 1250 | "can't attach client %d\n", i); |
@@ -1252,7 +1252,16 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
1252 | goto fail; | 1252 | goto fail; |
1253 | } | 1253 | } |
1254 | } | 1254 | } |
1255 | mutex_init(&twl->xfer_lock); | 1255 | |
1256 | twl->regmap = devm_regmap_init_i2c(twl->client, | ||
1257 | &twl_regmap_config[i]); | ||
1258 | if (IS_ERR(twl->regmap)) { | ||
1259 | status = PTR_ERR(twl->regmap); | ||
1260 | dev_err(&client->dev, | ||
1261 | "Failed to allocate regmap %d, err: %d\n", i, | ||
1262 | status); | ||
1263 | goto fail; | ||
1264 | } | ||
1256 | } | 1265 | } |
1257 | 1266 | ||
1258 | inuse = true; | 1267 | inuse = true; |
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index cdd1173ed4e..a5f9888aa19 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c | |||
@@ -295,8 +295,8 @@ static irqreturn_t handle_twl4030_pih(int irq, void *devid) | |||
295 | irqreturn_t ret; | 295 | irqreturn_t ret; |
296 | u8 pih_isr; | 296 | u8 pih_isr; |
297 | 297 | ||
298 | ret = twl_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr, | 298 | ret = twl_i2c_read_u8(TWL_MODULE_PIH, &pih_isr, |
299 | REG_PIH_ISR_P1); | 299 | REG_PIH_ISR_P1); |
300 | if (ret) { | 300 | if (ret) { |
301 | pr_warning("twl4030: I2C error %d reading PIH ISR\n", ret); | 301 | pr_warning("twl4030: I2C error %d reading PIH ISR\n", ret); |
302 | return IRQ_NONE; | 302 | return IRQ_NONE; |
@@ -501,7 +501,7 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data) | |||
501 | } imr; | 501 | } imr; |
502 | 502 | ||
503 | /* byte[0] gets overwritten as we write ... */ | 503 | /* byte[0] gets overwritten as we write ... */ |
504 | imr.word = cpu_to_le32(agent->imr << 8); | 504 | imr.word = cpu_to_le32(agent->imr); |
505 | agent->imr_change_pending = false; | 505 | agent->imr_change_pending = false; |
506 | 506 | ||
507 | /* write the whole mask ... simpler than subsetting it */ | 507 | /* write the whole mask ... simpler than subsetting it */ |
@@ -526,7 +526,7 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data) | |||
526 | * any processor on the other IRQ line, EDR registers are | 526 | * any processor on the other IRQ line, EDR registers are |
527 | * shared. | 527 | * shared. |
528 | */ | 528 | */ |
529 | status = twl_i2c_read(sih->module, bytes + 1, | 529 | status = twl_i2c_read(sih->module, bytes, |
530 | sih->edr_offset, sih->bytes_edr); | 530 | sih->edr_offset, sih->bytes_edr); |
531 | if (status) { | 531 | if (status) { |
532 | pr_err("twl4030: %s, %s --> %d\n", __func__, | 532 | pr_err("twl4030: %s, %s --> %d\n", __func__, |
@@ -538,7 +538,7 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data) | |||
538 | while (edge_change) { | 538 | while (edge_change) { |
539 | int i = fls(edge_change) - 1; | 539 | int i = fls(edge_change) - 1; |
540 | struct irq_data *idata; | 540 | struct irq_data *idata; |
541 | int byte = 1 + (i >> 2); | 541 | int byte = i >> 2; |
542 | int off = (i & 0x3) * 2; | 542 | int off = (i & 0x3) * 2; |
543 | unsigned int type; | 543 | unsigned int type; |
544 | 544 | ||
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index a39dcf3e213..88ff9dc8330 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c | |||
@@ -173,7 +173,7 @@ static int twl4030battery_temperature(int raw_volt) | |||
173 | 173 | ||
174 | volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R; | 174 | volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R; |
175 | /* Getting and calculating the supply current in micro ampers */ | 175 | /* Getting and calculating the supply current in micro ampers */ |
176 | ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val, | 176 | ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val, |
177 | REG_BCICTL2); | 177 | REG_BCICTL2); |
178 | if (ret < 0) | 178 | if (ret < 0) |
179 | return ret; | 179 | return ret; |
@@ -196,7 +196,7 @@ static int twl4030battery_current(int raw_volt) | |||
196 | int ret; | 196 | int ret; |
197 | u8 val; | 197 | u8 val; |
198 | 198 | ||
199 | ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val, | 199 | ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val, |
200 | TWL4030_BCI_BCICTL1); | 200 | TWL4030_BCI_BCICTL1); |
201 | if (ret) | 201 | if (ret) |
202 | return ret; | 202 | return ret; |
@@ -635,7 +635,7 @@ static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc, | |||
635 | int ret; | 635 | int ret; |
636 | u8 regval; | 636 | u8 regval; |
637 | 637 | ||
638 | ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, | 638 | ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, |
639 | ®val, TWL4030_BCI_BCICTL1); | 639 | ®val, TWL4030_BCI_BCICTL1); |
640 | if (ret) { | 640 | if (ret) { |
641 | dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X", | 641 | dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X", |
@@ -646,7 +646,7 @@ static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc, | |||
646 | regval |= chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN; | 646 | regval |= chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN; |
647 | else | 647 | else |
648 | regval &= chan ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN; | 648 | regval &= chan ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN; |
649 | ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, | 649 | ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, |
650 | regval, TWL4030_BCI_BCICTL1); | 650 | regval, TWL4030_BCI_BCICTL1); |
651 | if (ret) { | 651 | if (ret) { |
652 | dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n", | 652 | dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n", |
@@ -668,7 +668,7 @@ static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on) | |||
668 | u8 regval; | 668 | u8 regval; |
669 | int ret; | 669 | int ret; |
670 | 670 | ||
671 | ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, | 671 | ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, |
672 | ®val, TWL4030_MADC_CTRL1); | 672 | ®val, TWL4030_MADC_CTRL1); |
673 | if (ret) { | 673 | if (ret) { |
674 | dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n", | 674 | dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n", |
@@ -725,7 +725,7 @@ static int twl4030_madc_probe(struct platform_device *pdev) | |||
725 | if (ret < 0) | 725 | if (ret < 0) |
726 | goto err_current_generator; | 726 | goto err_current_generator; |
727 | 727 | ||
728 | ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, | 728 | ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, |
729 | ®val, TWL4030_BCI_BCICTL1); | 729 | ®val, TWL4030_BCI_BCICTL1); |
730 | if (ret) { | 730 | if (ret) { |
731 | dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n", | 731 | dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n", |
@@ -733,7 +733,7 @@ static int twl4030_madc_probe(struct platform_device *pdev) | |||
733 | goto err_i2c; | 733 | goto err_i2c; |
734 | } | 734 | } |
735 | regval |= TWL4030_BCI_MESBAT; | 735 | regval |= TWL4030_BCI_MESBAT; |
736 | ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, | 736 | ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, |
737 | regval, TWL4030_BCI_BCICTL1); | 737 | regval, TWL4030_BCI_BCICTL1); |
738 | if (ret) { | 738 | if (ret) { |
739 | dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n", | 739 | dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n", |
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index a5332063183..4dae241e501 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c | |||
@@ -128,12 +128,10 @@ static int twl4030_write_script_byte(u8 address, u8 byte) | |||
128 | { | 128 | { |
129 | int err; | 129 | int err; |
130 | 130 | ||
131 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, | 131 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, address, R_MEMORY_ADDRESS); |
132 | R_MEMORY_ADDRESS); | ||
133 | if (err) | 132 | if (err) |
134 | goto out; | 133 | goto out; |
135 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte, | 134 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, byte, R_MEMORY_DATA); |
136 | R_MEMORY_DATA); | ||
137 | out: | 135 | out: |
138 | return err; | 136 | return err; |
139 | } | 137 | } |
@@ -189,19 +187,16 @@ static int twl4030_config_wakeup3_sequence(u8 address) | |||
189 | u8 data; | 187 | u8 data; |
190 | 188 | ||
191 | /* Set SLEEP to ACTIVE SEQ address for P3 */ | 189 | /* Set SLEEP to ACTIVE SEQ address for P3 */ |
192 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, | 190 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, address, R_SEQ_ADD_S2A3); |
193 | R_SEQ_ADD_S2A3); | ||
194 | if (err) | 191 | if (err) |
195 | goto out; | 192 | goto out; |
196 | 193 | ||
197 | /* P3 LVL_WAKEUP should be on LEVEL */ | 194 | /* P3 LVL_WAKEUP should be on LEVEL */ |
198 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, | 195 | err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &data, R_P3_SW_EVENTS); |
199 | R_P3_SW_EVENTS); | ||
200 | if (err) | 196 | if (err) |
201 | goto out; | 197 | goto out; |
202 | data |= LVL_WAKEUP; | 198 | data |= LVL_WAKEUP; |
203 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data, | 199 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, data, R_P3_SW_EVENTS); |
204 | R_P3_SW_EVENTS); | ||
205 | out: | 200 | out: |
206 | if (err) | 201 | if (err) |
207 | pr_err("TWL4030 wakeup sequence for P3 config error\n"); | 202 | pr_err("TWL4030 wakeup sequence for P3 config error\n"); |
@@ -214,43 +209,38 @@ static int twl4030_config_wakeup12_sequence(u8 address) | |||
214 | u8 data; | 209 | u8 data; |
215 | 210 | ||
216 | /* Set SLEEP to ACTIVE SEQ address for P1 and P2 */ | 211 | /* Set SLEEP to ACTIVE SEQ address for P1 and P2 */ |
217 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, | 212 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, address, R_SEQ_ADD_S2A12); |
218 | R_SEQ_ADD_S2A12); | ||
219 | if (err) | 213 | if (err) |
220 | goto out; | 214 | goto out; |
221 | 215 | ||
222 | /* P1/P2 LVL_WAKEUP should be on LEVEL */ | 216 | /* P1/P2 LVL_WAKEUP should be on LEVEL */ |
223 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, | 217 | err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &data, R_P1_SW_EVENTS); |
224 | R_P1_SW_EVENTS); | ||
225 | if (err) | 218 | if (err) |
226 | goto out; | 219 | goto out; |
227 | 220 | ||
228 | data |= LVL_WAKEUP; | 221 | data |= LVL_WAKEUP; |
229 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data, | 222 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, data, R_P1_SW_EVENTS); |
230 | R_P1_SW_EVENTS); | ||
231 | if (err) | 223 | if (err) |
232 | goto out; | 224 | goto out; |
233 | 225 | ||
234 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, | 226 | err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &data, R_P2_SW_EVENTS); |
235 | R_P2_SW_EVENTS); | ||
236 | if (err) | 227 | if (err) |
237 | goto out; | 228 | goto out; |
238 | 229 | ||
239 | data |= LVL_WAKEUP; | 230 | data |= LVL_WAKEUP; |
240 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data, | 231 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, data, R_P2_SW_EVENTS); |
241 | R_P2_SW_EVENTS); | ||
242 | if (err) | 232 | if (err) |
243 | goto out; | 233 | goto out; |
244 | 234 | ||
245 | if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) { | 235 | if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) { |
246 | /* Disabling AC charger effect on sleep-active transitions */ | 236 | /* Disabling AC charger effect on sleep-active transitions */ |
247 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, | 237 | err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &data, |
248 | R_CFG_P1_TRANSITION); | 238 | R_CFG_P1_TRANSITION); |
249 | if (err) | 239 | if (err) |
250 | goto out; | 240 | goto out; |
251 | data &= ~(1<<1); | 241 | data &= ~(1<<1); |
252 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data , | 242 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, data, |
253 | R_CFG_P1_TRANSITION); | 243 | R_CFG_P1_TRANSITION); |
254 | if (err) | 244 | if (err) |
255 | goto out; | 245 | goto out; |
256 | } | 246 | } |
@@ -267,8 +257,7 @@ static int twl4030_config_sleep_sequence(u8 address) | |||
267 | int err; | 257 | int err; |
268 | 258 | ||
269 | /* Set ACTIVE to SLEEP SEQ address in T2 memory*/ | 259 | /* Set ACTIVE to SLEEP SEQ address in T2 memory*/ |
270 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, | 260 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, address, R_SEQ_ADD_A2S); |
271 | R_SEQ_ADD_A2S); | ||
272 | 261 | ||
273 | if (err) | 262 | if (err) |
274 | pr_err("TWL4030 sleep sequence config error\n"); | 263 | pr_err("TWL4030 sleep sequence config error\n"); |
@@ -282,42 +271,35 @@ static int twl4030_config_warmreset_sequence(u8 address) | |||
282 | u8 rd_data; | 271 | u8 rd_data; |
283 | 272 | ||
284 | /* Set WARM RESET SEQ address for P1 */ | 273 | /* Set WARM RESET SEQ address for P1 */ |
285 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, | 274 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, address, R_SEQ_ADD_WARM); |
286 | R_SEQ_ADD_WARM); | ||
287 | if (err) | 275 | if (err) |
288 | goto out; | 276 | goto out; |
289 | 277 | ||
290 | /* P1/P2/P3 enable WARMRESET */ | 278 | /* P1/P2/P3 enable WARMRESET */ |
291 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data, | 279 | err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &rd_data, R_P1_SW_EVENTS); |
292 | R_P1_SW_EVENTS); | ||
293 | if (err) | 280 | if (err) |
294 | goto out; | 281 | goto out; |
295 | 282 | ||
296 | rd_data |= ENABLE_WARMRESET; | 283 | rd_data |= ENABLE_WARMRESET; |
297 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data, | 284 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, rd_data, R_P1_SW_EVENTS); |
298 | R_P1_SW_EVENTS); | ||
299 | if (err) | 285 | if (err) |
300 | goto out; | 286 | goto out; |
301 | 287 | ||
302 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data, | 288 | err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &rd_data, R_P2_SW_EVENTS); |
303 | R_P2_SW_EVENTS); | ||
304 | if (err) | 289 | if (err) |
305 | goto out; | 290 | goto out; |
306 | 291 | ||
307 | rd_data |= ENABLE_WARMRESET; | 292 | rd_data |= ENABLE_WARMRESET; |
308 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data, | 293 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, rd_data, R_P2_SW_EVENTS); |
309 | R_P2_SW_EVENTS); | ||
310 | if (err) | 294 | if (err) |
311 | goto out; | 295 | goto out; |
312 | 296 | ||
313 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data, | 297 | err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &rd_data, R_P3_SW_EVENTS); |
314 | R_P3_SW_EVENTS); | ||
315 | if (err) | 298 | if (err) |
316 | goto out; | 299 | goto out; |
317 | 300 | ||
318 | rd_data |= ENABLE_WARMRESET; | 301 | rd_data |= ENABLE_WARMRESET; |
319 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data, | 302 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, rd_data, R_P3_SW_EVENTS); |
320 | R_P3_SW_EVENTS); | ||
321 | out: | 303 | out: |
322 | if (err) | 304 | if (err) |
323 | pr_err("TWL4030 warmreset seq config error\n"); | 305 | pr_err("TWL4030 warmreset seq config error\n"); |
@@ -341,7 +323,7 @@ static int twl4030_configure_resource(struct twl4030_resconfig *rconfig) | |||
341 | rconfig_addr = res_config_addrs[rconfig->resource]; | 323 | rconfig_addr = res_config_addrs[rconfig->resource]; |
342 | 324 | ||
343 | /* Set resource group */ | 325 | /* Set resource group */ |
344 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp, | 326 | err = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &grp, |
345 | rconfig_addr + DEV_GRP_OFFSET); | 327 | rconfig_addr + DEV_GRP_OFFSET); |
346 | if (err) { | 328 | if (err) { |
347 | pr_err("TWL4030 Resource %d group could not be read\n", | 329 | pr_err("TWL4030 Resource %d group could not be read\n", |
@@ -352,7 +334,7 @@ static int twl4030_configure_resource(struct twl4030_resconfig *rconfig) | |||
352 | if (rconfig->devgroup != TWL4030_RESCONFIG_UNDEF) { | 334 | if (rconfig->devgroup != TWL4030_RESCONFIG_UNDEF) { |
353 | grp &= ~DEV_GRP_MASK; | 335 | grp &= ~DEV_GRP_MASK; |
354 | grp |= rconfig->devgroup << DEV_GRP_SHIFT; | 336 | grp |= rconfig->devgroup << DEV_GRP_SHIFT; |
355 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, | 337 | err = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, |
356 | grp, rconfig_addr + DEV_GRP_OFFSET); | 338 | grp, rconfig_addr + DEV_GRP_OFFSET); |
357 | if (err < 0) { | 339 | if (err < 0) { |
358 | pr_err("TWL4030 failed to program devgroup\n"); | 340 | pr_err("TWL4030 failed to program devgroup\n"); |
@@ -361,7 +343,7 @@ static int twl4030_configure_resource(struct twl4030_resconfig *rconfig) | |||
361 | } | 343 | } |
362 | 344 | ||
363 | /* Set resource types */ | 345 | /* Set resource types */ |
364 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &type, | 346 | err = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &type, |
365 | rconfig_addr + TYPE_OFFSET); | 347 | rconfig_addr + TYPE_OFFSET); |
366 | if (err < 0) { | 348 | if (err < 0) { |
367 | pr_err("TWL4030 Resource %d type could not be read\n", | 349 | pr_err("TWL4030 Resource %d type could not be read\n", |
@@ -379,7 +361,7 @@ static int twl4030_configure_resource(struct twl4030_resconfig *rconfig) | |||
379 | type |= rconfig->type2 << TYPE2_SHIFT; | 361 | type |= rconfig->type2 << TYPE2_SHIFT; |
380 | } | 362 | } |
381 | 363 | ||
382 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, | 364 | err = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, |
383 | type, rconfig_addr + TYPE_OFFSET); | 365 | type, rconfig_addr + TYPE_OFFSET); |
384 | if (err < 0) { | 366 | if (err < 0) { |
385 | pr_err("TWL4030 failed to program resource type\n"); | 367 | pr_err("TWL4030 failed to program resource type\n"); |
@@ -387,7 +369,7 @@ static int twl4030_configure_resource(struct twl4030_resconfig *rconfig) | |||
387 | } | 369 | } |
388 | 370 | ||
389 | /* Set remap states */ | 371 | /* Set remap states */ |
390 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &remap, | 372 | err = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &remap, |
391 | rconfig_addr + REMAP_OFFSET); | 373 | rconfig_addr + REMAP_OFFSET); |
392 | if (err < 0) { | 374 | if (err < 0) { |
393 | pr_err("TWL4030 Resource %d remap could not be read\n", | 375 | pr_err("TWL4030 Resource %d remap could not be read\n", |
@@ -405,7 +387,7 @@ static int twl4030_configure_resource(struct twl4030_resconfig *rconfig) | |||
405 | remap |= rconfig->remap_sleep << SLEEP_STATE_SHIFT; | 387 | remap |= rconfig->remap_sleep << SLEEP_STATE_SHIFT; |
406 | } | 388 | } |
407 | 389 | ||
408 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, | 390 | err = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, |
409 | remap, | 391 | remap, |
410 | rconfig_addr + REMAP_OFFSET); | 392 | rconfig_addr + REMAP_OFFSET); |
411 | if (err < 0) { | 393 | if (err < 0) { |
@@ -463,49 +445,47 @@ int twl4030_remove_script(u8 flags) | |||
463 | { | 445 | { |
464 | int err = 0; | 446 | int err = 0; |
465 | 447 | ||
466 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, | 448 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1, |
467 | TWL4030_PM_MASTER_KEY_CFG1, | 449 | TWL4030_PM_MASTER_PROTECT_KEY); |
468 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
469 | if (err) { | 450 | if (err) { |
470 | pr_err("twl4030: unable to unlock PROTECT_KEY\n"); | 451 | pr_err("twl4030: unable to unlock PROTECT_KEY\n"); |
471 | return err; | 452 | return err; |
472 | } | 453 | } |
473 | 454 | ||
474 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, | 455 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2, |
475 | TWL4030_PM_MASTER_KEY_CFG2, | 456 | TWL4030_PM_MASTER_PROTECT_KEY); |
476 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
477 | if (err) { | 457 | if (err) { |
478 | pr_err("twl4030: unable to unlock PROTECT_KEY\n"); | 458 | pr_err("twl4030: unable to unlock PROTECT_KEY\n"); |
479 | return err; | 459 | return err; |
480 | } | 460 | } |
481 | 461 | ||
482 | if (flags & TWL4030_WRST_SCRIPT) { | 462 | if (flags & TWL4030_WRST_SCRIPT) { |
483 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT, | 463 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, END_OF_SCRIPT, |
484 | R_SEQ_ADD_WARM); | 464 | R_SEQ_ADD_WARM); |
485 | if (err) | 465 | if (err) |
486 | return err; | 466 | return err; |
487 | } | 467 | } |
488 | if (flags & TWL4030_WAKEUP12_SCRIPT) { | 468 | if (flags & TWL4030_WAKEUP12_SCRIPT) { |
489 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT, | 469 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, END_OF_SCRIPT, |
490 | R_SEQ_ADD_S2A12); | 470 | R_SEQ_ADD_S2A12); |
491 | if (err) | 471 | if (err) |
492 | return err; | 472 | return err; |
493 | } | 473 | } |
494 | if (flags & TWL4030_WAKEUP3_SCRIPT) { | 474 | if (flags & TWL4030_WAKEUP3_SCRIPT) { |
495 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT, | 475 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, END_OF_SCRIPT, |
496 | R_SEQ_ADD_S2A3); | 476 | R_SEQ_ADD_S2A3); |
497 | if (err) | 477 | if (err) |
498 | return err; | 478 | return err; |
499 | } | 479 | } |
500 | if (flags & TWL4030_SLEEP_SCRIPT) { | 480 | if (flags & TWL4030_SLEEP_SCRIPT) { |
501 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT, | 481 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, END_OF_SCRIPT, |
502 | R_SEQ_ADD_A2S); | 482 | R_SEQ_ADD_A2S); |
503 | if (err) | 483 | if (err) |
504 | return err; | 484 | return err; |
505 | } | 485 | } |
506 | 486 | ||
507 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, | 487 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0, |
508 | TWL4030_PM_MASTER_PROTECT_KEY); | 488 | TWL4030_PM_MASTER_PROTECT_KEY); |
509 | if (err) | 489 | if (err) |
510 | pr_err("TWL4030 Unable to relock registers\n"); | 490 | pr_err("TWL4030 Unable to relock registers\n"); |
511 | 491 | ||
@@ -521,7 +501,7 @@ void twl4030_power_off(void) | |||
521 | { | 501 | { |
522 | int err; | 502 | int err; |
523 | 503 | ||
524 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, PWR_DEVOFF, | 504 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, PWR_DEVOFF, |
525 | TWL4030_PM_MASTER_P1_SW_EVENTS); | 505 | TWL4030_PM_MASTER_P1_SW_EVENTS); |
526 | if (err) | 506 | if (err) |
527 | pr_err("TWL4030 Unable to power off\n"); | 507 | pr_err("TWL4030 Unable to power off\n"); |
@@ -534,15 +514,13 @@ void twl4030_power_init(struct twl4030_power_data *twl4030_scripts) | |||
534 | struct twl4030_resconfig *resconfig; | 514 | struct twl4030_resconfig *resconfig; |
535 | u8 val, address = twl4030_start_script_address; | 515 | u8 val, address = twl4030_start_script_address; |
536 | 516 | ||
537 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, | 517 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1, |
538 | TWL4030_PM_MASTER_KEY_CFG1, | 518 | TWL4030_PM_MASTER_PROTECT_KEY); |
539 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
540 | if (err) | 519 | if (err) |
541 | goto unlock; | 520 | goto unlock; |
542 | 521 | ||
543 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, | 522 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2, |
544 | TWL4030_PM_MASTER_KEY_CFG2, | 523 | TWL4030_PM_MASTER_PROTECT_KEY); |
545 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
546 | if (err) | 524 | if (err) |
547 | goto unlock; | 525 | goto unlock; |
548 | 526 | ||
@@ -567,14 +545,14 @@ void twl4030_power_init(struct twl4030_power_data *twl4030_scripts) | |||
567 | /* Board has to be wired properly to use this feature */ | 545 | /* Board has to be wired properly to use this feature */ |
568 | if (twl4030_scripts->use_poweroff && !pm_power_off) { | 546 | if (twl4030_scripts->use_poweroff && !pm_power_off) { |
569 | /* Default for SEQ_OFFSYNC is set, lets ensure this */ | 547 | /* Default for SEQ_OFFSYNC is set, lets ensure this */ |
570 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val, | 548 | err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val, |
571 | TWL4030_PM_MASTER_CFG_P123_TRANSITION); | 549 | TWL4030_PM_MASTER_CFG_P123_TRANSITION); |
572 | if (err) { | 550 | if (err) { |
573 | pr_warning("TWL4030 Unable to read registers\n"); | 551 | pr_warning("TWL4030 Unable to read registers\n"); |
574 | 552 | ||
575 | } else if (!(val & SEQ_OFFSYNC)) { | 553 | } else if (!(val & SEQ_OFFSYNC)) { |
576 | val |= SEQ_OFFSYNC; | 554 | val |= SEQ_OFFSYNC; |
577 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val, | 555 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, val, |
578 | TWL4030_PM_MASTER_CFG_P123_TRANSITION); | 556 | TWL4030_PM_MASTER_CFG_P123_TRANSITION); |
579 | if (err) { | 557 | if (err) { |
580 | pr_err("TWL4030 Unable to setup SEQ_OFFSYNC\n"); | 558 | pr_err("TWL4030 Unable to setup SEQ_OFFSYNC\n"); |
@@ -586,8 +564,8 @@ void twl4030_power_init(struct twl4030_power_data *twl4030_scripts) | |||
586 | } | 564 | } |
587 | 565 | ||
588 | relock: | 566 | relock: |
589 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, | 567 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0, |
590 | TWL4030_PM_MASTER_PROTECT_KEY); | 568 | TWL4030_PM_MASTER_PROTECT_KEY); |
591 | if (err) | 569 | if (err) |
592 | pr_err("TWL4030 Unable to relock registers\n"); | 570 | pr_err("TWL4030 Unable to relock registers\n"); |
593 | return; | 571 | return; |
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index b76902f1e44..277a8dba42d 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c | |||
@@ -355,7 +355,7 @@ int twl6030_init_irq(struct device *dev, int irq_num) | |||
355 | static struct irq_chip twl6030_irq_chip; | 355 | static struct irq_chip twl6030_irq_chip; |
356 | int status = 0; | 356 | int status = 0; |
357 | int i; | 357 | int i; |
358 | u8 mask[4]; | 358 | u8 mask[3]; |
359 | 359 | ||
360 | nr_irqs = TWL6030_NR_IRQS; | 360 | nr_irqs = TWL6030_NR_IRQS; |
361 | 361 | ||
@@ -370,9 +370,9 @@ int twl6030_init_irq(struct device *dev, int irq_num) | |||
370 | 370 | ||
371 | irq_end = irq_base + nr_irqs; | 371 | irq_end = irq_base + nr_irqs; |
372 | 372 | ||
373 | mask[0] = 0xFF; | ||
373 | mask[1] = 0xFF; | 374 | mask[1] = 0xFF; |
374 | mask[2] = 0xFF; | 375 | mask[2] = 0xFF; |
375 | mask[3] = 0xFF; | ||
376 | 376 | ||
377 | /* mask all int lines */ | 377 | /* mask all int lines */ |
378 | twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3); | 378 | twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3); |
diff --git a/drivers/mfd/twl6040-irq.c b/drivers/mfd/twl6040-irq.c deleted file mode 100644 index 4b42543da22..00000000000 --- a/drivers/mfd/twl6040-irq.c +++ /dev/null | |||
@@ -1,205 +0,0 @@ | |||
1 | /* | ||
2 | * Interrupt controller support for TWL6040 | ||
3 | * | ||
4 | * Author: Misael Lopez Cruz <misael.lopez@ti.com> | ||
5 | * | ||
6 | * Copyright: (C) 2011 Texas Instruments, Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/err.h> | ||
27 | #include <linux/irq.h> | ||
28 | #include <linux/of.h> | ||
29 | #include <linux/irqdomain.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/mfd/core.h> | ||
32 | #include <linux/mfd/twl6040.h> | ||
33 | |||
34 | struct twl6040_irq_data { | ||
35 | int mask; | ||
36 | int status; | ||
37 | }; | ||
38 | |||
39 | static struct twl6040_irq_data twl6040_irqs[] = { | ||
40 | { | ||
41 | .mask = TWL6040_THMSK, | ||
42 | .status = TWL6040_THINT, | ||
43 | }, | ||
44 | { | ||
45 | .mask = TWL6040_PLUGMSK, | ||
46 | .status = TWL6040_PLUGINT | TWL6040_UNPLUGINT, | ||
47 | }, | ||
48 | { | ||
49 | .mask = TWL6040_HOOKMSK, | ||
50 | .status = TWL6040_HOOKINT, | ||
51 | }, | ||
52 | { | ||
53 | .mask = TWL6040_HFMSK, | ||
54 | .status = TWL6040_HFINT, | ||
55 | }, | ||
56 | { | ||
57 | .mask = TWL6040_VIBMSK, | ||
58 | .status = TWL6040_VIBINT, | ||
59 | }, | ||
60 | { | ||
61 | .mask = TWL6040_READYMSK, | ||
62 | .status = TWL6040_READYINT, | ||
63 | }, | ||
64 | }; | ||
65 | |||
66 | static inline | ||
67 | struct twl6040_irq_data *irq_to_twl6040_irq(struct twl6040 *twl6040, | ||
68 | int irq) | ||
69 | { | ||
70 | return &twl6040_irqs[irq - twl6040->irq_base]; | ||
71 | } | ||
72 | |||
73 | static void twl6040_irq_lock(struct irq_data *data) | ||
74 | { | ||
75 | struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data); | ||
76 | |||
77 | mutex_lock(&twl6040->irq_mutex); | ||
78 | } | ||
79 | |||
80 | static void twl6040_irq_sync_unlock(struct irq_data *data) | ||
81 | { | ||
82 | struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data); | ||
83 | |||
84 | /* write back to hardware any change in irq mask */ | ||
85 | if (twl6040->irq_masks_cur != twl6040->irq_masks_cache) { | ||
86 | twl6040->irq_masks_cache = twl6040->irq_masks_cur; | ||
87 | twl6040_reg_write(twl6040, TWL6040_REG_INTMR, | ||
88 | twl6040->irq_masks_cur); | ||
89 | } | ||
90 | |||
91 | mutex_unlock(&twl6040->irq_mutex); | ||
92 | } | ||
93 | |||
94 | static void twl6040_irq_enable(struct irq_data *data) | ||
95 | { | ||
96 | struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data); | ||
97 | struct twl6040_irq_data *irq_data = irq_to_twl6040_irq(twl6040, | ||
98 | data->irq); | ||
99 | |||
100 | twl6040->irq_masks_cur &= ~irq_data->mask; | ||
101 | } | ||
102 | |||
103 | static void twl6040_irq_disable(struct irq_data *data) | ||
104 | { | ||
105 | struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data); | ||
106 | struct twl6040_irq_data *irq_data = irq_to_twl6040_irq(twl6040, | ||
107 | data->irq); | ||
108 | |||
109 | twl6040->irq_masks_cur |= irq_data->mask; | ||
110 | } | ||
111 | |||
112 | static struct irq_chip twl6040_irq_chip = { | ||
113 | .name = "twl6040", | ||
114 | .irq_bus_lock = twl6040_irq_lock, | ||
115 | .irq_bus_sync_unlock = twl6040_irq_sync_unlock, | ||
116 | .irq_enable = twl6040_irq_enable, | ||
117 | .irq_disable = twl6040_irq_disable, | ||
118 | }; | ||
119 | |||
120 | static irqreturn_t twl6040_irq_thread(int irq, void *data) | ||
121 | { | ||
122 | struct twl6040 *twl6040 = data; | ||
123 | u8 intid; | ||
124 | int i; | ||
125 | |||
126 | intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID); | ||
127 | |||
128 | /* apply masking and report (backwards to handle READYINT first) */ | ||
129 | for (i = ARRAY_SIZE(twl6040_irqs) - 1; i >= 0; i--) { | ||
130 | if (twl6040->irq_masks_cur & twl6040_irqs[i].mask) | ||
131 | intid &= ~twl6040_irqs[i].status; | ||
132 | if (intid & twl6040_irqs[i].status) | ||
133 | handle_nested_irq(twl6040->irq_base + i); | ||
134 | } | ||
135 | |||
136 | /* ack unmasked irqs */ | ||
137 | twl6040_reg_write(twl6040, TWL6040_REG_INTID, intid); | ||
138 | |||
139 | return IRQ_HANDLED; | ||
140 | } | ||
141 | |||
142 | int twl6040_irq_init(struct twl6040 *twl6040) | ||
143 | { | ||
144 | struct device_node *node = twl6040->dev->of_node; | ||
145 | int i, nr_irqs, irq_base, ret; | ||
146 | u8 val; | ||
147 | |||
148 | mutex_init(&twl6040->irq_mutex); | ||
149 | |||
150 | /* mask the individual interrupt sources */ | ||
151 | twl6040->irq_masks_cur = TWL6040_ALLINT_MSK; | ||
152 | twl6040->irq_masks_cache = TWL6040_ALLINT_MSK; | ||
153 | twl6040_reg_write(twl6040, TWL6040_REG_INTMR, TWL6040_ALLINT_MSK); | ||
154 | |||
155 | nr_irqs = ARRAY_SIZE(twl6040_irqs); | ||
156 | |||
157 | irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0); | ||
158 | if (IS_ERR_VALUE(irq_base)) { | ||
159 | dev_err(twl6040->dev, "Fail to allocate IRQ descs\n"); | ||
160 | return irq_base; | ||
161 | } | ||
162 | twl6040->irq_base = irq_base; | ||
163 | |||
164 | irq_domain_add_legacy(node, ARRAY_SIZE(twl6040_irqs), irq_base, 0, | ||
165 | &irq_domain_simple_ops, NULL); | ||
166 | |||
167 | /* Register them with genirq */ | ||
168 | for (i = irq_base; i < irq_base + nr_irqs; i++) { | ||
169 | irq_set_chip_data(i, twl6040); | ||
170 | irq_set_chip_and_handler(i, &twl6040_irq_chip, | ||
171 | handle_level_irq); | ||
172 | irq_set_nested_thread(i, 1); | ||
173 | |||
174 | /* ARM needs us to explicitly flag the IRQ as valid | ||
175 | * and will set them noprobe when we do so. */ | ||
176 | #ifdef CONFIG_ARM | ||
177 | set_irq_flags(i, IRQF_VALID); | ||
178 | #else | ||
179 | irq_set_noprobe(i); | ||
180 | #endif | ||
181 | } | ||
182 | |||
183 | ret = request_threaded_irq(twl6040->irq, NULL, twl6040_irq_thread, | ||
184 | IRQF_ONESHOT, "twl6040", twl6040); | ||
185 | if (ret) { | ||
186 | dev_err(twl6040->dev, "failed to request IRQ %d: %d\n", | ||
187 | twl6040->irq, ret); | ||
188 | return ret; | ||
189 | } | ||
190 | |||
191 | /* reset interrupts */ | ||
192 | val = twl6040_reg_read(twl6040, TWL6040_REG_INTID); | ||
193 | |||
194 | /* interrupts cleared on write */ | ||
195 | twl6040_clear_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_INTCLRMODE); | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | EXPORT_SYMBOL(twl6040_irq_init); | ||
200 | |||
201 | void twl6040_irq_exit(struct twl6040 *twl6040) | ||
202 | { | ||
203 | free_irq(twl6040->irq, twl6040); | ||
204 | } | ||
205 | EXPORT_SYMBOL(twl6040_irq_exit); | ||
diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040.c index 3f2a1cf02fc..583be76e36a 100644 --- a/drivers/mfd/twl6040-core.c +++ b/drivers/mfd/twl6040.c | |||
@@ -37,7 +37,6 @@ | |||
37 | #include <linux/delay.h> | 37 | #include <linux/delay.h> |
38 | #include <linux/i2c.h> | 38 | #include <linux/i2c.h> |
39 | #include <linux/regmap.h> | 39 | #include <linux/regmap.h> |
40 | #include <linux/err.h> | ||
41 | #include <linux/mfd/core.h> | 40 | #include <linux/mfd/core.h> |
42 | #include <linux/mfd/twl6040.h> | 41 | #include <linux/mfd/twl6040.h> |
43 | #include <linux/regulator/consumer.h> | 42 | #include <linux/regulator/consumer.h> |
@@ -104,7 +103,7 @@ int twl6040_clear_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask) | |||
104 | EXPORT_SYMBOL(twl6040_clear_bits); | 103 | EXPORT_SYMBOL(twl6040_clear_bits); |
105 | 104 | ||
106 | /* twl6040 codec manual power-up sequence */ | 105 | /* twl6040 codec manual power-up sequence */ |
107 | static int twl6040_power_up(struct twl6040 *twl6040) | 106 | static int twl6040_power_up_manual(struct twl6040 *twl6040) |
108 | { | 107 | { |
109 | u8 ldoctl, ncpctl, lppllctl; | 108 | u8 ldoctl, ncpctl, lppllctl; |
110 | int ret; | 109 | int ret; |
@@ -158,11 +157,12 @@ ncp_err: | |||
158 | ldoctl &= ~(TWL6040_HSLDOENA | TWL6040_REFENA | TWL6040_OSCENA); | 157 | ldoctl &= ~(TWL6040_HSLDOENA | TWL6040_REFENA | TWL6040_OSCENA); |
159 | twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl); | 158 | twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl); |
160 | 159 | ||
160 | dev_err(twl6040->dev, "manual power-up failed\n"); | ||
161 | return ret; | 161 | return ret; |
162 | } | 162 | } |
163 | 163 | ||
164 | /* twl6040 manual power-down sequence */ | 164 | /* twl6040 manual power-down sequence */ |
165 | static void twl6040_power_down(struct twl6040 *twl6040) | 165 | static void twl6040_power_down_manual(struct twl6040 *twl6040) |
166 | { | 166 | { |
167 | u8 ncpctl, ldoctl, lppllctl; | 167 | u8 ncpctl, ldoctl, lppllctl; |
168 | 168 | ||
@@ -192,45 +192,48 @@ static void twl6040_power_down(struct twl6040 *twl6040) | |||
192 | twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl); | 192 | twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl); |
193 | } | 193 | } |
194 | 194 | ||
195 | static irqreturn_t twl6040_naudint_handler(int irq, void *data) | 195 | static irqreturn_t twl6040_readyint_handler(int irq, void *data) |
196 | { | 196 | { |
197 | struct twl6040 *twl6040 = data; | 197 | struct twl6040 *twl6040 = data; |
198 | u8 intid, status; | ||
199 | 198 | ||
200 | intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID); | 199 | complete(&twl6040->ready); |
201 | 200 | ||
202 | if (intid & TWL6040_READYINT) | 201 | return IRQ_HANDLED; |
203 | complete(&twl6040->ready); | 202 | } |
204 | 203 | ||
205 | if (intid & TWL6040_THINT) { | 204 | static irqreturn_t twl6040_thint_handler(int irq, void *data) |
206 | status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS); | 205 | { |
207 | if (status & TWL6040_TSHUTDET) { | 206 | struct twl6040 *twl6040 = data; |
208 | dev_warn(twl6040->dev, | 207 | u8 status; |
209 | "Thermal shutdown, powering-off"); | 208 | |
210 | twl6040_power(twl6040, 0); | 209 | status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS); |
211 | } else { | 210 | if (status & TWL6040_TSHUTDET) { |
212 | dev_warn(twl6040->dev, | 211 | dev_warn(twl6040->dev, "Thermal shutdown, powering-off"); |
213 | "Leaving thermal shutdown, powering-on"); | 212 | twl6040_power(twl6040, 0); |
214 | twl6040_power(twl6040, 1); | 213 | } else { |
215 | } | 214 | dev_warn(twl6040->dev, "Leaving thermal shutdown, powering-on"); |
215 | twl6040_power(twl6040, 1); | ||
216 | } | 216 | } |
217 | 217 | ||
218 | return IRQ_HANDLED; | 218 | return IRQ_HANDLED; |
219 | } | 219 | } |
220 | 220 | ||
221 | static int twl6040_power_up_completion(struct twl6040 *twl6040, | 221 | static int twl6040_power_up_automatic(struct twl6040 *twl6040) |
222 | int naudint) | ||
223 | { | 222 | { |
224 | int time_left; | 223 | int time_left; |
225 | u8 intid; | 224 | |
225 | gpio_set_value(twl6040->audpwron, 1); | ||
226 | 226 | ||
227 | time_left = wait_for_completion_timeout(&twl6040->ready, | 227 | time_left = wait_for_completion_timeout(&twl6040->ready, |
228 | msecs_to_jiffies(144)); | 228 | msecs_to_jiffies(144)); |
229 | if (!time_left) { | 229 | if (!time_left) { |
230 | u8 intid; | ||
231 | |||
232 | dev_warn(twl6040->dev, "timeout waiting for READYINT\n"); | ||
230 | intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID); | 233 | intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID); |
231 | if (!(intid & TWL6040_READYINT)) { | 234 | if (!(intid & TWL6040_READYINT)) { |
232 | dev_err(twl6040->dev, | 235 | dev_err(twl6040->dev, "automatic power-up failed\n"); |
233 | "timeout waiting for READYINT\n"); | 236 | gpio_set_value(twl6040->audpwron, 0); |
234 | return -ETIMEDOUT; | 237 | return -ETIMEDOUT; |
235 | } | 238 | } |
236 | } | 239 | } |
@@ -240,8 +243,6 @@ static int twl6040_power_up_completion(struct twl6040 *twl6040, | |||
240 | 243 | ||
241 | int twl6040_power(struct twl6040 *twl6040, int on) | 244 | int twl6040_power(struct twl6040 *twl6040, int on) |
242 | { | 245 | { |
243 | int audpwron = twl6040->audpwron; | ||
244 | int naudint = twl6040->irq; | ||
245 | int ret = 0; | 246 | int ret = 0; |
246 | 247 | ||
247 | mutex_lock(&twl6040->mutex); | 248 | mutex_lock(&twl6040->mutex); |
@@ -251,23 +252,17 @@ int twl6040_power(struct twl6040 *twl6040, int on) | |||
251 | if (twl6040->power_count++) | 252 | if (twl6040->power_count++) |
252 | goto out; | 253 | goto out; |
253 | 254 | ||
254 | if (gpio_is_valid(audpwron)) { | 255 | if (gpio_is_valid(twl6040->audpwron)) { |
255 | /* use AUDPWRON line */ | 256 | /* use automatic power-up sequence */ |
256 | gpio_set_value(audpwron, 1); | 257 | ret = twl6040_power_up_automatic(twl6040); |
257 | /* wait for power-up completion */ | ||
258 | ret = twl6040_power_up_completion(twl6040, naudint); | ||
259 | if (ret) { | 258 | if (ret) { |
260 | dev_err(twl6040->dev, | ||
261 | "automatic power-down failed\n"); | ||
262 | twl6040->power_count = 0; | 259 | twl6040->power_count = 0; |
263 | goto out; | 260 | goto out; |
264 | } | 261 | } |
265 | } else { | 262 | } else { |
266 | /* use manual power-up sequence */ | 263 | /* use manual power-up sequence */ |
267 | ret = twl6040_power_up(twl6040); | 264 | ret = twl6040_power_up_manual(twl6040); |
268 | if (ret) { | 265 | if (ret) { |
269 | dev_err(twl6040->dev, | ||
270 | "manual power-up failed\n"); | ||
271 | twl6040->power_count = 0; | 266 | twl6040->power_count = 0; |
272 | goto out; | 267 | goto out; |
273 | } | 268 | } |
@@ -288,15 +283,15 @@ int twl6040_power(struct twl6040 *twl6040, int on) | |||
288 | if (--twl6040->power_count) | 283 | if (--twl6040->power_count) |
289 | goto out; | 284 | goto out; |
290 | 285 | ||
291 | if (gpio_is_valid(audpwron)) { | 286 | if (gpio_is_valid(twl6040->audpwron)) { |
292 | /* use AUDPWRON line */ | 287 | /* use AUDPWRON line */ |
293 | gpio_set_value(audpwron, 0); | 288 | gpio_set_value(twl6040->audpwron, 0); |
294 | 289 | ||
295 | /* power-down sequence latency */ | 290 | /* power-down sequence latency */ |
296 | usleep_range(500, 700); | 291 | usleep_range(500, 700); |
297 | } else { | 292 | } else { |
298 | /* use manual power-down sequence */ | 293 | /* use manual power-down sequence */ |
299 | twl6040_power_down(twl6040); | 294 | twl6040_power_down_manual(twl6040); |
300 | } | 295 | } |
301 | twl6040->sysclk = 0; | 296 | twl6040->sysclk = 0; |
302 | twl6040->mclk = 0; | 297 | twl6040->mclk = 0; |
@@ -503,6 +498,25 @@ static struct regmap_config twl6040_regmap_config = { | |||
503 | .readable_reg = twl6040_readable_reg, | 498 | .readable_reg = twl6040_readable_reg, |
504 | }; | 499 | }; |
505 | 500 | ||
501 | static const struct regmap_irq twl6040_irqs[] = { | ||
502 | { .reg_offset = 0, .mask = TWL6040_THINT, }, | ||
503 | { .reg_offset = 0, .mask = TWL6040_PLUGINT | TWL6040_UNPLUGINT, }, | ||
504 | { .reg_offset = 0, .mask = TWL6040_HOOKINT, }, | ||
505 | { .reg_offset = 0, .mask = TWL6040_HFINT, }, | ||
506 | { .reg_offset = 0, .mask = TWL6040_VIBINT, }, | ||
507 | { .reg_offset = 0, .mask = TWL6040_READYINT, }, | ||
508 | }; | ||
509 | |||
510 | static struct regmap_irq_chip twl6040_irq_chip = { | ||
511 | .name = "twl6040", | ||
512 | .irqs = twl6040_irqs, | ||
513 | .num_irqs = ARRAY_SIZE(twl6040_irqs), | ||
514 | |||
515 | .num_regs = 1, | ||
516 | .status_base = TWL6040_REG_INTID, | ||
517 | .mask_base = TWL6040_REG_INTMR, | ||
518 | }; | ||
519 | |||
506 | static int __devinit twl6040_probe(struct i2c_client *client, | 520 | static int __devinit twl6040_probe(struct i2c_client *client, |
507 | const struct i2c_device_id *id) | 521 | const struct i2c_device_id *id) |
508 | { | 522 | { |
@@ -578,18 +592,31 @@ static int __devinit twl6040_probe(struct i2c_client *client, | |||
578 | goto gpio_err; | 592 | goto gpio_err; |
579 | } | 593 | } |
580 | 594 | ||
581 | /* codec interrupt */ | 595 | ret = regmap_add_irq_chip(twl6040->regmap, twl6040->irq, |
582 | ret = twl6040_irq_init(twl6040); | 596 | IRQF_ONESHOT, 0, &twl6040_irq_chip, |
583 | if (ret) | 597 | &twl6040->irq_data); |
598 | if (ret < 0) | ||
584 | goto irq_init_err; | 599 | goto irq_init_err; |
585 | 600 | ||
586 | ret = request_threaded_irq(twl6040->irq_base + TWL6040_IRQ_READY, | 601 | twl6040->irq_ready = regmap_irq_get_virq(twl6040->irq_data, |
587 | NULL, twl6040_naudint_handler, IRQF_ONESHOT, | 602 | TWL6040_IRQ_READY); |
603 | twl6040->irq_th = regmap_irq_get_virq(twl6040->irq_data, | ||
604 | TWL6040_IRQ_TH); | ||
605 | |||
606 | ret = request_threaded_irq(twl6040->irq_ready, NULL, | ||
607 | twl6040_readyint_handler, IRQF_ONESHOT, | ||
588 | "twl6040_irq_ready", twl6040); | 608 | "twl6040_irq_ready", twl6040); |
589 | if (ret) { | 609 | if (ret) { |
590 | dev_err(twl6040->dev, "READY IRQ request failed: %d\n", | 610 | dev_err(twl6040->dev, "READY IRQ request failed: %d\n", ret); |
591 | ret); | 611 | goto readyirq_err; |
592 | goto irq_err; | 612 | } |
613 | |||
614 | ret = request_threaded_irq(twl6040->irq_th, NULL, | ||
615 | twl6040_thint_handler, IRQF_ONESHOT, | ||
616 | "twl6040_irq_th", twl6040); | ||
617 | if (ret) { | ||
618 | dev_err(twl6040->dev, "Thermal IRQ request failed: %d\n", ret); | ||
619 | goto thirq_err; | ||
593 | } | 620 | } |
594 | 621 | ||
595 | /* dual-access registers controlled by I2C only */ | 622 | /* dual-access registers controlled by I2C only */ |
@@ -601,7 +628,7 @@ static int __devinit twl6040_probe(struct i2c_client *client, | |||
601 | * The ASoC codec can work without pdata, pass the platform_data only if | 628 | * The ASoC codec can work without pdata, pass the platform_data only if |
602 | * it has been provided. | 629 | * it has been provided. |
603 | */ | 630 | */ |
604 | irq = twl6040->irq_base + TWL6040_IRQ_PLUG; | 631 | irq = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_PLUG); |
605 | cell = &twl6040->cells[children]; | 632 | cell = &twl6040->cells[children]; |
606 | cell->name = "twl6040-codec"; | 633 | cell->name = "twl6040-codec"; |
607 | twl6040_codec_rsrc[0].start = irq; | 634 | twl6040_codec_rsrc[0].start = irq; |
@@ -615,7 +642,7 @@ static int __devinit twl6040_probe(struct i2c_client *client, | |||
615 | children++; | 642 | children++; |
616 | 643 | ||
617 | if (twl6040_has_vibra(pdata, node)) { | 644 | if (twl6040_has_vibra(pdata, node)) { |
618 | irq = twl6040->irq_base + TWL6040_IRQ_VIB; | 645 | irq = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_VIB); |
619 | 646 | ||
620 | cell = &twl6040->cells[children]; | 647 | cell = &twl6040->cells[children]; |
621 | cell->name = "twl6040-vibra"; | 648 | cell->name = "twl6040-vibra"; |
@@ -654,9 +681,11 @@ static int __devinit twl6040_probe(struct i2c_client *client, | |||
654 | return 0; | 681 | return 0; |
655 | 682 | ||
656 | mfd_err: | 683 | mfd_err: |
657 | free_irq(twl6040->irq_base + TWL6040_IRQ_READY, twl6040); | 684 | free_irq(twl6040->irq_th, twl6040); |
658 | irq_err: | 685 | thirq_err: |
659 | twl6040_irq_exit(twl6040); | 686 | free_irq(twl6040->irq_ready, twl6040); |
687 | readyirq_err: | ||
688 | regmap_del_irq_chip(twl6040->irq, twl6040->irq_data); | ||
660 | irq_init_err: | 689 | irq_init_err: |
661 | if (gpio_is_valid(twl6040->audpwron)) | 690 | if (gpio_is_valid(twl6040->audpwron)) |
662 | gpio_free(twl6040->audpwron); | 691 | gpio_free(twl6040->audpwron); |
@@ -680,8 +709,9 @@ static int __devexit twl6040_remove(struct i2c_client *client) | |||
680 | if (gpio_is_valid(twl6040->audpwron)) | 709 | if (gpio_is_valid(twl6040->audpwron)) |
681 | gpio_free(twl6040->audpwron); | 710 | gpio_free(twl6040->audpwron); |
682 | 711 | ||
683 | free_irq(twl6040->irq_base + TWL6040_IRQ_READY, twl6040); | 712 | free_irq(twl6040->irq_ready, twl6040); |
684 | twl6040_irq_exit(twl6040); | 713 | free_irq(twl6040->irq_th, twl6040); |
714 | regmap_del_irq_chip(twl6040->irq, twl6040->irq_data); | ||
685 | 715 | ||
686 | mfd_remove_devices(&client->dev); | 716 | mfd_remove_devices(&client->dev); |
687 | i2c_set_clientdata(client, NULL); | 717 | i2c_set_clientdata(client, NULL); |
diff --git a/drivers/mfd/viperboard.c b/drivers/mfd/viperboard.c new file mode 100644 index 00000000000..af2a6703f34 --- /dev/null +++ b/drivers/mfd/viperboard.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * Nano River Technologies viperboard driver | ||
3 | * | ||
4 | * This is the core driver for the viperboard. There are cell drivers | ||
5 | * available for I2C, ADC and both GPIOs. SPI is not yet supported. | ||
6 | * The drivers do not support all features the board exposes. See user | ||
7 | * manual of the viperboard. | ||
8 | * | ||
9 | * (C) 2012 by Lemonage GmbH | ||
10 | * Author: Lars Poeschel <poeschel@lemonage.de> | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/types.h> | ||
25 | #include <linux/mutex.h> | ||
26 | |||
27 | #include <linux/mfd/core.h> | ||
28 | #include <linux/mfd/viperboard.h> | ||
29 | |||
30 | #include <linux/usb.h> | ||
31 | |||
32 | |||
33 | static const struct usb_device_id vprbrd_table[] = { | ||
34 | { USB_DEVICE(0x2058, 0x1005) }, /* Nano River Technologies */ | ||
35 | { } /* Terminating entry */ | ||
36 | }; | ||
37 | |||
38 | MODULE_DEVICE_TABLE(usb, vprbrd_table); | ||
39 | |||
40 | static struct mfd_cell vprbrd_devs[] = { | ||
41 | { | ||
42 | .name = "viperboard-gpio", | ||
43 | }, | ||
44 | { | ||
45 | .name = "viperboard-i2c", | ||
46 | }, | ||
47 | { | ||
48 | .name = "viperboard-adc", | ||
49 | }, | ||
50 | }; | ||
51 | |||
52 | static int vprbrd_probe(struct usb_interface *interface, | ||
53 | const struct usb_device_id *id) | ||
54 | { | ||
55 | struct vprbrd *vb; | ||
56 | |||
57 | u16 version = 0; | ||
58 | int pipe, ret; | ||
59 | |||
60 | /* allocate memory for our device state and initialize it */ | ||
61 | vb = kzalloc(sizeof(*vb), GFP_KERNEL); | ||
62 | if (vb == NULL) { | ||
63 | dev_err(&interface->dev, "Out of memory\n"); | ||
64 | return -ENOMEM; | ||
65 | } | ||
66 | |||
67 | mutex_init(&vb->lock); | ||
68 | |||
69 | vb->usb_dev = usb_get_dev(interface_to_usbdev(interface)); | ||
70 | |||
71 | /* save our data pointer in this interface device */ | ||
72 | usb_set_intfdata(interface, vb); | ||
73 | dev_set_drvdata(&vb->pdev.dev, vb); | ||
74 | |||
75 | /* get version information, major first, minor then */ | ||
76 | pipe = usb_rcvctrlpipe(vb->usb_dev, 0); | ||
77 | ret = usb_control_msg(vb->usb_dev, pipe, VPRBRD_USB_REQUEST_MAJOR, | ||
78 | VPRBRD_USB_TYPE_IN, 0x0000, 0x0000, vb->buf, 1, | ||
79 | VPRBRD_USB_TIMEOUT_MS); | ||
80 | if (ret == 1) | ||
81 | version = vb->buf[0]; | ||
82 | |||
83 | ret = usb_control_msg(vb->usb_dev, pipe, VPRBRD_USB_REQUEST_MINOR, | ||
84 | VPRBRD_USB_TYPE_IN, 0x0000, 0x0000, vb->buf, 1, | ||
85 | VPRBRD_USB_TIMEOUT_MS); | ||
86 | if (ret == 1) { | ||
87 | version <<= 8; | ||
88 | version = version | vb->buf[0]; | ||
89 | } | ||
90 | |||
91 | dev_info(&interface->dev, | ||
92 | "version %x.%02x found at bus %03d address %03d\n", | ||
93 | version >> 8, version & 0xff, | ||
94 | vb->usb_dev->bus->busnum, vb->usb_dev->devnum); | ||
95 | |||
96 | ret = mfd_add_devices(&interface->dev, -1, vprbrd_devs, | ||
97 | ARRAY_SIZE(vprbrd_devs), NULL, 0, NULL); | ||
98 | if (ret != 0) { | ||
99 | dev_err(&interface->dev, "Failed to add mfd devices to core."); | ||
100 | goto error; | ||
101 | } | ||
102 | |||
103 | return 0; | ||
104 | |||
105 | error: | ||
106 | if (vb) { | ||
107 | usb_put_dev(vb->usb_dev); | ||
108 | kfree(vb); | ||
109 | } | ||
110 | |||
111 | return ret; | ||
112 | } | ||
113 | |||
114 | static void vprbrd_disconnect(struct usb_interface *interface) | ||
115 | { | ||
116 | struct vprbrd *vb = usb_get_intfdata(interface); | ||
117 | |||
118 | mfd_remove_devices(&interface->dev); | ||
119 | usb_set_intfdata(interface, NULL); | ||
120 | usb_put_dev(vb->usb_dev); | ||
121 | kfree(vb); | ||
122 | |||
123 | dev_dbg(&interface->dev, "disconnected\n"); | ||
124 | } | ||
125 | |||
126 | static struct usb_driver vprbrd_driver = { | ||
127 | .name = "viperboard", | ||
128 | .probe = vprbrd_probe, | ||
129 | .disconnect = vprbrd_disconnect, | ||
130 | .id_table = vprbrd_table, | ||
131 | }; | ||
132 | |||
133 | module_usb_driver(vprbrd_driver); | ||
134 | |||
135 | MODULE_DESCRIPTION("Nano River Technologies viperboard mfd core driver"); | ||
136 | MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>"); | ||
137 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index 3141c4a173a..088872ab633 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c | |||
@@ -56,6 +56,18 @@ static const struct reg_default wm5102_reva_patch[] = { | |||
56 | { 0x80, 0x0000 }, | 56 | { 0x80, 0x0000 }, |
57 | }; | 57 | }; |
58 | 58 | ||
59 | static const struct reg_default wm5102_revb_patch[] = { | ||
60 | { 0x80, 0x0003 }, | ||
61 | { 0x081, 0xE022 }, | ||
62 | { 0x410, 0x6080 }, | ||
63 | { 0x418, 0x6080 }, | ||
64 | { 0x420, 0x6080 }, | ||
65 | { 0x428, 0xC000 }, | ||
66 | { 0x441, 0x8014 }, | ||
67 | { 0x458, 0x000b }, | ||
68 | { 0x80, 0x0000 }, | ||
69 | }; | ||
70 | |||
59 | /* We use a function so we can use ARRAY_SIZE() */ | 71 | /* We use a function so we can use ARRAY_SIZE() */ |
60 | int wm5102_patch(struct arizona *arizona) | 72 | int wm5102_patch(struct arizona *arizona) |
61 | { | 73 | { |
@@ -65,7 +77,9 @@ int wm5102_patch(struct arizona *arizona) | |||
65 | wm5102_reva_patch, | 77 | wm5102_reva_patch, |
66 | ARRAY_SIZE(wm5102_reva_patch)); | 78 | ARRAY_SIZE(wm5102_reva_patch)); |
67 | default: | 79 | default: |
68 | return 0; | 80 | return regmap_register_patch(arizona->regmap, |
81 | wm5102_revb_patch, | ||
82 | ARRAY_SIZE(wm5102_revb_patch)); | ||
69 | } | 83 | } |
70 | } | 84 | } |
71 | 85 | ||
@@ -291,6 +305,7 @@ static const struct reg_default wm5102_reg_default[] = { | |||
291 | { 0x000001AA, 0x0004 }, /* R426 - FLL2 GPIO Clock */ | 305 | { 0x000001AA, 0x0004 }, /* R426 - FLL2 GPIO Clock */ |
292 | { 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */ | 306 | { 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */ |
293 | { 0x00000210, 0x00D4 }, /* R528 - LDO1 Control 1 */ | 307 | { 0x00000210, 0x00D4 }, /* R528 - LDO1 Control 1 */ |
308 | { 0x00000212, 0x0001 }, /* R530 - LDO1 Control 2 */ | ||
294 | { 0x00000213, 0x0344 }, /* R531 - LDO2 Control 1 */ | 309 | { 0x00000213, 0x0344 }, /* R531 - LDO2 Control 1 */ |
295 | { 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */ | 310 | { 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */ |
296 | { 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */ | 311 | { 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */ |
@@ -1056,6 +1071,7 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) | |||
1056 | case ARIZONA_FLL1_CONTROL_5: | 1071 | case ARIZONA_FLL1_CONTROL_5: |
1057 | case ARIZONA_FLL1_CONTROL_6: | 1072 | case ARIZONA_FLL1_CONTROL_6: |
1058 | case ARIZONA_FLL1_LOOP_FILTER_TEST_1: | 1073 | case ARIZONA_FLL1_LOOP_FILTER_TEST_1: |
1074 | case ARIZONA_FLL1_NCO_TEST_0: | ||
1059 | case ARIZONA_FLL1_SYNCHRONISER_1: | 1075 | case ARIZONA_FLL1_SYNCHRONISER_1: |
1060 | case ARIZONA_FLL1_SYNCHRONISER_2: | 1076 | case ARIZONA_FLL1_SYNCHRONISER_2: |
1061 | case ARIZONA_FLL1_SYNCHRONISER_3: | 1077 | case ARIZONA_FLL1_SYNCHRONISER_3: |
@@ -1071,6 +1087,7 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) | |||
1071 | case ARIZONA_FLL2_CONTROL_5: | 1087 | case ARIZONA_FLL2_CONTROL_5: |
1072 | case ARIZONA_FLL2_CONTROL_6: | 1088 | case ARIZONA_FLL2_CONTROL_6: |
1073 | case ARIZONA_FLL2_LOOP_FILTER_TEST_1: | 1089 | case ARIZONA_FLL2_LOOP_FILTER_TEST_1: |
1090 | case ARIZONA_FLL2_NCO_TEST_0: | ||
1074 | case ARIZONA_FLL2_SYNCHRONISER_1: | 1091 | case ARIZONA_FLL2_SYNCHRONISER_1: |
1075 | case ARIZONA_FLL2_SYNCHRONISER_2: | 1092 | case ARIZONA_FLL2_SYNCHRONISER_2: |
1076 | case ARIZONA_FLL2_SYNCHRONISER_3: | 1093 | case ARIZONA_FLL2_SYNCHRONISER_3: |
@@ -1805,6 +1822,7 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) | |||
1805 | case ARIZONA_DSP1_CLOCKING_1: | 1822 | case ARIZONA_DSP1_CLOCKING_1: |
1806 | case ARIZONA_DSP1_STATUS_1: | 1823 | case ARIZONA_DSP1_STATUS_1: |
1807 | case ARIZONA_DSP1_STATUS_2: | 1824 | case ARIZONA_DSP1_STATUS_2: |
1825 | case ARIZONA_DSP1_STATUS_3: | ||
1808 | return true; | 1826 | return true; |
1809 | default: | 1827 | default: |
1810 | return false; | 1828 | return false; |
@@ -1813,15 +1831,23 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) | |||
1813 | 1831 | ||
1814 | static bool wm5102_volatile_register(struct device *dev, unsigned int reg) | 1832 | static bool wm5102_volatile_register(struct device *dev, unsigned int reg) |
1815 | { | 1833 | { |
1834 | if (reg > 0xffff) | ||
1835 | return true; | ||
1836 | |||
1816 | switch (reg) { | 1837 | switch (reg) { |
1817 | case ARIZONA_SOFTWARE_RESET: | 1838 | case ARIZONA_SOFTWARE_RESET: |
1818 | case ARIZONA_DEVICE_REVISION: | 1839 | case ARIZONA_DEVICE_REVISION: |
1819 | case ARIZONA_OUTPUT_STATUS_1: | 1840 | case ARIZONA_OUTPUT_STATUS_1: |
1841 | case ARIZONA_RAW_OUTPUT_STATUS_1: | ||
1842 | case ARIZONA_SLIMBUS_RX_PORT_STATUS: | ||
1843 | case ARIZONA_SLIMBUS_TX_PORT_STATUS: | ||
1820 | case ARIZONA_SAMPLE_RATE_1_STATUS: | 1844 | case ARIZONA_SAMPLE_RATE_1_STATUS: |
1821 | case ARIZONA_SAMPLE_RATE_2_STATUS: | 1845 | case ARIZONA_SAMPLE_RATE_2_STATUS: |
1822 | case ARIZONA_SAMPLE_RATE_3_STATUS: | 1846 | case ARIZONA_SAMPLE_RATE_3_STATUS: |
1823 | case ARIZONA_HAPTICS_STATUS: | 1847 | case ARIZONA_HAPTICS_STATUS: |
1824 | case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS: | 1848 | case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS: |
1849 | case ARIZONA_FLL1_NCO_TEST_0: | ||
1850 | case ARIZONA_FLL2_NCO_TEST_0: | ||
1825 | case ARIZONA_FX_CTRL2: | 1851 | case ARIZONA_FX_CTRL2: |
1826 | case ARIZONA_INTERRUPT_STATUS_1: | 1852 | case ARIZONA_INTERRUPT_STATUS_1: |
1827 | case ARIZONA_INTERRUPT_STATUS_2: | 1853 | case ARIZONA_INTERRUPT_STATUS_2: |
@@ -1847,6 +1873,7 @@ static bool wm5102_volatile_register(struct device *dev, unsigned int reg) | |||
1847 | case ARIZONA_AOD_IRQ_RAW_STATUS: | 1873 | case ARIZONA_AOD_IRQ_RAW_STATUS: |
1848 | case ARIZONA_DSP1_STATUS_1: | 1874 | case ARIZONA_DSP1_STATUS_1: |
1849 | case ARIZONA_DSP1_STATUS_2: | 1875 | case ARIZONA_DSP1_STATUS_2: |
1876 | case ARIZONA_DSP1_STATUS_3: | ||
1850 | case ARIZONA_HEADPHONE_DETECT_2: | 1877 | case ARIZONA_HEADPHONE_DETECT_2: |
1851 | case ARIZONA_MIC_DETECT_3: | 1878 | case ARIZONA_MIC_DETECT_3: |
1852 | return true; | 1879 | return true; |
@@ -1855,12 +1882,14 @@ static bool wm5102_volatile_register(struct device *dev, unsigned int reg) | |||
1855 | } | 1882 | } |
1856 | } | 1883 | } |
1857 | 1884 | ||
1885 | #define WM5102_MAX_REGISTER 0x1a8fff | ||
1886 | |||
1858 | const struct regmap_config wm5102_spi_regmap = { | 1887 | const struct regmap_config wm5102_spi_regmap = { |
1859 | .reg_bits = 32, | 1888 | .reg_bits = 32, |
1860 | .pad_bits = 16, | 1889 | .pad_bits = 16, |
1861 | .val_bits = 16, | 1890 | .val_bits = 16, |
1862 | 1891 | ||
1863 | .max_register = ARIZONA_DSP1_STATUS_2, | 1892 | .max_register = WM5102_MAX_REGISTER, |
1864 | .readable_reg = wm5102_readable_register, | 1893 | .readable_reg = wm5102_readable_register, |
1865 | .volatile_reg = wm5102_volatile_register, | 1894 | .volatile_reg = wm5102_volatile_register, |
1866 | 1895 | ||
@@ -1874,7 +1903,7 @@ const struct regmap_config wm5102_i2c_regmap = { | |||
1874 | .reg_bits = 32, | 1903 | .reg_bits = 32, |
1875 | .val_bits = 16, | 1904 | .val_bits = 16, |
1876 | 1905 | ||
1877 | .max_register = ARIZONA_DSP1_STATUS_2, | 1906 | .max_register = WM5102_MAX_REGISTER, |
1878 | .readable_reg = wm5102_readable_register, | 1907 | .readable_reg = wm5102_readable_register, |
1879 | .volatile_reg = wm5102_volatile_register, | 1908 | .volatile_reg = wm5102_volatile_register, |
1880 | 1909 | ||
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index bcb226ff9d2..57c488d42d3 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c | |||
@@ -535,11 +535,10 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) | |||
535 | break; | 535 | break; |
536 | case 2: | 536 | case 2: |
537 | case 3: | 537 | case 3: |
538 | default: | ||
538 | regmap_patch = wm8994_revc_patch; | 539 | regmap_patch = wm8994_revc_patch; |
539 | patch_regs = ARRAY_SIZE(wm8994_revc_patch); | 540 | patch_regs = ARRAY_SIZE(wm8994_revc_patch); |
540 | break; | 541 | break; |
541 | default: | ||
542 | break; | ||
543 | } | 542 | } |
544 | break; | 543 | break; |
545 | 544 | ||
@@ -558,17 +557,9 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) | |||
558 | /* Revision C did not change the relevant layer */ | 557 | /* Revision C did not change the relevant layer */ |
559 | if (wm8994->revision > 1) | 558 | if (wm8994->revision > 1) |
560 | wm8994->revision++; | 559 | wm8994->revision++; |
561 | switch (wm8994->revision) { | 560 | |
562 | case 0: | 561 | regmap_patch = wm1811_reva_patch; |
563 | case 1: | 562 | patch_regs = ARRAY_SIZE(wm1811_reva_patch); |
564 | case 2: | ||
565 | case 3: | ||
566 | regmap_patch = wm1811_reva_patch; | ||
567 | patch_regs = ARRAY_SIZE(wm1811_reva_patch); | ||
568 | break; | ||
569 | default: | ||
570 | break; | ||
571 | } | ||
572 | break; | 563 | break; |
573 | 564 | ||
574 | default: | 565 | default: |
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index b648058d718..e4e218c930b 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile | |||
@@ -49,6 +49,8 @@ obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o | |||
49 | 49 | ||
50 | obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o | 50 | obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o |
51 | 51 | ||
52 | obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o | ||
53 | |||
52 | obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o | 54 | obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o |
53 | obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o | 55 | obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o |
54 | obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o | 56 | obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o |
diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 12eff6f8cab..571915dfb21 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c | |||
@@ -21,6 +21,7 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/slab.h> | ||
24 | #include <linux/highmem.h> | 25 | #include <linux/highmem.h> |
25 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
26 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
@@ -382,8 +383,6 @@ static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) | |||
382 | 0xFF, (u8)data->blocks); | 383 | 0xFF, (u8)data->blocks); |
383 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, | 384 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, |
384 | 0xFF, (u8)(data->blocks >> 8)); | 385 | 0xFF, (u8)(data->blocks >> 8)); |
385 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
386 | CARD_DATA_SOURCE, 0x01, RING_BUFFER); | ||
387 | 386 | ||
388 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0, | 387 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0, |
389 | DMA_DONE_INT, DMA_DONE_INT); | 388 | DMA_DONE_INT, DMA_DONE_INT); |
@@ -407,6 +406,7 @@ static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) | |||
407 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, | 406 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, |
408 | 0x01, RING_BUFFER); | 407 | 0x01, RING_BUFFER); |
409 | 408 | ||
409 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, cfg2); | ||
410 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, | 410 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, |
411 | trans_mode | SD_TRANSFER_START); | 411 | trans_mode | SD_TRANSFER_START); |
412 | rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, | 412 | rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, |
diff --git a/drivers/power/da9052-battery.c b/drivers/power/da9052-battery.c index bb0df8917ad..3c5c2e459d7 100644 --- a/drivers/power/da9052-battery.c +++ b/drivers/power/da9052-battery.c | |||
@@ -440,8 +440,10 @@ static int da9052_bat_check_health(struct da9052_battery *bat, int *health) | |||
440 | static irqreturn_t da9052_bat_irq(int irq, void *data) | 440 | static irqreturn_t da9052_bat_irq(int irq, void *data) |
441 | { | 441 | { |
442 | struct da9052_battery *bat = data; | 442 | struct da9052_battery *bat = data; |
443 | int virq; | ||
443 | 444 | ||
444 | irq -= bat->da9052->irq_base; | 445 | virq = regmap_irq_get_virq(bat->da9052->irq_data, irq); |
446 | irq -= virq; | ||
445 | 447 | ||
446 | if (irq == DA9052_IRQ_CHGEND) | 448 | if (irq == DA9052_IRQ_CHGEND) |
447 | bat->status = POWER_SUPPLY_STATUS_FULL; | 449 | bat->status = POWER_SUPPLY_STATUS_FULL; |
@@ -567,7 +569,7 @@ static struct power_supply template_battery = { | |||
567 | .get_property = da9052_bat_get_property, | 569 | .get_property = da9052_bat_get_property, |
568 | }; | 570 | }; |
569 | 571 | ||
570 | static const char *const da9052_bat_irqs[] = { | 572 | static char *da9052_bat_irqs[] = { |
571 | "BATT TEMP", | 573 | "BATT TEMP", |
572 | "DCIN DET", | 574 | "DCIN DET", |
573 | "DCIN REM", | 575 | "DCIN REM", |
@@ -576,12 +578,20 @@ static const char *const da9052_bat_irqs[] = { | |||
576 | "CHG END", | 578 | "CHG END", |
577 | }; | 579 | }; |
578 | 580 | ||
581 | static int da9052_bat_irq_bits[] = { | ||
582 | DA9052_IRQ_TBAT, | ||
583 | DA9052_IRQ_DCIN, | ||
584 | DA9052_IRQ_DCINREM, | ||
585 | DA9052_IRQ_VBUS, | ||
586 | DA9052_IRQ_VBUSREM, | ||
587 | DA9052_IRQ_CHGEND, | ||
588 | }; | ||
589 | |||
579 | static s32 da9052_bat_probe(struct platform_device *pdev) | 590 | static s32 da9052_bat_probe(struct platform_device *pdev) |
580 | { | 591 | { |
581 | struct da9052_pdata *pdata; | 592 | struct da9052_pdata *pdata; |
582 | struct da9052_battery *bat; | 593 | struct da9052_battery *bat; |
583 | int ret; | 594 | int ret; |
584 | int irq; | ||
585 | int i; | 595 | int i; |
586 | 596 | ||
587 | bat = kzalloc(sizeof(struct da9052_battery), GFP_KERNEL); | 597 | bat = kzalloc(sizeof(struct da9052_battery), GFP_KERNEL); |
@@ -602,15 +612,14 @@ static s32 da9052_bat_probe(struct platform_device *pdev) | |||
602 | bat->psy.use_for_apm = 1; | 612 | bat->psy.use_for_apm = 1; |
603 | 613 | ||
604 | for (i = 0; i < ARRAY_SIZE(da9052_bat_irqs); i++) { | 614 | for (i = 0; i < ARRAY_SIZE(da9052_bat_irqs); i++) { |
605 | irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]); | 615 | ret = da9052_request_irq(bat->da9052, |
606 | ret = request_threaded_irq(bat->da9052->irq_base + irq, | 616 | da9052_bat_irq_bits[i], da9052_bat_irqs[i], |
607 | NULL, da9052_bat_irq, | 617 | da9052_bat_irq, bat); |
608 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | 618 | |
609 | da9052_bat_irqs[i], bat); | ||
610 | if (ret != 0) { | 619 | if (ret != 0) { |
611 | dev_err(bat->da9052->dev, | 620 | dev_err(bat->da9052->dev, |
612 | "DA9052 failed to request %s IRQ %d: %d\n", | 621 | "DA9052 failed to request %s IRQ: %d\n", |
613 | da9052_bat_irqs[i], irq, ret); | 622 | da9052_bat_irqs[i], ret); |
614 | goto err; | 623 | goto err; |
615 | } | 624 | } |
616 | } | 625 | } |
@@ -623,23 +632,20 @@ static s32 da9052_bat_probe(struct platform_device *pdev) | |||
623 | return 0; | 632 | return 0; |
624 | 633 | ||
625 | err: | 634 | err: |
626 | while (--i >= 0) { | 635 | while (--i >= 0) |
627 | irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]); | 636 | da9052_free_irq(bat->da9052, da9052_bat_irq_bits[i], bat); |
628 | free_irq(bat->da9052->irq_base + irq, bat); | 637 | |
629 | } | ||
630 | kfree(bat); | 638 | kfree(bat); |
631 | return ret; | 639 | return ret; |
632 | } | 640 | } |
633 | static int da9052_bat_remove(struct platform_device *pdev) | 641 | static int da9052_bat_remove(struct platform_device *pdev) |
634 | { | 642 | { |
635 | int i; | 643 | int i; |
636 | int irq; | ||
637 | struct da9052_battery *bat = platform_get_drvdata(pdev); | 644 | struct da9052_battery *bat = platform_get_drvdata(pdev); |
638 | 645 | ||
639 | for (i = 0; i < ARRAY_SIZE(da9052_bat_irqs); i++) { | 646 | for (i = 0; i < ARRAY_SIZE(da9052_bat_irqs); i++) |
640 | irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]); | 647 | da9052_free_irq(bat->da9052, da9052_bat_irq_bits[i], bat); |
641 | free_irq(bat->da9052->irq_base + irq, bat); | 648 | |
642 | } | ||
643 | power_supply_unregister(&bat->psy); | 649 | power_supply_unregister(&bat->psy); |
644 | kfree(bat); | 650 | kfree(bat); |
645 | 651 | ||
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 9277d945bf4..8b7464c8b5c 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c | |||
@@ -233,7 +233,7 @@ static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) | |||
233 | */ | 233 | */ |
234 | static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) | 234 | static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) |
235 | { | 235 | { |
236 | unsigned char rtc_data[ALL_TIME_REGS + 1]; | 236 | unsigned char rtc_data[ALL_TIME_REGS]; |
237 | int ret; | 237 | int ret; |
238 | u8 save_control; | 238 | u8 save_control; |
239 | u8 rtc_control; | 239 | u8 rtc_control; |
@@ -300,15 +300,15 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
300 | static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm) | 300 | static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm) |
301 | { | 301 | { |
302 | unsigned char save_control; | 302 | unsigned char save_control; |
303 | unsigned char rtc_data[ALL_TIME_REGS + 1]; | 303 | unsigned char rtc_data[ALL_TIME_REGS]; |
304 | int ret; | 304 | int ret; |
305 | 305 | ||
306 | rtc_data[1] = bin2bcd(tm->tm_sec); | 306 | rtc_data[0] = bin2bcd(tm->tm_sec); |
307 | rtc_data[2] = bin2bcd(tm->tm_min); | 307 | rtc_data[1] = bin2bcd(tm->tm_min); |
308 | rtc_data[3] = bin2bcd(tm->tm_hour); | 308 | rtc_data[2] = bin2bcd(tm->tm_hour); |
309 | rtc_data[4] = bin2bcd(tm->tm_mday); | 309 | rtc_data[3] = bin2bcd(tm->tm_mday); |
310 | rtc_data[5] = bin2bcd(tm->tm_mon + 1); | 310 | rtc_data[4] = bin2bcd(tm->tm_mon + 1); |
311 | rtc_data[6] = bin2bcd(tm->tm_year - 100); | 311 | rtc_data[5] = bin2bcd(tm->tm_year - 100); |
312 | 312 | ||
313 | /* Stop RTC while updating the TC registers */ | 313 | /* Stop RTC while updating the TC registers */ |
314 | ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); | 314 | ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); |
@@ -341,7 +341,7 @@ out: | |||
341 | */ | 341 | */ |
342 | static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) | 342 | static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) |
343 | { | 343 | { |
344 | unsigned char rtc_data[ALL_TIME_REGS + 1]; | 344 | unsigned char rtc_data[ALL_TIME_REGS]; |
345 | int ret; | 345 | int ret; |
346 | 346 | ||
347 | ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, | 347 | ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, |
@@ -368,19 +368,19 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) | |||
368 | 368 | ||
369 | static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) | 369 | static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) |
370 | { | 370 | { |
371 | unsigned char alarm_data[ALL_TIME_REGS + 1]; | 371 | unsigned char alarm_data[ALL_TIME_REGS]; |
372 | int ret; | 372 | int ret; |
373 | 373 | ||
374 | ret = twl_rtc_alarm_irq_enable(dev, 0); | 374 | ret = twl_rtc_alarm_irq_enable(dev, 0); |
375 | if (ret) | 375 | if (ret) |
376 | goto out; | 376 | goto out; |
377 | 377 | ||
378 | alarm_data[1] = bin2bcd(alm->time.tm_sec); | 378 | alarm_data[0] = bin2bcd(alm->time.tm_sec); |
379 | alarm_data[2] = bin2bcd(alm->time.tm_min); | 379 | alarm_data[1] = bin2bcd(alm->time.tm_min); |
380 | alarm_data[3] = bin2bcd(alm->time.tm_hour); | 380 | alarm_data[2] = bin2bcd(alm->time.tm_hour); |
381 | alarm_data[4] = bin2bcd(alm->time.tm_mday); | 381 | alarm_data[3] = bin2bcd(alm->time.tm_mday); |
382 | alarm_data[5] = bin2bcd(alm->time.tm_mon + 1); | 382 | alarm_data[4] = bin2bcd(alm->time.tm_mon + 1); |
383 | alarm_data[6] = bin2bcd(alm->time.tm_year - 100); | 383 | alarm_data[5] = bin2bcd(alm->time.tm_year - 100); |
384 | 384 | ||
385 | /* update all the alarm registers in one shot */ | 385 | /* update all the alarm registers in one shot */ |
386 | ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data, | 386 | ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data, |