diff options
Diffstat (limited to 'drivers/mfd')
32 files changed, 3693 insertions, 1721 deletions
diff --git a/drivers/mfd/88pm8607.c b/drivers/mfd/88pm8607.c new file mode 100644 index 000000000000..7e3f65907993 --- /dev/null +++ b/drivers/mfd/88pm8607.c | |||
@@ -0,0 +1,302 @@ | |||
1 | /* | ||
2 | * Base driver for Marvell 88PM8607 | ||
3 | * | ||
4 | * Copyright (C) 2009 Marvell International Ltd. | ||
5 | * Haojian Zhuang <haojian.zhuang@marvell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/mfd/core.h> | ||
18 | #include <linux/mfd/88pm8607.h> | ||
19 | |||
20 | |||
21 | #define PM8607_REG_RESOURCE(_start, _end) \ | ||
22 | { \ | ||
23 | .start = PM8607_##_start, \ | ||
24 | .end = PM8607_##_end, \ | ||
25 | .flags = IORESOURCE_IO, \ | ||
26 | } | ||
27 | |||
28 | static struct resource pm8607_regulator_resources[] = { | ||
29 | PM8607_REG_RESOURCE(BUCK1, BUCK1), | ||
30 | PM8607_REG_RESOURCE(BUCK2, BUCK2), | ||
31 | PM8607_REG_RESOURCE(BUCK3, BUCK3), | ||
32 | PM8607_REG_RESOURCE(LDO1, LDO1), | ||
33 | PM8607_REG_RESOURCE(LDO2, LDO2), | ||
34 | PM8607_REG_RESOURCE(LDO3, LDO3), | ||
35 | PM8607_REG_RESOURCE(LDO4, LDO4), | ||
36 | PM8607_REG_RESOURCE(LDO5, LDO5), | ||
37 | PM8607_REG_RESOURCE(LDO6, LDO6), | ||
38 | PM8607_REG_RESOURCE(LDO7, LDO7), | ||
39 | PM8607_REG_RESOURCE(LDO8, LDO8), | ||
40 | PM8607_REG_RESOURCE(LDO9, LDO9), | ||
41 | PM8607_REG_RESOURCE(LDO10, LDO10), | ||
42 | PM8607_REG_RESOURCE(LDO12, LDO12), | ||
43 | PM8607_REG_RESOURCE(LDO14, LDO14), | ||
44 | }; | ||
45 | |||
46 | #define PM8607_REG_DEVS(_name, _id) \ | ||
47 | { \ | ||
48 | .name = "88pm8607-" #_name, \ | ||
49 | .num_resources = 1, \ | ||
50 | .resources = &pm8607_regulator_resources[PM8607_ID_##_id], \ | ||
51 | } | ||
52 | |||
53 | static struct mfd_cell pm8607_devs[] = { | ||
54 | PM8607_REG_DEVS(buck1, BUCK1), | ||
55 | PM8607_REG_DEVS(buck2, BUCK2), | ||
56 | PM8607_REG_DEVS(buck3, BUCK3), | ||
57 | PM8607_REG_DEVS(ldo1, LDO1), | ||
58 | PM8607_REG_DEVS(ldo2, LDO2), | ||
59 | PM8607_REG_DEVS(ldo3, LDO3), | ||
60 | PM8607_REG_DEVS(ldo4, LDO4), | ||
61 | PM8607_REG_DEVS(ldo5, LDO5), | ||
62 | PM8607_REG_DEVS(ldo6, LDO6), | ||
63 | PM8607_REG_DEVS(ldo7, LDO7), | ||
64 | PM8607_REG_DEVS(ldo8, LDO8), | ||
65 | PM8607_REG_DEVS(ldo9, LDO9), | ||
66 | PM8607_REG_DEVS(ldo10, LDO10), | ||
67 | PM8607_REG_DEVS(ldo12, LDO12), | ||
68 | PM8607_REG_DEVS(ldo14, LDO14), | ||
69 | }; | ||
70 | |||
71 | static inline int pm8607_read_device(struct pm8607_chip *chip, | ||
72 | int reg, int bytes, void *dest) | ||
73 | { | ||
74 | struct i2c_client *i2c = chip->client; | ||
75 | unsigned char data; | ||
76 | int ret; | ||
77 | |||
78 | data = (unsigned char)reg; | ||
79 | ret = i2c_master_send(i2c, &data, 1); | ||
80 | if (ret < 0) | ||
81 | return ret; | ||
82 | |||
83 | ret = i2c_master_recv(i2c, dest, bytes); | ||
84 | if (ret < 0) | ||
85 | return ret; | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static inline int pm8607_write_device(struct pm8607_chip *chip, | ||
90 | int reg, int bytes, void *src) | ||
91 | { | ||
92 | struct i2c_client *i2c = chip->client; | ||
93 | unsigned char buf[bytes + 1]; | ||
94 | int ret; | ||
95 | |||
96 | buf[0] = (unsigned char)reg; | ||
97 | memcpy(&buf[1], src, bytes); | ||
98 | |||
99 | ret = i2c_master_send(i2c, buf, bytes + 1); | ||
100 | if (ret < 0) | ||
101 | return ret; | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | int pm8607_reg_read(struct pm8607_chip *chip, int reg) | ||
106 | { | ||
107 | unsigned char data; | ||
108 | int ret; | ||
109 | |||
110 | mutex_lock(&chip->io_lock); | ||
111 | ret = chip->read(chip, reg, 1, &data); | ||
112 | mutex_unlock(&chip->io_lock); | ||
113 | |||
114 | if (ret < 0) | ||
115 | return ret; | ||
116 | else | ||
117 | return (int)data; | ||
118 | } | ||
119 | EXPORT_SYMBOL(pm8607_reg_read); | ||
120 | |||
121 | int pm8607_reg_write(struct pm8607_chip *chip, int reg, | ||
122 | unsigned char data) | ||
123 | { | ||
124 | int ret; | ||
125 | |||
126 | mutex_lock(&chip->io_lock); | ||
127 | ret = chip->write(chip, reg, 1, &data); | ||
128 | mutex_unlock(&chip->io_lock); | ||
129 | |||
130 | return ret; | ||
131 | } | ||
132 | EXPORT_SYMBOL(pm8607_reg_write); | ||
133 | |||
134 | int pm8607_bulk_read(struct pm8607_chip *chip, int reg, | ||
135 | int count, unsigned char *buf) | ||
136 | { | ||
137 | int ret; | ||
138 | |||
139 | mutex_lock(&chip->io_lock); | ||
140 | ret = chip->read(chip, reg, count, buf); | ||
141 | mutex_unlock(&chip->io_lock); | ||
142 | |||
143 | return ret; | ||
144 | } | ||
145 | EXPORT_SYMBOL(pm8607_bulk_read); | ||
146 | |||
147 | int pm8607_bulk_write(struct pm8607_chip *chip, int reg, | ||
148 | int count, unsigned char *buf) | ||
149 | { | ||
150 | int ret; | ||
151 | |||
152 | mutex_lock(&chip->io_lock); | ||
153 | ret = chip->write(chip, reg, count, buf); | ||
154 | mutex_unlock(&chip->io_lock); | ||
155 | |||
156 | return ret; | ||
157 | } | ||
158 | EXPORT_SYMBOL(pm8607_bulk_write); | ||
159 | |||
160 | int pm8607_set_bits(struct pm8607_chip *chip, int reg, | ||
161 | unsigned char mask, unsigned char data) | ||
162 | { | ||
163 | unsigned char value; | ||
164 | int ret; | ||
165 | |||
166 | mutex_lock(&chip->io_lock); | ||
167 | ret = chip->read(chip, reg, 1, &value); | ||
168 | if (ret < 0) | ||
169 | goto out; | ||
170 | value &= ~mask; | ||
171 | value |= data; | ||
172 | ret = chip->write(chip, reg, 1, &value); | ||
173 | out: | ||
174 | mutex_unlock(&chip->io_lock); | ||
175 | return ret; | ||
176 | } | ||
177 | EXPORT_SYMBOL(pm8607_set_bits); | ||
178 | |||
179 | |||
180 | static const struct i2c_device_id pm8607_id_table[] = { | ||
181 | { "88PM8607", 0 }, | ||
182 | {} | ||
183 | }; | ||
184 | MODULE_DEVICE_TABLE(i2c, pm8607_id_table); | ||
185 | |||
186 | |||
187 | static int __devinit pm8607_probe(struct i2c_client *client, | ||
188 | const struct i2c_device_id *id) | ||
189 | { | ||
190 | struct pm8607_platform_data *pdata = client->dev.platform_data; | ||
191 | struct pm8607_chip *chip; | ||
192 | int i, count; | ||
193 | int ret; | ||
194 | |||
195 | chip = kzalloc(sizeof(struct pm8607_chip), GFP_KERNEL); | ||
196 | if (chip == NULL) | ||
197 | return -ENOMEM; | ||
198 | |||
199 | chip->client = client; | ||
200 | chip->dev = &client->dev; | ||
201 | chip->read = pm8607_read_device; | ||
202 | chip->write = pm8607_write_device; | ||
203 | i2c_set_clientdata(client, chip); | ||
204 | |||
205 | mutex_init(&chip->io_lock); | ||
206 | dev_set_drvdata(chip->dev, chip); | ||
207 | |||
208 | ret = pm8607_reg_read(chip, PM8607_CHIP_ID); | ||
209 | if (ret < 0) { | ||
210 | dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret); | ||
211 | goto out; | ||
212 | } | ||
213 | if ((ret & CHIP_ID_MASK) == CHIP_ID) | ||
214 | dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n", | ||
215 | ret); | ||
216 | else { | ||
217 | dev_err(chip->dev, "Failed to detect Marvell 88PM8607. " | ||
218 | "Chip ID: %02x\n", ret); | ||
219 | goto out; | ||
220 | } | ||
221 | chip->chip_id = ret; | ||
222 | |||
223 | ret = pm8607_reg_read(chip, PM8607_BUCK3); | ||
224 | if (ret < 0) { | ||
225 | dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret); | ||
226 | goto out; | ||
227 | } | ||
228 | if (ret & PM8607_BUCK3_DOUBLE) | ||
229 | chip->buck3_double = 1; | ||
230 | |||
231 | ret = pm8607_reg_read(chip, PM8607_MISC1); | ||
232 | if (ret < 0) { | ||
233 | dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret); | ||
234 | goto out; | ||
235 | } | ||
236 | if (pdata->i2c_port == PI2C_PORT) | ||
237 | ret |= PM8607_MISC1_PI2C; | ||
238 | else | ||
239 | ret &= ~PM8607_MISC1_PI2C; | ||
240 | ret = pm8607_reg_write(chip, PM8607_MISC1, ret); | ||
241 | if (ret < 0) { | ||
242 | dev_err(chip->dev, "Failed to write MISC1 register: %d\n", ret); | ||
243 | goto out; | ||
244 | } | ||
245 | |||
246 | |||
247 | count = ARRAY_SIZE(pm8607_devs); | ||
248 | for (i = 0; i < count; i++) { | ||
249 | ret = mfd_add_devices(chip->dev, i, &pm8607_devs[i], | ||
250 | 1, NULL, 0); | ||
251 | if (ret != 0) { | ||
252 | dev_err(chip->dev, "Failed to add subdevs\n"); | ||
253 | goto out; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | return 0; | ||
258 | |||
259 | out: | ||
260 | i2c_set_clientdata(client, NULL); | ||
261 | kfree(chip); | ||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | static int __devexit pm8607_remove(struct i2c_client *client) | ||
266 | { | ||
267 | struct pm8607_chip *chip = i2c_get_clientdata(client); | ||
268 | |||
269 | mfd_remove_devices(chip->dev); | ||
270 | kfree(chip); | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static struct i2c_driver pm8607_driver = { | ||
275 | .driver = { | ||
276 | .name = "88PM8607", | ||
277 | .owner = THIS_MODULE, | ||
278 | }, | ||
279 | .probe = pm8607_probe, | ||
280 | .remove = __devexit_p(pm8607_remove), | ||
281 | .id_table = pm8607_id_table, | ||
282 | }; | ||
283 | |||
284 | static int __init pm8607_init(void) | ||
285 | { | ||
286 | int ret; | ||
287 | ret = i2c_add_driver(&pm8607_driver); | ||
288 | if (ret != 0) | ||
289 | pr_err("Failed to register 88PM8607 I2C driver: %d\n", ret); | ||
290 | return ret; | ||
291 | } | ||
292 | subsys_initcall(pm8607_init); | ||
293 | |||
294 | static void __exit pm8607_exit(void) | ||
295 | { | ||
296 | i2c_del_driver(&pm8607_driver); | ||
297 | } | ||
298 | module_exit(pm8607_exit); | ||
299 | |||
300 | MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM8607"); | ||
301 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); | ||
302 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 570be139f9df..87829789243e 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -35,6 +35,14 @@ config MFD_ASIC3 | |||
35 | This driver supports the ASIC3 multifunction chip found on many | 35 | This driver supports the ASIC3 multifunction chip found on many |
36 | PDAs (mainly iPAQ and HTC based ones) | 36 | PDAs (mainly iPAQ and HTC based ones) |
37 | 37 | ||
38 | config MFD_SH_MOBILE_SDHI | ||
39 | bool "Support for SuperH Mobile SDHI" | ||
40 | depends on SUPERH | ||
41 | select MFD_CORE | ||
42 | ---help--- | ||
43 | This driver supports the SDHI hardware block found in many | ||
44 | SuperH Mobile SoCs. | ||
45 | |||
38 | config MFD_DM355EVM_MSP | 46 | config MFD_DM355EVM_MSP |
39 | bool "DaVinci DM355 EVM microcontroller" | 47 | bool "DaVinci DM355 EVM microcontroller" |
40 | depends on I2C && MACH_DAVINCI_DM355_EVM | 48 | depends on I2C && MACH_DAVINCI_DM355_EVM |
@@ -95,10 +103,10 @@ config MENELAUS | |||
95 | cell phones and PDAs. | 103 | cell phones and PDAs. |
96 | 104 | ||
97 | config TWL4030_CORE | 105 | config TWL4030_CORE |
98 | bool "Texas Instruments TWL4030/TPS659x0 Support" | 106 | bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" |
99 | depends on I2C=y && GENERIC_HARDIRQS | 107 | depends on I2C=y && GENERIC_HARDIRQS |
100 | help | 108 | help |
101 | Say yes here if you have TWL4030 family chip on your board. | 109 | Say yes here if you have TWL4030 / TWL6030 family chip on your board. |
102 | This core driver provides register access and IRQ handling | 110 | This core driver provides register access and IRQ handling |
103 | facilities, and registers devices for the various functions | 111 | facilities, and registers devices for the various functions |
104 | so that function-specific drivers can bind to them. | 112 | so that function-specific drivers can bind to them. |
@@ -121,6 +129,12 @@ config TWL4030_POWER | |||
121 | and load scripts controling which resources are switched off/on | 129 | and load scripts controling which resources are switched off/on |
122 | or reset when a sleep, wakeup or warm reset event occurs. | 130 | or reset when a sleep, wakeup or warm reset event occurs. |
123 | 131 | ||
132 | config TWL4030_CODEC | ||
133 | bool | ||
134 | depends on TWL4030_CORE | ||
135 | select MFD_CORE | ||
136 | default n | ||
137 | |||
124 | config MFD_TMIO | 138 | config MFD_TMIO |
125 | bool | 139 | bool |
126 | default n | 140 | default n |
@@ -160,6 +174,16 @@ config PMIC_DA903X | |||
160 | individual components like LCD backlight, voltage regulators, | 174 | individual components like LCD backlight, voltage regulators, |
161 | LEDs and battery-charger under the corresponding menus. | 175 | LEDs and battery-charger under the corresponding menus. |
162 | 176 | ||
177 | config PMIC_ADP5520 | ||
178 | bool "Analog Devices ADP5520/01 MFD PMIC Core Support" | ||
179 | depends on I2C=y | ||
180 | help | ||
181 | Say yes here to add support for Analog Devices AD5520 and ADP5501, | ||
182 | Multifunction Power Management IC. This includes | ||
183 | the I2C driver and the core APIs _only_, you have to select | ||
184 | individual components like LCD backlight, LEDs, GPIOs and Kepad | ||
185 | under the corresponding menus. | ||
186 | |||
163 | config MFD_WM8400 | 187 | config MFD_WM8400 |
164 | tristate "Support Wolfson Microelectronics WM8400" | 188 | tristate "Support Wolfson Microelectronics WM8400" |
165 | select MFD_CORE | 189 | select MFD_CORE |
@@ -171,12 +195,12 @@ config MFD_WM8400 | |||
171 | the functionality of the device. | 195 | the functionality of the device. |
172 | 196 | ||
173 | config MFD_WM831X | 197 | config MFD_WM831X |
174 | tristate "Support Wolfson Microelectronics WM831x PMICs" | 198 | bool "Support Wolfson Microelectronics WM831x/2x PMICs" |
175 | select MFD_CORE | 199 | select MFD_CORE |
176 | depends on I2C | 200 | depends on I2C=y |
177 | help | 201 | help |
178 | Support for the Wolfson Microelecronics WM831x PMICs. This | 202 | Support for the Wolfson Microelecronics WM831x and WM832x PMICs. |
179 | driver provides common support for accessing the device, | 203 | This driver provides common support for accessing the device, |
180 | additional drivers must be enabled in order to use the | 204 | additional drivers must be enabled in order to use the |
181 | functionality of the device. | 205 | functionality of the device. |
182 | 206 | ||
@@ -305,6 +329,25 @@ config EZX_PCAP | |||
305 | This enables the PCAP ASIC present on EZX Phones. This is | 329 | This enables the PCAP ASIC present on EZX Phones. This is |
306 | needed for MMC, TouchScreen, Sound, USB, etc.. | 330 | needed for MMC, TouchScreen, Sound, USB, etc.. |
307 | 331 | ||
332 | config MFD_88PM8607 | ||
333 | bool "Support Marvell 88PM8607" | ||
334 | depends on I2C=y | ||
335 | select MFD_CORE | ||
336 | help | ||
337 | This supports for Marvell 88PM8607 Power Management IC. This includes | ||
338 | the I2C driver and the core APIs _only_, you have to select | ||
339 | individual components like voltage regulators, RTC and | ||
340 | battery-charger under the corresponding menus. | ||
341 | |||
342 | config AB4500_CORE | ||
343 | tristate "ST-Ericsson's AB4500 Mixed Signal Power management chip" | ||
344 | depends on SPI | ||
345 | help | ||
346 | Select this option to enable access to AB4500 power management | ||
347 | chip. This connects to U8500 on the SSP/SPI bus and exports | ||
348 | read/write functions for the devices to get access to this chip. | ||
349 | This chip embeds various other multimedia funtionalities as well. | ||
350 | |||
308 | endmenu | 351 | endmenu |
309 | 352 | ||
310 | menu "Multimedia Capabilities Port drivers" | 353 | menu "Multimedia Capabilities Port drivers" |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index f3b277b90d40..ca2f2c4ff05e 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_MFD_SM501) += sm501.o | 5 | obj-$(CONFIG_MFD_SM501) += sm501.o |
6 | obj-$(CONFIG_MFD_ASIC3) += asic3.o | 6 | obj-$(CONFIG_MFD_ASIC3) += asic3.o |
7 | obj-$(CONFIG_MFD_SH_MOBILE_SDHI) += sh_mobile_sdhi.o | ||
7 | 8 | ||
8 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o | 9 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o |
9 | obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o | 10 | obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o |
@@ -18,14 +19,16 @@ obj-$(CONFIG_MFD_WM8400) += wm8400-core.o | |||
18 | wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o | 19 | wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o |
19 | obj-$(CONFIG_MFD_WM831X) += wm831x.o | 20 | obj-$(CONFIG_MFD_WM831X) += wm831x.o |
20 | wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o | 21 | wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o |
22 | wm8350-objs += wm8350-irq.o | ||
21 | obj-$(CONFIG_MFD_WM8350) += wm8350.o | 23 | obj-$(CONFIG_MFD_WM8350) += wm8350.o |
22 | obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o | 24 | obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o |
23 | 25 | ||
24 | obj-$(CONFIG_TPS65010) += tps65010.o | 26 | obj-$(CONFIG_TPS65010) += tps65010.o |
25 | obj-$(CONFIG_MENELAUS) += menelaus.o | 27 | obj-$(CONFIG_MENELAUS) += menelaus.o |
26 | 28 | ||
27 | obj-$(CONFIG_TWL4030_CORE) += twl4030-core.o twl4030-irq.o | 29 | obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o |
28 | obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o | 30 | obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o |
31 | obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o | ||
29 | 32 | ||
30 | obj-$(CONFIG_MFD_MC13783) += mc13783-core.o | 33 | obj-$(CONFIG_MFD_MC13783) += mc13783-core.o |
31 | 34 | ||
@@ -50,3 +53,6 @@ obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o | |||
50 | obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o | 53 | obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o |
51 | obj-$(CONFIG_AB3100_CORE) += ab3100-core.o | 54 | obj-$(CONFIG_AB3100_CORE) += ab3100-core.o |
52 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o | 55 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o |
56 | obj-$(CONFIG_AB4500_CORE) += ab4500-core.o | ||
57 | obj-$(CONFIG_MFD_88PM8607) += 88pm8607.o | ||
58 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o \ No newline at end of file | ||
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 613481028272..fd42a80e7bf9 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c | |||
@@ -900,9 +900,6 @@ static int __init ab3100_probe(struct i2c_client *client, | |||
900 | goto exit_no_testreg_client; | 900 | goto exit_no_testreg_client; |
901 | } | 901 | } |
902 | 902 | ||
903 | strlcpy(ab3100->testreg_client->name, id->name, | ||
904 | sizeof(ab3100->testreg_client->name)); | ||
905 | |||
906 | err = ab3100_setup(ab3100); | 903 | err = ab3100_setup(ab3100); |
907 | if (err) | 904 | if (err) |
908 | goto exit_no_setup; | 905 | goto exit_no_setup; |
diff --git a/drivers/mfd/ab4500-core.c b/drivers/mfd/ab4500-core.c new file mode 100644 index 000000000000..1c44c19e073a --- /dev/null +++ b/drivers/mfd/ab4500-core.c | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 ST-Ericsson | ||
3 | * | ||
4 | * Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it | ||
7 | * and/or modify it under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * AB4500 is a companion power management chip used with U8500. | ||
11 | * On this platform, this is interfaced with SSP0 controller | ||
12 | * which is a ARM primecell pl022. | ||
13 | * | ||
14 | * At the moment the module just exports read/write features. | ||
15 | * Interrupt management to be added - TODO. | ||
16 | */ | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/spi/spi.h> | ||
22 | #include <linux/mfd/ab4500.h> | ||
23 | |||
24 | /* just required if probe fails, we need to | ||
25 | * unregister the device | ||
26 | */ | ||
27 | static struct spi_driver ab4500_driver; | ||
28 | |||
29 | /* | ||
30 | * This funtion writes to any AB4500 registers using | ||
31 | * SPI protocol & before it writes it packs the data | ||
32 | * in the below 24 bit frame format | ||
33 | * | ||
34 | * *|------------------------------------| | ||
35 | * *| 23|22...18|17.......10|9|8|7......0| | ||
36 | * *| r/w bank adr data | | ||
37 | * * ------------------------------------ | ||
38 | * | ||
39 | * This function shouldn't be called from interrupt | ||
40 | * context | ||
41 | */ | ||
42 | int ab4500_write(struct ab4500 *ab4500, unsigned char block, | ||
43 | unsigned long addr, unsigned char data) | ||
44 | { | ||
45 | struct spi_transfer xfer; | ||
46 | struct spi_message msg; | ||
47 | int err; | ||
48 | unsigned long spi_data = | ||
49 | block << 18 | addr << 10 | data; | ||
50 | |||
51 | mutex_lock(&ab4500->lock); | ||
52 | ab4500->tx_buf[0] = spi_data; | ||
53 | ab4500->rx_buf[0] = 0; | ||
54 | |||
55 | xfer.tx_buf = ab4500->tx_buf; | ||
56 | xfer.rx_buf = NULL; | ||
57 | xfer.len = sizeof(unsigned long); | ||
58 | |||
59 | spi_message_init(&msg); | ||
60 | spi_message_add_tail(&xfer, &msg); | ||
61 | |||
62 | err = spi_sync(ab4500->spi, &msg); | ||
63 | mutex_unlock(&ab4500->lock); | ||
64 | |||
65 | return err; | ||
66 | } | ||
67 | EXPORT_SYMBOL(ab4500_write); | ||
68 | |||
69 | int ab4500_read(struct ab4500 *ab4500, unsigned char block, | ||
70 | unsigned long addr) | ||
71 | { | ||
72 | struct spi_transfer xfer; | ||
73 | struct spi_message msg; | ||
74 | unsigned long spi_data = | ||
75 | 1 << 23 | block << 18 | addr << 10; | ||
76 | |||
77 | mutex_lock(&ab4500->lock); | ||
78 | ab4500->tx_buf[0] = spi_data; | ||
79 | ab4500->rx_buf[0] = 0; | ||
80 | |||
81 | xfer.tx_buf = ab4500->tx_buf; | ||
82 | xfer.rx_buf = ab4500->rx_buf; | ||
83 | xfer.len = sizeof(unsigned long); | ||
84 | |||
85 | spi_message_init(&msg); | ||
86 | spi_message_add_tail(&xfer, &msg); | ||
87 | |||
88 | spi_sync(ab4500->spi, &msg); | ||
89 | mutex_unlock(&ab4500->lock); | ||
90 | |||
91 | return ab4500->rx_buf[0]; | ||
92 | } | ||
93 | EXPORT_SYMBOL(ab4500_read); | ||
94 | |||
95 | /* ref: ab3100 core */ | ||
96 | #define AB4500_DEVICE(devname, devid) \ | ||
97 | static struct platform_device ab4500_##devname##_device = { \ | ||
98 | .name = devid, \ | ||
99 | .id = -1, \ | ||
100 | } | ||
101 | |||
102 | /* list of childern devices of ab4500 - all are | ||
103 | * not populated here - TODO | ||
104 | */ | ||
105 | AB4500_DEVICE(charger, "ab4500-charger"); | ||
106 | AB4500_DEVICE(audio, "ab4500-audio"); | ||
107 | AB4500_DEVICE(usb, "ab4500-usb"); | ||
108 | AB4500_DEVICE(tvout, "ab4500-tvout"); | ||
109 | AB4500_DEVICE(sim, "ab4500-sim"); | ||
110 | AB4500_DEVICE(gpadc, "ab4500-gpadc"); | ||
111 | AB4500_DEVICE(clkmgt, "ab4500-clkmgt"); | ||
112 | AB4500_DEVICE(misc, "ab4500-misc"); | ||
113 | |||
114 | static struct platform_device *ab4500_platform_devs[] = { | ||
115 | &ab4500_charger_device, | ||
116 | &ab4500_audio_device, | ||
117 | &ab4500_usb_device, | ||
118 | &ab4500_tvout_device, | ||
119 | &ab4500_sim_device, | ||
120 | &ab4500_gpadc_device, | ||
121 | &ab4500_clkmgt_device, | ||
122 | &ab4500_misc_device, | ||
123 | }; | ||
124 | |||
125 | static int __init ab4500_probe(struct spi_device *spi) | ||
126 | { | ||
127 | struct ab4500 *ab4500; | ||
128 | unsigned char revision; | ||
129 | int err = 0; | ||
130 | int i; | ||
131 | |||
132 | ab4500 = kzalloc(sizeof *ab4500, GFP_KERNEL); | ||
133 | if (!ab4500) { | ||
134 | dev_err(&spi->dev, "could not allocate AB4500\n"); | ||
135 | err = -ENOMEM; | ||
136 | goto not_detect; | ||
137 | } | ||
138 | |||
139 | ab4500->spi = spi; | ||
140 | spi_set_drvdata(spi, ab4500); | ||
141 | |||
142 | mutex_init(&ab4500->lock); | ||
143 | |||
144 | /* read the revision register */ | ||
145 | revision = ab4500_read(ab4500, AB4500_MISC, AB4500_REV_REG); | ||
146 | |||
147 | /* revision id 0x0 is for early drop, 0x10 is for cut1.0 */ | ||
148 | if (revision == 0x0 || revision == 0x10) | ||
149 | dev_info(&spi->dev, "Detected chip: %s, revision = %x\n", | ||
150 | ab4500_driver.driver.name, revision); | ||
151 | else { | ||
152 | dev_err(&spi->dev, "unknown chip: 0x%x\n", revision); | ||
153 | goto not_detect; | ||
154 | } | ||
155 | |||
156 | for (i = 0; i < ARRAY_SIZE(ab4500_platform_devs); i++) { | ||
157 | ab4500_platform_devs[i]->dev.parent = | ||
158 | &spi->dev; | ||
159 | platform_set_drvdata(ab4500_platform_devs[i], ab4500); | ||
160 | } | ||
161 | |||
162 | /* register the ab4500 platform devices */ | ||
163 | platform_add_devices(ab4500_platform_devs, | ||
164 | ARRAY_SIZE(ab4500_platform_devs)); | ||
165 | |||
166 | return err; | ||
167 | |||
168 | not_detect: | ||
169 | spi_unregister_driver(&ab4500_driver); | ||
170 | kfree(ab4500); | ||
171 | return err; | ||
172 | } | ||
173 | |||
174 | static int __devexit ab4500_remove(struct spi_device *spi) | ||
175 | { | ||
176 | struct ab4500 *ab4500 = | ||
177 | spi_get_drvdata(spi); | ||
178 | |||
179 | kfree(ab4500); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static struct spi_driver ab4500_driver = { | ||
185 | .driver = { | ||
186 | .name = "ab4500", | ||
187 | .owner = THIS_MODULE, | ||
188 | }, | ||
189 | .probe = ab4500_probe, | ||
190 | .remove = __devexit_p(ab4500_remove) | ||
191 | }; | ||
192 | |||
193 | static int __devinit ab4500_init(void) | ||
194 | { | ||
195 | return spi_register_driver(&ab4500_driver); | ||
196 | } | ||
197 | |||
198 | static void __exit ab4500_exit(void) | ||
199 | { | ||
200 | spi_unregister_driver(&ab4500_driver); | ||
201 | } | ||
202 | |||
203 | subsys_initcall(ab4500_init); | ||
204 | module_exit(ab4500_exit); | ||
205 | |||
206 | MODULE_AUTHOR("Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com"); | ||
207 | MODULE_DESCRIPTION("AB4500 core driver"); | ||
208 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c new file mode 100644 index 000000000000..b26644772d02 --- /dev/null +++ b/drivers/mfd/adp5520.c | |||
@@ -0,0 +1,379 @@ | |||
1 | /* | ||
2 | * Base driver for Analog Devices ADP5520/ADP5501 MFD PMICs | ||
3 | * LCD Backlight: drivers/video/backlight/adp5520_bl | ||
4 | * LEDs : drivers/led/leds-adp5520 | ||
5 | * GPIO : drivers/gpio/adp5520-gpio (ADP5520 only) | ||
6 | * Keys : drivers/input/keyboard/adp5520-keys (ADP5520 only) | ||
7 | * | ||
8 | * Copyright 2009 Analog Devices Inc. | ||
9 | * | ||
10 | * Derived from da903x: | ||
11 | * Copyright (C) 2008 Compulab, Ltd. | ||
12 | * Mike Rapoport <mike@compulab.co.il> | ||
13 | * | ||
14 | * Copyright (C) 2006-2008 Marvell International Ltd. | ||
15 | * Eric Miao <eric.miao@marvell.com> | ||
16 | * | ||
17 | * Licensed under the GPL-2 or later. | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/irq.h> | ||
26 | #include <linux/err.h> | ||
27 | #include <linux/i2c.h> | ||
28 | |||
29 | #include <linux/mfd/adp5520.h> | ||
30 | |||
31 | struct adp5520_chip { | ||
32 | struct i2c_client *client; | ||
33 | struct device *dev; | ||
34 | struct mutex lock; | ||
35 | struct blocking_notifier_head notifier_list; | ||
36 | int irq; | ||
37 | unsigned long id; | ||
38 | }; | ||
39 | |||
40 | static int __adp5520_read(struct i2c_client *client, | ||
41 | int reg, uint8_t *val) | ||
42 | { | ||
43 | int ret; | ||
44 | |||
45 | ret = i2c_smbus_read_byte_data(client, reg); | ||
46 | if (ret < 0) { | ||
47 | dev_err(&client->dev, "failed reading at 0x%02x\n", reg); | ||
48 | return ret; | ||
49 | } | ||
50 | |||
51 | *val = (uint8_t)ret; | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static int __adp5520_write(struct i2c_client *client, | ||
56 | int reg, uint8_t val) | ||
57 | { | ||
58 | int ret; | ||
59 | |||
60 | ret = i2c_smbus_write_byte_data(client, reg, val); | ||
61 | if (ret < 0) { | ||
62 | dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n", | ||
63 | val, reg); | ||
64 | return ret; | ||
65 | } | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static int __adp5520_ack_bits(struct i2c_client *client, int reg, | ||
70 | uint8_t bit_mask) | ||
71 | { | ||
72 | struct adp5520_chip *chip = i2c_get_clientdata(client); | ||
73 | uint8_t reg_val; | ||
74 | int ret; | ||
75 | |||
76 | mutex_lock(&chip->lock); | ||
77 | |||
78 | ret = __adp5520_read(client, reg, ®_val); | ||
79 | |||
80 | if (!ret) { | ||
81 | reg_val |= bit_mask; | ||
82 | ret = __adp5520_write(client, reg, reg_val); | ||
83 | } | ||
84 | |||
85 | mutex_unlock(&chip->lock); | ||
86 | return ret; | ||
87 | } | ||
88 | |||
89 | int adp5520_write(struct device *dev, int reg, uint8_t val) | ||
90 | { | ||
91 | return __adp5520_write(to_i2c_client(dev), reg, val); | ||
92 | } | ||
93 | EXPORT_SYMBOL_GPL(adp5520_write); | ||
94 | |||
95 | int adp5520_read(struct device *dev, int reg, uint8_t *val) | ||
96 | { | ||
97 | return __adp5520_read(to_i2c_client(dev), reg, val); | ||
98 | } | ||
99 | EXPORT_SYMBOL_GPL(adp5520_read); | ||
100 | |||
101 | int adp5520_set_bits(struct device *dev, int reg, uint8_t bit_mask) | ||
102 | { | ||
103 | struct adp5520_chip *chip = dev_get_drvdata(dev); | ||
104 | uint8_t reg_val; | ||
105 | int ret; | ||
106 | |||
107 | mutex_lock(&chip->lock); | ||
108 | |||
109 | ret = __adp5520_read(chip->client, reg, ®_val); | ||
110 | |||
111 | if (!ret && ((reg_val & bit_mask) == 0)) { | ||
112 | reg_val |= bit_mask; | ||
113 | ret = __adp5520_write(chip->client, reg, reg_val); | ||
114 | } | ||
115 | |||
116 | mutex_unlock(&chip->lock); | ||
117 | return ret; | ||
118 | } | ||
119 | EXPORT_SYMBOL_GPL(adp5520_set_bits); | ||
120 | |||
121 | int adp5520_clr_bits(struct device *dev, int reg, uint8_t bit_mask) | ||
122 | { | ||
123 | struct adp5520_chip *chip = dev_get_drvdata(dev); | ||
124 | uint8_t reg_val; | ||
125 | int ret; | ||
126 | |||
127 | mutex_lock(&chip->lock); | ||
128 | |||
129 | ret = __adp5520_read(chip->client, reg, ®_val); | ||
130 | |||
131 | if (!ret && (reg_val & bit_mask)) { | ||
132 | reg_val &= ~bit_mask; | ||
133 | ret = __adp5520_write(chip->client, reg, reg_val); | ||
134 | } | ||
135 | |||
136 | mutex_unlock(&chip->lock); | ||
137 | return ret; | ||
138 | } | ||
139 | EXPORT_SYMBOL_GPL(adp5520_clr_bits); | ||
140 | |||
141 | int adp5520_register_notifier(struct device *dev, struct notifier_block *nb, | ||
142 | unsigned int events) | ||
143 | { | ||
144 | struct adp5520_chip *chip = dev_get_drvdata(dev); | ||
145 | |||
146 | if (chip->irq) { | ||
147 | adp5520_set_bits(chip->dev, ADP5520_INTERRUPT_ENABLE, | ||
148 | events & (ADP5520_KP_IEN | ADP5520_KR_IEN | | ||
149 | ADP5520_OVP_IEN | ADP5520_CMPR_IEN)); | ||
150 | |||
151 | return blocking_notifier_chain_register(&chip->notifier_list, | ||
152 | nb); | ||
153 | } | ||
154 | |||
155 | return -ENODEV; | ||
156 | } | ||
157 | EXPORT_SYMBOL_GPL(adp5520_register_notifier); | ||
158 | |||
159 | int adp5520_unregister_notifier(struct device *dev, struct notifier_block *nb, | ||
160 | unsigned int events) | ||
161 | { | ||
162 | struct adp5520_chip *chip = dev_get_drvdata(dev); | ||
163 | |||
164 | adp5520_clr_bits(chip->dev, ADP5520_INTERRUPT_ENABLE, | ||
165 | events & (ADP5520_KP_IEN | ADP5520_KR_IEN | | ||
166 | ADP5520_OVP_IEN | ADP5520_CMPR_IEN)); | ||
167 | |||
168 | return blocking_notifier_chain_unregister(&chip->notifier_list, nb); | ||
169 | } | ||
170 | EXPORT_SYMBOL_GPL(adp5520_unregister_notifier); | ||
171 | |||
172 | static irqreturn_t adp5520_irq_thread(int irq, void *data) | ||
173 | { | ||
174 | struct adp5520_chip *chip = data; | ||
175 | unsigned int events; | ||
176 | uint8_t reg_val; | ||
177 | int ret; | ||
178 | |||
179 | ret = __adp5520_read(chip->client, ADP5520_MODE_STATUS, ®_val); | ||
180 | if (ret) | ||
181 | goto out; | ||
182 | |||
183 | events = reg_val & (ADP5520_OVP_INT | ADP5520_CMPR_INT | | ||
184 | ADP5520_GPI_INT | ADP5520_KR_INT | ADP5520_KP_INT); | ||
185 | |||
186 | blocking_notifier_call_chain(&chip->notifier_list, events, NULL); | ||
187 | /* ACK, Sticky bits are W1C */ | ||
188 | __adp5520_ack_bits(chip->client, ADP5520_MODE_STATUS, events); | ||
189 | |||
190 | out: | ||
191 | return IRQ_HANDLED; | ||
192 | } | ||
193 | |||
194 | static int __remove_subdev(struct device *dev, void *unused) | ||
195 | { | ||
196 | platform_device_unregister(to_platform_device(dev)); | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static int adp5520_remove_subdevs(struct adp5520_chip *chip) | ||
201 | { | ||
202 | return device_for_each_child(chip->dev, NULL, __remove_subdev); | ||
203 | } | ||
204 | |||
205 | static int __devinit adp5520_probe(struct i2c_client *client, | ||
206 | const struct i2c_device_id *id) | ||
207 | { | ||
208 | struct adp5520_platform_data *pdata = client->dev.platform_data; | ||
209 | struct platform_device *pdev; | ||
210 | struct adp5520_chip *chip; | ||
211 | int ret; | ||
212 | |||
213 | if (!i2c_check_functionality(client->adapter, | ||
214 | I2C_FUNC_SMBUS_BYTE_DATA)) { | ||
215 | dev_err(&client->dev, "SMBUS Word Data not Supported\n"); | ||
216 | return -EIO; | ||
217 | } | ||
218 | |||
219 | if (pdata == NULL) { | ||
220 | dev_err(&client->dev, "missing platform data\n"); | ||
221 | return -ENODEV; | ||
222 | } | ||
223 | |||
224 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||
225 | if (!chip) | ||
226 | return -ENOMEM; | ||
227 | |||
228 | i2c_set_clientdata(client, chip); | ||
229 | chip->client = client; | ||
230 | |||
231 | chip->dev = &client->dev; | ||
232 | chip->irq = client->irq; | ||
233 | chip->id = id->driver_data; | ||
234 | mutex_init(&chip->lock); | ||
235 | |||
236 | if (chip->irq) { | ||
237 | BLOCKING_INIT_NOTIFIER_HEAD(&chip->notifier_list); | ||
238 | |||
239 | ret = request_threaded_irq(chip->irq, NULL, adp5520_irq_thread, | ||
240 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
241 | "adp5520", chip); | ||
242 | if (ret) { | ||
243 | dev_err(&client->dev, "failed to request irq %d\n", | ||
244 | chip->irq); | ||
245 | goto out_free_chip; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | ret = adp5520_write(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); | ||
250 | if (ret) { | ||
251 | dev_err(&client->dev, "failed to write\n"); | ||
252 | goto out_free_irq; | ||
253 | } | ||
254 | |||
255 | if (pdata->keys) { | ||
256 | pdev = platform_device_register_data(chip->dev, "adp5520-keys", | ||
257 | chip->id, pdata->keys, sizeof(*pdata->keys)); | ||
258 | if (IS_ERR(pdev)) { | ||
259 | ret = PTR_ERR(pdev); | ||
260 | goto out_remove_subdevs; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | if (pdata->gpio) { | ||
265 | pdev = platform_device_register_data(chip->dev, "adp5520-gpio", | ||
266 | chip->id, pdata->gpio, sizeof(*pdata->gpio)); | ||
267 | if (IS_ERR(pdev)) { | ||
268 | ret = PTR_ERR(pdev); | ||
269 | goto out_remove_subdevs; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | if (pdata->leds) { | ||
274 | pdev = platform_device_register_data(chip->dev, "adp5520-led", | ||
275 | chip->id, pdata->leds, sizeof(*pdata->leds)); | ||
276 | if (IS_ERR(pdev)) { | ||
277 | ret = PTR_ERR(pdev); | ||
278 | goto out_remove_subdevs; | ||
279 | } | ||
280 | } | ||
281 | |||
282 | if (pdata->backlight) { | ||
283 | pdev = platform_device_register_data(chip->dev, | ||
284 | "adp5520-backlight", | ||
285 | chip->id, | ||
286 | pdata->backlight, | ||
287 | sizeof(*pdata->backlight)); | ||
288 | if (IS_ERR(pdev)) { | ||
289 | ret = PTR_ERR(pdev); | ||
290 | goto out_remove_subdevs; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | return 0; | ||
295 | |||
296 | out_remove_subdevs: | ||
297 | adp5520_remove_subdevs(chip); | ||
298 | |||
299 | out_free_irq: | ||
300 | if (chip->irq) | ||
301 | free_irq(chip->irq, chip); | ||
302 | |||
303 | out_free_chip: | ||
304 | i2c_set_clientdata(client, NULL); | ||
305 | kfree(chip); | ||
306 | |||
307 | return ret; | ||
308 | } | ||
309 | |||
310 | static int __devexit adp5520_remove(struct i2c_client *client) | ||
311 | { | ||
312 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); | ||
313 | |||
314 | if (chip->irq) | ||
315 | free_irq(chip->irq, chip); | ||
316 | |||
317 | adp5520_remove_subdevs(chip); | ||
318 | adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0); | ||
319 | i2c_set_clientdata(client, NULL); | ||
320 | kfree(chip); | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | #ifdef CONFIG_PM | ||
325 | static int adp5520_suspend(struct i2c_client *client, | ||
326 | pm_message_t state) | ||
327 | { | ||
328 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); | ||
329 | |||
330 | adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static int adp5520_resume(struct i2c_client *client) | ||
335 | { | ||
336 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); | ||
337 | |||
338 | adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); | ||
339 | return 0; | ||
340 | } | ||
341 | #else | ||
342 | #define adp5520_suspend NULL | ||
343 | #define adp5520_resume NULL | ||
344 | #endif | ||
345 | |||
346 | static const struct i2c_device_id adp5520_id[] = { | ||
347 | { "pmic-adp5520", ID_ADP5520 }, | ||
348 | { "pmic-adp5501", ID_ADP5501 }, | ||
349 | { } | ||
350 | }; | ||
351 | MODULE_DEVICE_TABLE(i2c, adp5520_id); | ||
352 | |||
353 | static struct i2c_driver adp5520_driver = { | ||
354 | .driver = { | ||
355 | .name = "adp5520", | ||
356 | .owner = THIS_MODULE, | ||
357 | }, | ||
358 | .probe = adp5520_probe, | ||
359 | .remove = __devexit_p(adp5520_remove), | ||
360 | .suspend = adp5520_suspend, | ||
361 | .resume = adp5520_resume, | ||
362 | .id_table = adp5520_id, | ||
363 | }; | ||
364 | |||
365 | static int __init adp5520_init(void) | ||
366 | { | ||
367 | return i2c_add_driver(&adp5520_driver); | ||
368 | } | ||
369 | module_init(adp5520_init); | ||
370 | |||
371 | static void __exit adp5520_exit(void) | ||
372 | { | ||
373 | i2c_del_driver(&adp5520_driver); | ||
374 | } | ||
375 | module_exit(adp5520_exit); | ||
376 | |||
377 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
378 | MODULE_DESCRIPTION("ADP5520(01) PMIC-MFD Driver"); | ||
379 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 63a2a6632106..e22128c3e9a8 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c | |||
@@ -908,7 +908,7 @@ static int __init asic3_probe(struct platform_device *pdev) | |||
908 | return ret; | 908 | return ret; |
909 | } | 909 | } |
910 | 910 | ||
911 | static int asic3_remove(struct platform_device *pdev) | 911 | static int __devexit asic3_remove(struct platform_device *pdev) |
912 | { | 912 | { |
913 | int ret; | 913 | int ret; |
914 | struct asic3 *asic = platform_get_drvdata(pdev); | 914 | struct asic3 *asic = platform_get_drvdata(pdev); |
diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 876288917976..df405af968fa 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c | |||
@@ -387,7 +387,6 @@ static int __devinit pcap_add_subdev(struct pcap_chip *pcap, | |||
387 | pdev = platform_device_alloc(subdev->name, subdev->id); | 387 | pdev = platform_device_alloc(subdev->name, subdev->id); |
388 | pdev->dev.parent = &pcap->spi->dev; | 388 | pdev->dev.parent = &pcap->spi->dev; |
389 | pdev->dev.platform_data = subdev->platform_data; | 389 | pdev->dev.platform_data = subdev->platform_data; |
390 | platform_set_drvdata(pdev, pcap); | ||
391 | 390 | ||
392 | return platform_device_add(pdev); | 391 | return platform_device_add(pdev); |
393 | } | 392 | } |
diff --git a/drivers/mfd/mc13783-core.c b/drivers/mfd/mc13783-core.c index e354d2912ef1..a1ade2324ea9 100644 --- a/drivers/mfd/mc13783-core.c +++ b/drivers/mfd/mc13783-core.c | |||
@@ -1,286 +1,549 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> | 2 | * Copyright 2009 Pengutronix |
3 | * | 3 | * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> |
4 | * This code is in parts based on wm8350-core.c and pcf50633-core.c | ||
5 | * | ||
6 | * Initial development of this code was funded by | ||
7 | * Phytec Messtechnik GmbH, http://www.phytec.de | ||
8 | * | 4 | * |
9 | * This program is free software; you can redistribute it and/or modify | 5 | * loosely based on an earlier driver that has |
10 | * it under the terms of the GNU General Public License as published by | 6 | * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> |
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | 7 | * |
19 | * You should have received a copy of the GNU General Public License | 8 | * This program is free software; you can redistribute it and/or modify it under |
20 | * along with this program; if not, write to the Free Software | 9 | * the terms of the GNU General Public License version 2 as published by the |
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 10 | * Free Software Foundation. |
22 | */ | 11 | */ |
23 | |||
24 | #include <linux/mfd/mc13783-private.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/mfd/mc13783.h> | ||
27 | #include <linux/completion.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/mfd/core.h> | ||
30 | #include <linux/spi/spi.h> | ||
31 | #include <linux/uaccess.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/module.h> | 12 | #include <linux/module.h> |
34 | #include <linux/init.h> | 13 | #include <linux/spi/spi.h> |
35 | #include <linux/slab.h> | 14 | #include <linux/mfd/core.h> |
36 | #include <linux/irq.h> | 15 | #include <linux/mfd/mc13783-private.h> |
16 | |||
17 | #define MC13783_IRQSTAT0 0 | ||
18 | #define MC13783_IRQSTAT0_ADCDONEI (1 << 0) | ||
19 | #define MC13783_IRQSTAT0_ADCBISDONEI (1 << 1) | ||
20 | #define MC13783_IRQSTAT0_TSI (1 << 2) | ||
21 | #define MC13783_IRQSTAT0_WHIGHI (1 << 3) | ||
22 | #define MC13783_IRQSTAT0_WLOWI (1 << 4) | ||
23 | #define MC13783_IRQSTAT0_CHGDETI (1 << 6) | ||
24 | #define MC13783_IRQSTAT0_CHGOVI (1 << 7) | ||
25 | #define MC13783_IRQSTAT0_CHGREVI (1 << 8) | ||
26 | #define MC13783_IRQSTAT0_CHGSHORTI (1 << 9) | ||
27 | #define MC13783_IRQSTAT0_CCCVI (1 << 10) | ||
28 | #define MC13783_IRQSTAT0_CHGCURRI (1 << 11) | ||
29 | #define MC13783_IRQSTAT0_BPONI (1 << 12) | ||
30 | #define MC13783_IRQSTAT0_LOBATLI (1 << 13) | ||
31 | #define MC13783_IRQSTAT0_LOBATHI (1 << 14) | ||
32 | #define MC13783_IRQSTAT0_UDPI (1 << 15) | ||
33 | #define MC13783_IRQSTAT0_USBI (1 << 16) | ||
34 | #define MC13783_IRQSTAT0_IDI (1 << 19) | ||
35 | #define MC13783_IRQSTAT0_SE1I (1 << 21) | ||
36 | #define MC13783_IRQSTAT0_CKDETI (1 << 22) | ||
37 | #define MC13783_IRQSTAT0_UDMI (1 << 23) | ||
38 | |||
39 | #define MC13783_IRQMASK0 1 | ||
40 | #define MC13783_IRQMASK0_ADCDONEM MC13783_IRQSTAT0_ADCDONEI | ||
41 | #define MC13783_IRQMASK0_ADCBISDONEM MC13783_IRQSTAT0_ADCBISDONEI | ||
42 | #define MC13783_IRQMASK0_TSM MC13783_IRQSTAT0_TSI | ||
43 | #define MC13783_IRQMASK0_WHIGHM MC13783_IRQSTAT0_WHIGHI | ||
44 | #define MC13783_IRQMASK0_WLOWM MC13783_IRQSTAT0_WLOWI | ||
45 | #define MC13783_IRQMASK0_CHGDETM MC13783_IRQSTAT0_CHGDETI | ||
46 | #define MC13783_IRQMASK0_CHGOVM MC13783_IRQSTAT0_CHGOVI | ||
47 | #define MC13783_IRQMASK0_CHGREVM MC13783_IRQSTAT0_CHGREVI | ||
48 | #define MC13783_IRQMASK0_CHGSHORTM MC13783_IRQSTAT0_CHGSHORTI | ||
49 | #define MC13783_IRQMASK0_CCCVM MC13783_IRQSTAT0_CCCVI | ||
50 | #define MC13783_IRQMASK0_CHGCURRM MC13783_IRQSTAT0_CHGCURRI | ||
51 | #define MC13783_IRQMASK0_BPONM MC13783_IRQSTAT0_BPONI | ||
52 | #define MC13783_IRQMASK0_LOBATLM MC13783_IRQSTAT0_LOBATLI | ||
53 | #define MC13783_IRQMASK0_LOBATHM MC13783_IRQSTAT0_LOBATHI | ||
54 | #define MC13783_IRQMASK0_UDPM MC13783_IRQSTAT0_UDPI | ||
55 | #define MC13783_IRQMASK0_USBM MC13783_IRQSTAT0_USBI | ||
56 | #define MC13783_IRQMASK0_IDM MC13783_IRQSTAT0_IDI | ||
57 | #define MC13783_IRQMASK0_SE1M MC13783_IRQSTAT0_SE1I | ||
58 | #define MC13783_IRQMASK0_CKDETM MC13783_IRQSTAT0_CKDETI | ||
59 | #define MC13783_IRQMASK0_UDMM MC13783_IRQSTAT0_UDMI | ||
60 | |||
61 | #define MC13783_IRQSTAT1 3 | ||
62 | #define MC13783_IRQSTAT1_1HZI (1 << 0) | ||
63 | #define MC13783_IRQSTAT1_TODAI (1 << 1) | ||
64 | #define MC13783_IRQSTAT1_ONOFD1I (1 << 3) | ||
65 | #define MC13783_IRQSTAT1_ONOFD2I (1 << 4) | ||
66 | #define MC13783_IRQSTAT1_ONOFD3I (1 << 5) | ||
67 | #define MC13783_IRQSTAT1_SYSRSTI (1 << 6) | ||
68 | #define MC13783_IRQSTAT1_RTCRSTI (1 << 7) | ||
69 | #define MC13783_IRQSTAT1_PCI (1 << 8) | ||
70 | #define MC13783_IRQSTAT1_WARMI (1 << 9) | ||
71 | #define MC13783_IRQSTAT1_MEMHLDI (1 << 10) | ||
72 | #define MC13783_IRQSTAT1_PWRRDYI (1 << 11) | ||
73 | #define MC13783_IRQSTAT1_THWARNLI (1 << 12) | ||
74 | #define MC13783_IRQSTAT1_THWARNHI (1 << 13) | ||
75 | #define MC13783_IRQSTAT1_CLKI (1 << 14) | ||
76 | #define MC13783_IRQSTAT1_SEMAFI (1 << 15) | ||
77 | #define MC13783_IRQSTAT1_MC2BI (1 << 17) | ||
78 | #define MC13783_IRQSTAT1_HSDETI (1 << 18) | ||
79 | #define MC13783_IRQSTAT1_HSLI (1 << 19) | ||
80 | #define MC13783_IRQSTAT1_ALSPTHI (1 << 20) | ||
81 | #define MC13783_IRQSTAT1_AHSSHORTI (1 << 21) | ||
82 | |||
83 | #define MC13783_IRQMASK1 4 | ||
84 | #define MC13783_IRQMASK1_1HZM MC13783_IRQSTAT1_1HZI | ||
85 | #define MC13783_IRQMASK1_TODAM MC13783_IRQSTAT1_TODAI | ||
86 | #define MC13783_IRQMASK1_ONOFD1M MC13783_IRQSTAT1_ONOFD1I | ||
87 | #define MC13783_IRQMASK1_ONOFD2M MC13783_IRQSTAT1_ONOFD2I | ||
88 | #define MC13783_IRQMASK1_ONOFD3M MC13783_IRQSTAT1_ONOFD3I | ||
89 | #define MC13783_IRQMASK1_SYSRSTM MC13783_IRQSTAT1_SYSRSTI | ||
90 | #define MC13783_IRQMASK1_RTCRSTM MC13783_IRQSTAT1_RTCRSTI | ||
91 | #define MC13783_IRQMASK1_PCM MC13783_IRQSTAT1_PCI | ||
92 | #define MC13783_IRQMASK1_WARMM MC13783_IRQSTAT1_WARMI | ||
93 | #define MC13783_IRQMASK1_MEMHLDM MC13783_IRQSTAT1_MEMHLDI | ||
94 | #define MC13783_IRQMASK1_PWRRDYM MC13783_IRQSTAT1_PWRRDYI | ||
95 | #define MC13783_IRQMASK1_THWARNLM MC13783_IRQSTAT1_THWARNLI | ||
96 | #define MC13783_IRQMASK1_THWARNHM MC13783_IRQSTAT1_THWARNHI | ||
97 | #define MC13783_IRQMASK1_CLKM MC13783_IRQSTAT1_CLKI | ||
98 | #define MC13783_IRQMASK1_SEMAFM MC13783_IRQSTAT1_SEMAFI | ||
99 | #define MC13783_IRQMASK1_MC2BM MC13783_IRQSTAT1_MC2BI | ||
100 | #define MC13783_IRQMASK1_HSDETM MC13783_IRQSTAT1_HSDETI | ||
101 | #define MC13783_IRQMASK1_HSLM MC13783_IRQSTAT1_HSLI | ||
102 | #define MC13783_IRQMASK1_ALSPTHM MC13783_IRQSTAT1_ALSPTHI | ||
103 | #define MC13783_IRQMASK1_AHSSHORTM MC13783_IRQSTAT1_AHSSHORTI | ||
104 | |||
105 | #define MC13783_ADC1 44 | ||
106 | #define MC13783_ADC1_ADEN (1 << 0) | ||
107 | #define MC13783_ADC1_RAND (1 << 1) | ||
108 | #define MC13783_ADC1_ADSEL (1 << 3) | ||
109 | #define MC13783_ADC1_ASC (1 << 20) | ||
110 | #define MC13783_ADC1_ADTRIGIGN (1 << 21) | ||
111 | |||
112 | #define MC13783_NUMREGS 0x3f | ||
113 | |||
114 | void mc13783_lock(struct mc13783 *mc13783) | ||
115 | { | ||
116 | if (!mutex_trylock(&mc13783->lock)) { | ||
117 | dev_dbg(&mc13783->spidev->dev, "wait for %s from %pf\n", | ||
118 | __func__, __builtin_return_address(0)); | ||
119 | |||
120 | mutex_lock(&mc13783->lock); | ||
121 | } | ||
122 | dev_dbg(&mc13783->spidev->dev, "%s from %pf\n", | ||
123 | __func__, __builtin_return_address(0)); | ||
124 | } | ||
125 | EXPORT_SYMBOL(mc13783_lock); | ||
37 | 126 | ||
38 | #define MC13783_MAX_REG_NUM 0x3f | 127 | void mc13783_unlock(struct mc13783 *mc13783) |
39 | #define MC13783_FRAME_MASK 0x00ffffff | 128 | { |
40 | #define MC13783_MAX_REG_NUM 0x3f | 129 | dev_dbg(&mc13783->spidev->dev, "%s from %pf\n", |
41 | #define MC13783_REG_NUM_SHIFT 0x19 | 130 | __func__, __builtin_return_address(0)); |
42 | #define MC13783_WRITE_BIT_SHIFT 31 | 131 | mutex_unlock(&mc13783->lock); |
132 | } | ||
133 | EXPORT_SYMBOL(mc13783_unlock); | ||
43 | 134 | ||
44 | static inline int spi_rw(struct spi_device *spi, u8 * buf, size_t len) | 135 | #define MC13783_REGOFFSET_SHIFT 25 |
136 | int mc13783_reg_read(struct mc13783 *mc13783, unsigned int offset, u32 *val) | ||
45 | { | 137 | { |
46 | struct spi_transfer t = { | 138 | struct spi_transfer t; |
47 | .tx_buf = (const void *)buf, | ||
48 | .rx_buf = buf, | ||
49 | .len = len, | ||
50 | .cs_change = 0, | ||
51 | .delay_usecs = 0, | ||
52 | }; | ||
53 | struct spi_message m; | 139 | struct spi_message m; |
140 | int ret; | ||
141 | |||
142 | BUG_ON(!mutex_is_locked(&mc13783->lock)); | ||
143 | |||
144 | if (offset > MC13783_NUMREGS) | ||
145 | return -EINVAL; | ||
146 | |||
147 | *val = offset << MC13783_REGOFFSET_SHIFT; | ||
148 | |||
149 | memset(&t, 0, sizeof(t)); | ||
150 | |||
151 | t.tx_buf = val; | ||
152 | t.rx_buf = val; | ||
153 | t.len = sizeof(u32); | ||
54 | 154 | ||
55 | spi_message_init(&m); | 155 | spi_message_init(&m); |
56 | spi_message_add_tail(&t, &m); | 156 | spi_message_add_tail(&t, &m); |
57 | if (spi_sync(spi, &m) != 0 || m.status != 0) | ||
58 | return -EINVAL; | ||
59 | return len - m.actual_length; | ||
60 | } | ||
61 | 157 | ||
62 | static int mc13783_read(struct mc13783 *mc13783, int reg_num, u32 *reg_val) | 158 | ret = spi_sync(mc13783->spidev, &m); |
63 | { | ||
64 | unsigned int frame = 0; | ||
65 | int ret = 0; | ||
66 | 159 | ||
67 | if (reg_num > MC13783_MAX_REG_NUM) | 160 | /* error in message.status implies error return from spi_sync */ |
68 | return -EINVAL; | 161 | BUG_ON(!ret && m.status); |
69 | 162 | ||
70 | frame |= reg_num << MC13783_REG_NUM_SHIFT; | 163 | if (ret) |
164 | return ret; | ||
71 | 165 | ||
72 | ret = spi_rw(mc13783->spi_device, (u8 *)&frame, 4); | 166 | *val &= 0xffffff; |
73 | 167 | ||
74 | *reg_val = frame & MC13783_FRAME_MASK; | 168 | dev_vdbg(&mc13783->spidev->dev, "[0x%02x] -> 0x%06x\n", offset, *val); |
75 | 169 | ||
76 | return ret; | 170 | return 0; |
77 | } | 171 | } |
172 | EXPORT_SYMBOL(mc13783_reg_read); | ||
78 | 173 | ||
79 | static int mc13783_write(struct mc13783 *mc13783, int reg_num, u32 reg_val) | 174 | int mc13783_reg_write(struct mc13783 *mc13783, unsigned int offset, u32 val) |
80 | { | 175 | { |
81 | unsigned int frame = 0; | 176 | u32 buf; |
177 | struct spi_transfer t; | ||
178 | struct spi_message m; | ||
179 | int ret; | ||
180 | |||
181 | BUG_ON(!mutex_is_locked(&mc13783->lock)); | ||
82 | 182 | ||
83 | if (reg_num > MC13783_MAX_REG_NUM) | 183 | dev_vdbg(&mc13783->spidev->dev, "[0x%02x] <- 0x%06x\n", offset, val); |
184 | |||
185 | if (offset > MC13783_NUMREGS || val > 0xffffff) | ||
84 | return -EINVAL; | 186 | return -EINVAL; |
85 | 187 | ||
86 | frame |= (1 << MC13783_WRITE_BIT_SHIFT); | 188 | buf = 1 << 31 | offset << MC13783_REGOFFSET_SHIFT | val; |
87 | frame |= reg_num << MC13783_REG_NUM_SHIFT; | 189 | |
88 | frame |= reg_val & MC13783_FRAME_MASK; | 190 | memset(&t, 0, sizeof(t)); |
89 | 191 | ||
90 | return spi_rw(mc13783->spi_device, (u8 *)&frame, 4); | 192 | t.tx_buf = &buf; |
193 | t.rx_buf = &buf; | ||
194 | t.len = sizeof(u32); | ||
195 | |||
196 | spi_message_init(&m); | ||
197 | spi_message_add_tail(&t, &m); | ||
198 | |||
199 | ret = spi_sync(mc13783->spidev, &m); | ||
200 | |||
201 | BUG_ON(!ret && m.status); | ||
202 | |||
203 | if (ret) | ||
204 | return ret; | ||
205 | |||
206 | return 0; | ||
91 | } | 207 | } |
208 | EXPORT_SYMBOL(mc13783_reg_write); | ||
92 | 209 | ||
93 | int mc13783_reg_read(struct mc13783 *mc13783, int reg_num, u32 *reg_val) | 210 | int mc13783_reg_rmw(struct mc13783 *mc13783, unsigned int offset, |
211 | u32 mask, u32 val) | ||
94 | { | 212 | { |
95 | int ret; | 213 | int ret; |
214 | u32 valread; | ||
96 | 215 | ||
97 | mutex_lock(&mc13783->io_lock); | 216 | BUG_ON(val & ~mask); |
98 | ret = mc13783_read(mc13783, reg_num, reg_val); | ||
99 | mutex_unlock(&mc13783->io_lock); | ||
100 | 217 | ||
101 | return ret; | 218 | ret = mc13783_reg_read(mc13783, offset, &valread); |
219 | if (ret) | ||
220 | return ret; | ||
221 | |||
222 | valread = (valread & ~mask) | val; | ||
223 | |||
224 | return mc13783_reg_write(mc13783, offset, valread); | ||
102 | } | 225 | } |
103 | EXPORT_SYMBOL_GPL(mc13783_reg_read); | 226 | EXPORT_SYMBOL(mc13783_reg_rmw); |
104 | 227 | ||
105 | int mc13783_reg_write(struct mc13783 *mc13783, int reg_num, u32 reg_val) | 228 | int mc13783_mask(struct mc13783 *mc13783, int irq) |
106 | { | 229 | { |
107 | int ret; | 230 | int ret; |
231 | unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1; | ||
232 | u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | ||
233 | u32 mask; | ||
108 | 234 | ||
109 | mutex_lock(&mc13783->io_lock); | 235 | if (irq < 0 || irq >= MC13783_NUM_IRQ) |
110 | ret = mc13783_write(mc13783, reg_num, reg_val); | 236 | return -EINVAL; |
111 | mutex_unlock(&mc13783->io_lock); | ||
112 | 237 | ||
113 | return ret; | 238 | ret = mc13783_reg_read(mc13783, offmask, &mask); |
239 | if (ret) | ||
240 | return ret; | ||
241 | |||
242 | if (mask & irqbit) | ||
243 | /* already masked */ | ||
244 | return 0; | ||
245 | |||
246 | return mc13783_reg_write(mc13783, offmask, mask | irqbit); | ||
114 | } | 247 | } |
115 | EXPORT_SYMBOL_GPL(mc13783_reg_write); | 248 | EXPORT_SYMBOL(mc13783_mask); |
116 | 249 | ||
117 | /** | 250 | int mc13783_unmask(struct mc13783 *mc13783, int irq) |
118 | * mc13783_set_bits - Bitmask write | ||
119 | * | ||
120 | * @mc13783: Pointer to mc13783 control structure | ||
121 | * @reg: Register to access | ||
122 | * @mask: Mask of bits to change | ||
123 | * @val: Value to set for masked bits | ||
124 | */ | ||
125 | int mc13783_set_bits(struct mc13783 *mc13783, int reg, u32 mask, u32 val) | ||
126 | { | 251 | { |
127 | u32 tmp; | ||
128 | int ret; | 252 | int ret; |
253 | unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1; | ||
254 | u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | ||
255 | u32 mask; | ||
129 | 256 | ||
130 | mutex_lock(&mc13783->io_lock); | 257 | if (irq < 0 || irq >= MC13783_NUM_IRQ) |
258 | return -EINVAL; | ||
131 | 259 | ||
132 | ret = mc13783_read(mc13783, reg, &tmp); | 260 | ret = mc13783_reg_read(mc13783, offmask, &mask); |
133 | tmp = (tmp & ~mask) | val; | 261 | if (ret) |
134 | if (ret == 0) | 262 | return ret; |
135 | ret = mc13783_write(mc13783, reg, tmp); | ||
136 | 263 | ||
137 | mutex_unlock(&mc13783->io_lock); | 264 | if (!(mask & irqbit)) |
265 | /* already unmasked */ | ||
266 | return 0; | ||
138 | 267 | ||
139 | return ret; | 268 | return mc13783_reg_write(mc13783, offmask, mask & ~irqbit); |
140 | } | 269 | } |
141 | EXPORT_SYMBOL_GPL(mc13783_set_bits); | 270 | EXPORT_SYMBOL(mc13783_unmask); |
142 | 271 | ||
143 | int mc13783_register_irq(struct mc13783 *mc13783, int irq, | 272 | int mc13783_irq_request_nounmask(struct mc13783 *mc13783, int irq, |
144 | void (*handler) (int, void *), void *data) | 273 | irq_handler_t handler, const char *name, void *dev) |
145 | { | 274 | { |
146 | if (irq < 0 || irq > MC13783_NUM_IRQ || !handler) | 275 | BUG_ON(!mutex_is_locked(&mc13783->lock)); |
276 | BUG_ON(!handler); | ||
277 | |||
278 | if (irq < 0 || irq >= MC13783_NUM_IRQ) | ||
147 | return -EINVAL; | 279 | return -EINVAL; |
148 | 280 | ||
149 | if (WARN_ON(mc13783->irq_handler[irq].handler)) | 281 | if (mc13783->irqhandler[irq]) |
150 | return -EBUSY; | 282 | return -EBUSY; |
151 | 283 | ||
152 | mutex_lock(&mc13783->io_lock); | 284 | mc13783->irqhandler[irq] = handler; |
153 | mc13783->irq_handler[irq].handler = handler; | 285 | mc13783->irqdata[irq] = dev; |
154 | mc13783->irq_handler[irq].data = data; | ||
155 | mutex_unlock(&mc13783->io_lock); | ||
156 | 286 | ||
157 | return 0; | 287 | return 0; |
158 | } | 288 | } |
159 | EXPORT_SYMBOL_GPL(mc13783_register_irq); | 289 | EXPORT_SYMBOL(mc13783_irq_request_nounmask); |
160 | 290 | ||
161 | int mc13783_free_irq(struct mc13783 *mc13783, int irq) | 291 | int mc13783_irq_request(struct mc13783 *mc13783, int irq, |
292 | irq_handler_t handler, const char *name, void *dev) | ||
162 | { | 293 | { |
163 | if (irq < 0 || irq > MC13783_NUM_IRQ) | 294 | int ret; |
295 | |||
296 | ret = mc13783_irq_request_nounmask(mc13783, irq, handler, name, dev); | ||
297 | if (ret) | ||
298 | return ret; | ||
299 | |||
300 | ret = mc13783_unmask(mc13783, irq); | ||
301 | if (ret) { | ||
302 | mc13783->irqhandler[irq] = NULL; | ||
303 | mc13783->irqdata[irq] = NULL; | ||
304 | return ret; | ||
305 | } | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | EXPORT_SYMBOL(mc13783_irq_request); | ||
310 | |||
311 | int mc13783_irq_free(struct mc13783 *mc13783, int irq, void *dev) | ||
312 | { | ||
313 | int ret; | ||
314 | BUG_ON(!mutex_is_locked(&mc13783->lock)); | ||
315 | |||
316 | if (irq < 0 || irq >= MC13783_NUM_IRQ || !mc13783->irqhandler[irq] || | ||
317 | mc13783->irqdata[irq] != dev) | ||
164 | return -EINVAL; | 318 | return -EINVAL; |
165 | 319 | ||
166 | mutex_lock(&mc13783->io_lock); | 320 | ret = mc13783_mask(mc13783, irq); |
167 | mc13783->irq_handler[irq].handler = NULL; | 321 | if (ret) |
168 | mutex_unlock(&mc13783->io_lock); | 322 | return ret; |
323 | |||
324 | mc13783->irqhandler[irq] = NULL; | ||
325 | mc13783->irqdata[irq] = NULL; | ||
169 | 326 | ||
170 | return 0; | 327 | return 0; |
171 | } | 328 | } |
172 | EXPORT_SYMBOL_GPL(mc13783_free_irq); | 329 | EXPORT_SYMBOL(mc13783_irq_free); |
173 | 330 | ||
174 | static void mc13783_irq_work(struct work_struct *work) | 331 | static inline irqreturn_t mc13783_irqhandler(struct mc13783 *mc13783, int irq) |
175 | { | 332 | { |
176 | struct mc13783 *mc13783 = container_of(work, struct mc13783, work); | 333 | return mc13783->irqhandler[irq](irq, mc13783->irqdata[irq]); |
177 | int i; | ||
178 | unsigned int adc_sts; | ||
179 | |||
180 | /* check if the adc has finished any completion */ | ||
181 | mc13783_reg_read(mc13783, MC13783_REG_INTERRUPT_STATUS_0, &adc_sts); | ||
182 | mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_STATUS_0, | ||
183 | adc_sts & MC13783_INT_STAT_ADCDONEI); | ||
184 | |||
185 | if (adc_sts & MC13783_INT_STAT_ADCDONEI) | ||
186 | complete_all(&mc13783->adc_done); | ||
187 | |||
188 | for (i = 0; i < MC13783_NUM_IRQ; i++) | ||
189 | if (mc13783->irq_handler[i].handler) | ||
190 | mc13783->irq_handler[i].handler(i, | ||
191 | mc13783->irq_handler[i].data); | ||
192 | enable_irq(mc13783->irq); | ||
193 | } | 334 | } |
194 | 335 | ||
195 | static irqreturn_t mc13783_interrupt(int irq, void *dev_id) | 336 | int mc13783_ackirq(struct mc13783 *mc13783, int irq) |
196 | { | 337 | { |
197 | struct mc13783 *mc13783 = dev_id; | 338 | unsigned int offstat = irq < 24 ? MC13783_IRQSTAT0 : MC13783_IRQSTAT1; |
339 | unsigned int val = 1 << (irq < 24 ? irq : irq - 24); | ||
198 | 340 | ||
199 | disable_irq_nosync(irq); | 341 | BUG_ON(irq < 0 || irq >= MC13783_NUM_IRQ); |
200 | 342 | ||
201 | schedule_work(&mc13783->work); | 343 | return mc13783_reg_write(mc13783, offstat, val); |
202 | return IRQ_HANDLED; | ||
203 | } | 344 | } |
345 | EXPORT_SYMBOL(mc13783_ackirq); | ||
204 | 346 | ||
205 | /* set adc to ts interrupt mode, which generates touchscreen wakeup interrupt */ | 347 | /* |
206 | static inline void mc13783_adc_set_ts_irq_mode(struct mc13783 *mc13783) | 348 | * returns: number of handled irqs or negative error |
349 | * locking: holds mc13783->lock | ||
350 | */ | ||
351 | static int mc13783_irq_handle(struct mc13783 *mc13783, | ||
352 | unsigned int offstat, unsigned int offmask, int baseirq) | ||
207 | { | 353 | { |
208 | unsigned int reg_adc0, reg_adc1; | 354 | u32 stat, mask; |
355 | int ret = mc13783_reg_read(mc13783, offstat, &stat); | ||
356 | int num_handled = 0; | ||
357 | |||
358 | if (ret) | ||
359 | return ret; | ||
360 | |||
361 | ret = mc13783_reg_read(mc13783, offmask, &mask); | ||
362 | if (ret) | ||
363 | return ret; | ||
364 | |||
365 | while (stat & ~mask) { | ||
366 | int irq = __ffs(stat & ~mask); | ||
367 | |||
368 | stat &= ~(1 << irq); | ||
369 | |||
370 | if (likely(mc13783->irqhandler[baseirq + irq])) { | ||
371 | irqreturn_t handled; | ||
209 | 372 | ||
210 | reg_adc0 = MC13783_ADC0_ADREFEN | MC13783_ADC0_ADREFMODE | 373 | handled = mc13783_irqhandler(mc13783, baseirq + irq); |
211 | | MC13783_ADC0_TSMOD0; | 374 | if (handled == IRQ_HANDLED) |
212 | reg_adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN; | 375 | num_handled++; |
376 | } else { | ||
377 | dev_err(&mc13783->spidev->dev, | ||
378 | "BUG: irq %u but no handler\n", | ||
379 | baseirq + irq); | ||
213 | 380 | ||
214 | mc13783_reg_write(mc13783, MC13783_REG_ADC_0, reg_adc0); | 381 | mask |= 1 << irq; |
215 | mc13783_reg_write(mc13783, MC13783_REG_ADC_1, reg_adc1); | 382 | |
383 | ret = mc13783_reg_write(mc13783, offmask, mask); | ||
384 | } | ||
385 | } | ||
386 | |||
387 | return num_handled; | ||
216 | } | 388 | } |
217 | 389 | ||
390 | static irqreturn_t mc13783_irq_thread(int irq, void *data) | ||
391 | { | ||
392 | struct mc13783 *mc13783 = data; | ||
393 | irqreturn_t ret; | ||
394 | int handled = 0; | ||
395 | |||
396 | mc13783_lock(mc13783); | ||
397 | |||
398 | ret = mc13783_irq_handle(mc13783, MC13783_IRQSTAT0, | ||
399 | MC13783_IRQMASK0, MC13783_IRQ_ADCDONE); | ||
400 | if (ret > 0) | ||
401 | handled = 1; | ||
402 | |||
403 | ret = mc13783_irq_handle(mc13783, MC13783_IRQSTAT1, | ||
404 | MC13783_IRQMASK1, MC13783_IRQ_1HZ); | ||
405 | if (ret > 0) | ||
406 | handled = 1; | ||
407 | |||
408 | mc13783_unlock(mc13783); | ||
409 | |||
410 | return IRQ_RETVAL(handled); | ||
411 | } | ||
412 | |||
413 | #define MC13783_ADC1_CHAN0_SHIFT 5 | ||
414 | #define MC13783_ADC1_CHAN1_SHIFT 8 | ||
415 | |||
416 | struct mc13783_adcdone_data { | ||
417 | struct mc13783 *mc13783; | ||
418 | struct completion done; | ||
419 | }; | ||
420 | |||
421 | static irqreturn_t mc13783_handler_adcdone(int irq, void *data) | ||
422 | { | ||
423 | struct mc13783_adcdone_data *adcdone_data = data; | ||
424 | |||
425 | mc13783_ackirq(adcdone_data->mc13783, irq); | ||
426 | |||
427 | complete_all(&adcdone_data->done); | ||
428 | |||
429 | return IRQ_HANDLED; | ||
430 | } | ||
431 | |||
432 | #define MC13783_ADC_WORKING (1 << 16) | ||
433 | |||
218 | int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, | 434 | int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, |
219 | unsigned int channel, unsigned int *sample) | 435 | unsigned int channel, unsigned int *sample) |
220 | { | 436 | { |
221 | unsigned int reg_adc0, reg_adc1; | 437 | u32 adc0, adc1, old_adc0; |
222 | int i; | 438 | int i, ret; |
439 | struct mc13783_adcdone_data adcdone_data = { | ||
440 | .mc13783 = mc13783, | ||
441 | }; | ||
442 | init_completion(&adcdone_data.done); | ||
443 | |||
444 | dev_dbg(&mc13783->spidev->dev, "%s\n", __func__); | ||
445 | |||
446 | mc13783_lock(mc13783); | ||
447 | |||
448 | if (mc13783->flags & MC13783_ADC_WORKING) { | ||
449 | ret = -EBUSY; | ||
450 | goto out; | ||
451 | } | ||
452 | |||
453 | mc13783->flags |= MC13783_ADC_WORKING; | ||
223 | 454 | ||
224 | mutex_lock(&mc13783->adc_conv_lock); | 455 | mc13783_reg_read(mc13783, MC13783_ADC0, &old_adc0); |
225 | 456 | ||
226 | /* set up auto incrementing anyway to make quick read */ | 457 | adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2; |
227 | reg_adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2; | 458 | adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN | MC13783_ADC1_ASC; |
228 | /* enable the adc, ignore external triggering and set ASC to trigger | ||
229 | * conversion */ | ||
230 | reg_adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN | ||
231 | | MC13783_ADC1_ASC; | ||
232 | 459 | ||
233 | /* setup channel number */ | ||
234 | if (channel > 7) | 460 | if (channel > 7) |
235 | reg_adc1 |= MC13783_ADC1_ADSEL; | 461 | adc1 |= MC13783_ADC1_ADSEL; |
236 | 462 | ||
237 | switch (mode) { | 463 | switch (mode) { |
238 | case MC13783_ADC_MODE_TS: | 464 | case MC13783_ADC_MODE_TS: |
239 | /* enables touch screen reference mode and set touchscreen mode | 465 | adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_TSMOD0 | |
240 | * to position mode */ | 466 | MC13783_ADC0_TSMOD1; |
241 | reg_adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_ADREFMODE | 467 | adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; |
242 | | MC13783_ADC0_TSMOD0 | MC13783_ADC0_TSMOD1; | ||
243 | reg_adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | ||
244 | break; | 468 | break; |
469 | |||
245 | case MC13783_ADC_MODE_SINGLE_CHAN: | 470 | case MC13783_ADC_MODE_SINGLE_CHAN: |
246 | reg_adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT; | 471 | adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; |
247 | reg_adc1 |= MC13783_ADC1_RAND; | 472 | adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT; |
473 | adc1 |= MC13783_ADC1_RAND; | ||
248 | break; | 474 | break; |
475 | |||
249 | case MC13783_ADC_MODE_MULT_CHAN: | 476 | case MC13783_ADC_MODE_MULT_CHAN: |
250 | reg_adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | 477 | adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; |
478 | adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | ||
251 | break; | 479 | break; |
480 | |||
252 | default: | 481 | default: |
482 | mc13783_unlock(mc13783); | ||
253 | return -EINVAL; | 483 | return -EINVAL; |
254 | } | 484 | } |
255 | 485 | ||
256 | mc13783_reg_write(mc13783, MC13783_REG_ADC_0, reg_adc0); | 486 | dev_dbg(&mc13783->spidev->dev, "%s: request irq\n", __func__); |
257 | mc13783_reg_write(mc13783, MC13783_REG_ADC_1, reg_adc1); | 487 | mc13783_irq_request(mc13783, MC13783_IRQ_ADCDONE, |
488 | mc13783_handler_adcdone, __func__, &adcdone_data); | ||
489 | mc13783_ackirq(mc13783, MC13783_IRQ_ADCDONE); | ||
258 | 490 | ||
259 | wait_for_completion_interruptible(&mc13783->adc_done); | 491 | mc13783_reg_write(mc13783, MC13783_REG_ADC_0, adc0); |
492 | mc13783_reg_write(mc13783, MC13783_REG_ADC_1, adc1); | ||
260 | 493 | ||
261 | for (i = 0; i < 4; i++) | 494 | mc13783_unlock(mc13783); |
262 | mc13783_reg_read(mc13783, MC13783_REG_ADC_2, &sample[i]); | ||
263 | 495 | ||
264 | if (mc13783->ts_active) | 496 | ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ); |
265 | mc13783_adc_set_ts_irq_mode(mc13783); | ||
266 | 497 | ||
267 | mutex_unlock(&mc13783->adc_conv_lock); | 498 | if (!ret) |
499 | ret = -ETIMEDOUT; | ||
268 | 500 | ||
269 | return 0; | 501 | mc13783_lock(mc13783); |
502 | |||
503 | mc13783_irq_free(mc13783, MC13783_IRQ_ADCDONE, &adcdone_data); | ||
504 | |||
505 | if (ret > 0) | ||
506 | for (i = 0; i < 4; ++i) { | ||
507 | ret = mc13783_reg_read(mc13783, | ||
508 | MC13783_REG_ADC_2, &sample[i]); | ||
509 | if (ret) | ||
510 | break; | ||
511 | } | ||
512 | |||
513 | if (mode == MC13783_ADC_MODE_TS) | ||
514 | /* restore TSMOD */ | ||
515 | mc13783_reg_write(mc13783, MC13783_REG_ADC_0, old_adc0); | ||
516 | |||
517 | mc13783->flags &= ~MC13783_ADC_WORKING; | ||
518 | out: | ||
519 | mc13783_unlock(mc13783); | ||
520 | |||
521 | return ret; | ||
270 | } | 522 | } |
271 | EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); | 523 | EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); |
272 | 524 | ||
273 | void mc13783_adc_set_ts_status(struct mc13783 *mc13783, unsigned int status) | 525 | static int mc13783_add_subdevice_pdata(struct mc13783 *mc13783, |
526 | const char *name, void *pdata, size_t pdata_size) | ||
274 | { | 527 | { |
275 | mc13783->ts_active = status; | 528 | struct mfd_cell cell = { |
529 | .name = name, | ||
530 | .platform_data = pdata, | ||
531 | .data_size = pdata_size, | ||
532 | }; | ||
533 | |||
534 | return mfd_add_devices(&mc13783->spidev->dev, -1, &cell, 1, NULL, 0); | ||
535 | } | ||
536 | |||
537 | static int mc13783_add_subdevice(struct mc13783 *mc13783, const char *name) | ||
538 | { | ||
539 | return mc13783_add_subdevice_pdata(mc13783, name, NULL, 0); | ||
276 | } | 540 | } |
277 | EXPORT_SYMBOL_GPL(mc13783_adc_set_ts_status); | ||
278 | 541 | ||
279 | static int mc13783_check_revision(struct mc13783 *mc13783) | 542 | static int mc13783_check_revision(struct mc13783 *mc13783) |
280 | { | 543 | { |
281 | u32 rev_id, rev1, rev2, finid, icid; | 544 | u32 rev_id, rev1, rev2, finid, icid; |
282 | 545 | ||
283 | mc13783_read(mc13783, MC13783_REG_REVISION, &rev_id); | 546 | mc13783_reg_read(mc13783, MC13783_REG_REVISION, &rev_id); |
284 | 547 | ||
285 | rev1 = (rev_id & 0x018) >> 3; | 548 | rev1 = (rev_id & 0x018) >> 3; |
286 | rev2 = (rev_id & 0x007); | 549 | rev2 = (rev_id & 0x007); |
@@ -292,38 +555,24 @@ static int mc13783_check_revision(struct mc13783 *mc13783) | |||
292 | rev1 = 3; | 555 | rev1 = 3; |
293 | 556 | ||
294 | if (rev1 == 0 || icid != 2) { | 557 | if (rev1 == 0 || icid != 2) { |
295 | dev_err(mc13783->dev, "No MC13783 detected.\n"); | 558 | dev_err(&mc13783->spidev->dev, "No MC13783 detected.\n"); |
296 | return -ENODEV; | 559 | return -ENODEV; |
297 | } | 560 | } |
298 | 561 | ||
299 | mc13783->revision = ((rev1 * 10) + rev2); | 562 | dev_info(&mc13783->spidev->dev, |
300 | dev_info(mc13783->dev, "MC13783 Rev %d.%d FinVer %x detected\n", rev1, | 563 | "MC13783 Rev %d.%d FinVer %x detected\n", |
301 | rev2, finid); | 564 | rev1, rev2, finid); |
302 | 565 | ||
303 | return 0; | 566 | return 0; |
304 | } | 567 | } |
305 | 568 | ||
306 | /* | 569 | static int mc13783_probe(struct spi_device *spi) |
307 | * Register a client device. This is non-fatal since there is no need to | ||
308 | * fail the entire device init due to a single platform device failing. | ||
309 | */ | ||
310 | static void mc13783_client_dev_register(struct mc13783 *mc13783, | ||
311 | const char *name) | ||
312 | { | ||
313 | struct mfd_cell cell = {}; | ||
314 | |||
315 | cell.name = name; | ||
316 | |||
317 | mfd_add_devices(mc13783->dev, -1, &cell, 1, NULL, 0); | ||
318 | } | ||
319 | |||
320 | static int __devinit mc13783_probe(struct spi_device *spi) | ||
321 | { | 570 | { |
322 | struct mc13783 *mc13783; | 571 | struct mc13783 *mc13783; |
323 | struct mc13783_platform_data *pdata = spi->dev.platform_data; | 572 | struct mc13783_platform_data *pdata = dev_get_platdata(&spi->dev); |
324 | int ret; | 573 | int ret; |
325 | 574 | ||
326 | mc13783 = kzalloc(sizeof(struct mc13783), GFP_KERNEL); | 575 | mc13783 = kzalloc(sizeof(*mc13783), GFP_KERNEL); |
327 | if (!mc13783) | 576 | if (!mc13783) |
328 | return -ENOMEM; | 577 | return -ENOMEM; |
329 | 578 | ||
@@ -332,96 +581,104 @@ static int __devinit mc13783_probe(struct spi_device *spi) | |||
332 | spi->bits_per_word = 32; | 581 | spi->bits_per_word = 32; |
333 | spi_setup(spi); | 582 | spi_setup(spi); |
334 | 583 | ||
335 | mc13783->spi_device = spi; | 584 | mc13783->spidev = spi; |
336 | mc13783->dev = &spi->dev; | 585 | |
337 | mc13783->irq = spi->irq; | 586 | mutex_init(&mc13783->lock); |
587 | mc13783_lock(mc13783); | ||
588 | |||
589 | ret = mc13783_check_revision(mc13783); | ||
590 | if (ret) | ||
591 | goto err_revision; | ||
592 | |||
593 | /* mask all irqs */ | ||
594 | ret = mc13783_reg_write(mc13783, MC13783_IRQMASK0, 0x00ffffff); | ||
595 | if (ret) | ||
596 | goto err_mask; | ||
338 | 597 | ||
339 | INIT_WORK(&mc13783->work, mc13783_irq_work); | 598 | ret = mc13783_reg_write(mc13783, MC13783_IRQMASK1, 0x00ffffff); |
340 | mutex_init(&mc13783->io_lock); | 599 | if (ret) |
341 | mutex_init(&mc13783->adc_conv_lock); | 600 | goto err_mask; |
342 | init_completion(&mc13783->adc_done); | 601 | |
602 | ret = request_threaded_irq(spi->irq, NULL, mc13783_irq_thread, | ||
603 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13783", mc13783); | ||
604 | |||
605 | if (ret) { | ||
606 | err_mask: | ||
607 | err_revision: | ||
608 | mutex_unlock(&mc13783->lock); | ||
609 | dev_set_drvdata(&spi->dev, NULL); | ||
610 | kfree(mc13783); | ||
611 | return ret; | ||
612 | } | ||
343 | 613 | ||
614 | /* This should go away (BEGIN) */ | ||
344 | if (pdata) { | 615 | if (pdata) { |
345 | mc13783->flags = pdata->flags; | 616 | mc13783->flags = pdata->flags; |
346 | mc13783->regulators = pdata->regulators; | 617 | mc13783->regulators = pdata->regulators; |
347 | mc13783->num_regulators = pdata->num_regulators; | 618 | mc13783->num_regulators = pdata->num_regulators; |
348 | } | 619 | } |
620 | /* This should go away (END) */ | ||
349 | 621 | ||
350 | if (mc13783_check_revision(mc13783)) { | 622 | if (pdata->flags & MC13783_USE_ADC) |
351 | ret = -ENODEV; | 623 | mc13783_add_subdevice(mc13783, "mc13783-adc"); |
352 | goto err_out; | 624 | |
625 | if (pdata->flags & MC13783_USE_CODEC) | ||
626 | mc13783_add_subdevice(mc13783, "mc13783-codec"); | ||
627 | |||
628 | if (pdata->flags & MC13783_USE_REGULATOR) { | ||
629 | struct mc13783_regulator_platform_data regulator_pdata = { | ||
630 | .num_regulators = pdata->num_regulators, | ||
631 | .regulators = pdata->regulators, | ||
632 | }; | ||
633 | |||
634 | mc13783_add_subdevice_pdata(mc13783, "mc13783-regulator", | ||
635 | ®ulator_pdata, sizeof(regulator_pdata)); | ||
353 | } | 636 | } |
354 | 637 | ||
355 | /* clear and mask all interrupts */ | 638 | if (pdata->flags & MC13783_USE_RTC) |
356 | mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_STATUS_0, 0x00ffffff); | 639 | mc13783_add_subdevice(mc13783, "mc13783-rtc"); |
357 | mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_MASK_0, 0x00ffffff); | ||
358 | mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_STATUS_1, 0x00ffffff); | ||
359 | mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_MASK_1, 0x00ffffff); | ||
360 | 640 | ||
361 | /* unmask adcdone interrupts */ | 641 | if (pdata->flags & MC13783_USE_TOUCHSCREEN) |
362 | mc13783_set_bits(mc13783, MC13783_REG_INTERRUPT_MASK_0, | 642 | mc13783_add_subdevice(mc13783, "mc13783-ts"); |
363 | MC13783_INT_MASK_ADCDONEM, 0); | ||
364 | 643 | ||
365 | ret = request_irq(mc13783->irq, mc13783_interrupt, | 644 | mc13783_unlock(mc13783); |
366 | IRQF_DISABLED | IRQF_TRIGGER_HIGH, "mc13783", | ||
367 | mc13783); | ||
368 | if (ret) | ||
369 | goto err_out; | ||
370 | |||
371 | if (mc13783->flags & MC13783_USE_CODEC) | ||
372 | mc13783_client_dev_register(mc13783, "mc13783-codec"); | ||
373 | if (mc13783->flags & MC13783_USE_ADC) | ||
374 | mc13783_client_dev_register(mc13783, "mc13783-adc"); | ||
375 | if (mc13783->flags & MC13783_USE_RTC) | ||
376 | mc13783_client_dev_register(mc13783, "mc13783-rtc"); | ||
377 | if (mc13783->flags & MC13783_USE_REGULATOR) | ||
378 | mc13783_client_dev_register(mc13783, "mc13783-regulator"); | ||
379 | if (mc13783->flags & MC13783_USE_TOUCHSCREEN) | ||
380 | mc13783_client_dev_register(mc13783, "mc13783-ts"); | ||
381 | 645 | ||
382 | return 0; | 646 | return 0; |
383 | |||
384 | err_out: | ||
385 | kfree(mc13783); | ||
386 | return ret; | ||
387 | } | 647 | } |
388 | 648 | ||
389 | static int __devexit mc13783_remove(struct spi_device *spi) | 649 | static int __devexit mc13783_remove(struct spi_device *spi) |
390 | { | 650 | { |
391 | struct mc13783 *mc13783; | 651 | struct mc13783 *mc13783 = dev_get_drvdata(&spi->dev); |
392 | 652 | ||
393 | mc13783 = dev_get_drvdata(&spi->dev); | 653 | free_irq(mc13783->spidev->irq, mc13783); |
394 | |||
395 | free_irq(mc13783->irq, mc13783); | ||
396 | 654 | ||
397 | mfd_remove_devices(&spi->dev); | 655 | mfd_remove_devices(&spi->dev); |
398 | 656 | ||
399 | return 0; | 657 | return 0; |
400 | } | 658 | } |
401 | 659 | ||
402 | static struct spi_driver pmic_driver = { | 660 | static struct spi_driver mc13783_driver = { |
403 | .driver = { | 661 | .driver = { |
404 | .name = "mc13783", | 662 | .name = "mc13783", |
405 | .bus = &spi_bus_type, | 663 | .bus = &spi_bus_type, |
406 | .owner = THIS_MODULE, | 664 | .owner = THIS_MODULE, |
407 | }, | 665 | }, |
408 | .probe = mc13783_probe, | 666 | .probe = mc13783_probe, |
409 | .remove = __devexit_p(mc13783_remove), | 667 | .remove = __devexit_p(mc13783_remove), |
410 | }; | 668 | }; |
411 | 669 | ||
412 | static int __init pmic_init(void) | 670 | static int __init mc13783_init(void) |
413 | { | 671 | { |
414 | return spi_register_driver(&pmic_driver); | 672 | return spi_register_driver(&mc13783_driver); |
415 | } | 673 | } |
416 | subsys_initcall(pmic_init); | 674 | subsys_initcall(mc13783_init); |
417 | 675 | ||
418 | static void __exit pmic_exit(void) | 676 | static void __exit mc13783_exit(void) |
419 | { | 677 | { |
420 | spi_unregister_driver(&pmic_driver); | 678 | spi_unregister_driver(&mc13783_driver); |
421 | } | 679 | } |
422 | module_exit(pmic_exit); | 680 | module_exit(mc13783_exit); |
423 | |||
424 | MODULE_DESCRIPTION("Core/Protocol driver for Freescale MC13783 PMIC"); | ||
425 | MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); | ||
426 | MODULE_LICENSE("GPL"); | ||
427 | 681 | ||
682 | MODULE_DESCRIPTION("Core driver for Freescale MC13783 PMIC"); | ||
683 | MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); | ||
684 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c index 57271cb3b316..84815f9ef636 100644 --- a/drivers/mfd/mcp-core.c +++ b/drivers/mfd/mcp-core.c | |||
@@ -17,11 +17,11 @@ | |||
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/string.h> | 19 | #include <linux/string.h> |
20 | #include <linux/mfd/mcp.h> | ||
20 | 21 | ||
21 | #include <mach/dma.h> | 22 | #include <mach/dma.h> |
22 | #include <asm/system.h> | 23 | #include <asm/system.h> |
23 | 24 | ||
24 | #include "mcp.h" | ||
25 | 25 | ||
26 | #define to_mcp(d) container_of(d, struct mcp, attached_device) | 26 | #define to_mcp(d) container_of(d, struct mcp, attached_device) |
27 | #define to_mcp_driver(d) container_of(d, struct mcp_driver, drv) | 27 | #define to_mcp_driver(d) container_of(d, struct mcp_driver, drv) |
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 62b32dabf629..258427232728 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/spinlock.h> | 19 | #include <linux/spinlock.h> |
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/mfd/mcp.h> | ||
22 | 23 | ||
23 | #include <mach/dma.h> | 24 | #include <mach/dma.h> |
24 | #include <mach/hardware.h> | 25 | #include <mach/hardware.h> |
@@ -28,7 +29,6 @@ | |||
28 | 29 | ||
29 | #include <mach/assabet.h> | 30 | #include <mach/assabet.h> |
30 | 31 | ||
31 | #include "mcp.h" | ||
32 | 32 | ||
33 | struct mcp_sa11x0 { | 33 | struct mcp_sa11x0 { |
34 | u32 mccr0; | 34 | u32 mccr0; |
@@ -163,6 +163,7 @@ static int mcp_sa11x0_probe(struct platform_device *pdev) | |||
163 | mcp->dma_audio_wr = DMA_Ser4MCP0Wr; | 163 | mcp->dma_audio_wr = DMA_Ser4MCP0Wr; |
164 | mcp->dma_telco_rd = DMA_Ser4MCP1Rd; | 164 | mcp->dma_telco_rd = DMA_Ser4MCP1Rd; |
165 | mcp->dma_telco_wr = DMA_Ser4MCP1Wr; | 165 | mcp->dma_telco_wr = DMA_Ser4MCP1Wr; |
166 | mcp->gpio_base = data->gpio_base; | ||
166 | 167 | ||
167 | platform_set_drvdata(pdev, mcp); | 168 | platform_set_drvdata(pdev, mcp); |
168 | 169 | ||
diff --git a/drivers/mfd/mcp.h b/drivers/mfd/mcp.h deleted file mode 100644 index c093a93b8808..000000000000 --- a/drivers/mfd/mcp.h +++ /dev/null | |||
@@ -1,66 +0,0 @@ | |||
1 | /* | ||
2 | * linux/drivers/mfd/mcp.h | ||
3 | * | ||
4 | * Copyright (C) 2001 Russell King, All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License. | ||
9 | */ | ||
10 | #ifndef MCP_H | ||
11 | #define MCP_H | ||
12 | |||
13 | struct mcp_ops; | ||
14 | |||
15 | struct mcp { | ||
16 | struct module *owner; | ||
17 | struct mcp_ops *ops; | ||
18 | spinlock_t lock; | ||
19 | int use_count; | ||
20 | unsigned int sclk_rate; | ||
21 | unsigned int rw_timeout; | ||
22 | dma_device_t dma_audio_rd; | ||
23 | dma_device_t dma_audio_wr; | ||
24 | dma_device_t dma_telco_rd; | ||
25 | dma_device_t dma_telco_wr; | ||
26 | struct device attached_device; | ||
27 | }; | ||
28 | |||
29 | struct mcp_ops { | ||
30 | void (*set_telecom_divisor)(struct mcp *, unsigned int); | ||
31 | void (*set_audio_divisor)(struct mcp *, unsigned int); | ||
32 | void (*reg_write)(struct mcp *, unsigned int, unsigned int); | ||
33 | unsigned int (*reg_read)(struct mcp *, unsigned int); | ||
34 | void (*enable)(struct mcp *); | ||
35 | void (*disable)(struct mcp *); | ||
36 | }; | ||
37 | |||
38 | void mcp_set_telecom_divisor(struct mcp *, unsigned int); | ||
39 | void mcp_set_audio_divisor(struct mcp *, unsigned int); | ||
40 | void mcp_reg_write(struct mcp *, unsigned int, unsigned int); | ||
41 | unsigned int mcp_reg_read(struct mcp *, unsigned int); | ||
42 | void mcp_enable(struct mcp *); | ||
43 | void mcp_disable(struct mcp *); | ||
44 | #define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate) | ||
45 | |||
46 | struct mcp *mcp_host_alloc(struct device *, size_t); | ||
47 | int mcp_host_register(struct mcp *); | ||
48 | void mcp_host_unregister(struct mcp *); | ||
49 | |||
50 | struct mcp_driver { | ||
51 | struct device_driver drv; | ||
52 | int (*probe)(struct mcp *); | ||
53 | void (*remove)(struct mcp *); | ||
54 | int (*suspend)(struct mcp *, pm_message_t); | ||
55 | int (*resume)(struct mcp *); | ||
56 | }; | ||
57 | |||
58 | int mcp_driver_register(struct mcp_driver *); | ||
59 | void mcp_driver_unregister(struct mcp_driver *); | ||
60 | |||
61 | #define mcp_get_drvdata(mcp) dev_get_drvdata(&(mcp)->attached_device) | ||
62 | #define mcp_set_drvdata(mcp,d) dev_set_drvdata(&(mcp)->attached_device, d) | ||
63 | |||
64 | #define mcp_priv(mcp) ((void *)((mcp)+1)) | ||
65 | |||
66 | #endif | ||
diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index 4b364bae6b3e..970afa103261 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c | |||
@@ -44,7 +44,7 @@ | |||
44 | #include <asm/mach/irq.h> | 44 | #include <asm/mach/irq.h> |
45 | 45 | ||
46 | #include <mach/gpio.h> | 46 | #include <mach/gpio.h> |
47 | #include <mach/menelaus.h> | 47 | #include <plat/menelaus.h> |
48 | 48 | ||
49 | #define DRIVER_NAME "menelaus" | 49 | #define DRIVER_NAME "menelaus" |
50 | 50 | ||
diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c index 3d31e97d6a45..6d2e8466df1d 100644 --- a/drivers/mfd/pcf50633-adc.c +++ b/drivers/mfd/pcf50633-adc.c | |||
@@ -209,17 +209,16 @@ static void pcf50633_adc_irq(int irq, void *data) | |||
209 | 209 | ||
210 | static int __devinit pcf50633_adc_probe(struct platform_device *pdev) | 210 | static int __devinit pcf50633_adc_probe(struct platform_device *pdev) |
211 | { | 211 | { |
212 | struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data; | ||
213 | struct pcf50633_adc *adc; | 212 | struct pcf50633_adc *adc; |
214 | 213 | ||
215 | adc = kzalloc(sizeof(*adc), GFP_KERNEL); | 214 | adc = kzalloc(sizeof(*adc), GFP_KERNEL); |
216 | if (!adc) | 215 | if (!adc) |
217 | return -ENOMEM; | 216 | return -ENOMEM; |
218 | 217 | ||
219 | adc->pcf = pdata->pcf; | 218 | adc->pcf = dev_to_pcf50633(pdev->dev.parent); |
220 | platform_set_drvdata(pdev, adc); | 219 | platform_set_drvdata(pdev, adc); |
221 | 220 | ||
222 | pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ADCRDY, | 221 | pcf50633_register_irq(adc->pcf, PCF50633_IRQ_ADCRDY, |
223 | pcf50633_adc_irq, adc); | 222 | pcf50633_adc_irq, adc); |
224 | 223 | ||
225 | mutex_init(&adc->queue_mutex); | 224 | mutex_init(&adc->queue_mutex); |
diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index d26d7747175e..03dcc9200707 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c | |||
@@ -290,7 +290,7 @@ out: | |||
290 | 290 | ||
291 | int pcf50633_irq_mask(struct pcf50633 *pcf, int irq) | 291 | int pcf50633_irq_mask(struct pcf50633 *pcf, int irq) |
292 | { | 292 | { |
293 | dev_info(pcf->dev, "Masking IRQ %d\n", irq); | 293 | dev_dbg(pcf->dev, "Masking IRQ %d\n", irq); |
294 | 294 | ||
295 | return __pcf50633_irq_mask_set(pcf, irq, 1); | 295 | return __pcf50633_irq_mask_set(pcf, irq, 1); |
296 | } | 296 | } |
@@ -298,7 +298,7 @@ EXPORT_SYMBOL_GPL(pcf50633_irq_mask); | |||
298 | 298 | ||
299 | int pcf50633_irq_unmask(struct pcf50633 *pcf, int irq) | 299 | int pcf50633_irq_unmask(struct pcf50633 *pcf, int irq) |
300 | { | 300 | { |
301 | dev_info(pcf->dev, "Unmasking IRQ %d\n", irq); | 301 | dev_dbg(pcf->dev, "Unmasking IRQ %d\n", irq); |
302 | 302 | ||
303 | return __pcf50633_irq_mask_set(pcf, irq, 0); | 303 | return __pcf50633_irq_mask_set(pcf, irq, 0); |
304 | } | 304 | } |
@@ -345,6 +345,9 @@ static void pcf50633_irq_worker(struct work_struct *work) | |||
345 | goto out; | 345 | goto out; |
346 | } | 346 | } |
347 | 347 | ||
348 | /* defeat 8s death from lowsys on A5 */ | ||
349 | pcf50633_reg_write(pcf, PCF50633_REG_OOCSHDWN, 0x04); | ||
350 | |||
348 | /* We immediately read the usb and adapter status. We thus make sure | 351 | /* We immediately read the usb and adapter status. We thus make sure |
349 | * only of USBINS/USBREM IRQ handlers are called */ | 352 | * only of USBINS/USBREM IRQ handlers are called */ |
350 | if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) { | 353 | if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) { |
@@ -453,7 +456,6 @@ static void | |||
453 | pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name, | 456 | pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name, |
454 | struct platform_device **pdev) | 457 | struct platform_device **pdev) |
455 | { | 458 | { |
456 | struct pcf50633_subdev_pdata *subdev_pdata; | ||
457 | int ret; | 459 | int ret; |
458 | 460 | ||
459 | *pdev = platform_device_alloc(name, -1); | 461 | *pdev = platform_device_alloc(name, -1); |
@@ -462,15 +464,6 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name, | |||
462 | return; | 464 | return; |
463 | } | 465 | } |
464 | 466 | ||
465 | subdev_pdata = kmalloc(sizeof(*subdev_pdata), GFP_KERNEL); | ||
466 | if (!subdev_pdata) { | ||
467 | dev_err(pcf->dev, "Error allocating subdev pdata\n"); | ||
468 | platform_device_put(*pdev); | ||
469 | } | ||
470 | |||
471 | subdev_pdata->pcf = pcf; | ||
472 | platform_device_add_data(*pdev, subdev_pdata, sizeof(*subdev_pdata)); | ||
473 | |||
474 | (*pdev)->dev.parent = pcf->dev; | 467 | (*pdev)->dev.parent = pcf->dev; |
475 | 468 | ||
476 | ret = platform_device_add(*pdev); | 469 | ret = platform_device_add(*pdev); |
@@ -482,13 +475,13 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name, | |||
482 | } | 475 | } |
483 | 476 | ||
484 | #ifdef CONFIG_PM | 477 | #ifdef CONFIG_PM |
485 | static int pcf50633_suspend(struct device *dev, pm_message_t state) | 478 | static int pcf50633_suspend(struct i2c_client *client, pm_message_t state) |
486 | { | 479 | { |
487 | struct pcf50633 *pcf; | 480 | struct pcf50633 *pcf; |
488 | int ret = 0, i; | 481 | int ret = 0, i; |
489 | u8 res[5]; | 482 | u8 res[5]; |
490 | 483 | ||
491 | pcf = dev_get_drvdata(dev); | 484 | pcf = i2c_get_clientdata(client); |
492 | 485 | ||
493 | /* Make sure our interrupt handlers are not called | 486 | /* Make sure our interrupt handlers are not called |
494 | * henceforth */ | 487 | * henceforth */ |
@@ -523,12 +516,12 @@ out: | |||
523 | return ret; | 516 | return ret; |
524 | } | 517 | } |
525 | 518 | ||
526 | static int pcf50633_resume(struct device *dev) | 519 | static int pcf50633_resume(struct i2c_client *client) |
527 | { | 520 | { |
528 | struct pcf50633 *pcf; | 521 | struct pcf50633 *pcf; |
529 | int ret; | 522 | int ret; |
530 | 523 | ||
531 | pcf = dev_get_drvdata(dev); | 524 | pcf = i2c_get_clientdata(client); |
532 | 525 | ||
533 | /* Write the saved mask registers */ | 526 | /* Write the saved mask registers */ |
534 | ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M, | 527 | ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M, |
@@ -560,9 +553,14 @@ static int __devinit pcf50633_probe(struct i2c_client *client, | |||
560 | { | 553 | { |
561 | struct pcf50633 *pcf; | 554 | struct pcf50633 *pcf; |
562 | struct pcf50633_platform_data *pdata = client->dev.platform_data; | 555 | struct pcf50633_platform_data *pdata = client->dev.platform_data; |
563 | int i, ret = 0; | 556 | int i, ret; |
564 | int version, variant; | 557 | int version, variant; |
565 | 558 | ||
559 | if (!client->irq) { | ||
560 | dev_err(&client->dev, "Missing IRQ\n"); | ||
561 | return -ENOENT; | ||
562 | } | ||
563 | |||
566 | pcf = kzalloc(sizeof(*pcf), GFP_KERNEL); | 564 | pcf = kzalloc(sizeof(*pcf), GFP_KERNEL); |
567 | if (!pcf) | 565 | if (!pcf) |
568 | return -ENOMEM; | 566 | return -ENOMEM; |
@@ -577,6 +575,12 @@ static int __devinit pcf50633_probe(struct i2c_client *client, | |||
577 | pcf->irq = client->irq; | 575 | pcf->irq = client->irq; |
578 | pcf->work_queue = create_singlethread_workqueue("pcf50633"); | 576 | pcf->work_queue = create_singlethread_workqueue("pcf50633"); |
579 | 577 | ||
578 | if (!pcf->work_queue) { | ||
579 | dev_err(&client->dev, "Failed to alloc workqueue\n"); | ||
580 | ret = -ENOMEM; | ||
581 | goto err_free; | ||
582 | } | ||
583 | |||
580 | INIT_WORK(&pcf->irq_work, pcf50633_irq_worker); | 584 | INIT_WORK(&pcf->irq_work, pcf50633_irq_worker); |
581 | 585 | ||
582 | version = pcf50633_reg_read(pcf, 0); | 586 | version = pcf50633_reg_read(pcf, 0); |
@@ -584,7 +588,7 @@ static int __devinit pcf50633_probe(struct i2c_client *client, | |||
584 | if (version < 0 || variant < 0) { | 588 | if (version < 0 || variant < 0) { |
585 | dev_err(pcf->dev, "Unable to probe pcf50633\n"); | 589 | dev_err(pcf->dev, "Unable to probe pcf50633\n"); |
586 | ret = -ENODEV; | 590 | ret = -ENODEV; |
587 | goto err; | 591 | goto err_destroy_workqueue; |
588 | } | 592 | } |
589 | 593 | ||
590 | dev_info(pcf->dev, "Probed device version %d variant %d\n", | 594 | dev_info(pcf->dev, "Probed device version %d variant %d\n", |
@@ -598,6 +602,14 @@ static int __devinit pcf50633_probe(struct i2c_client *client, | |||
598 | pcf50633_reg_write(pcf, PCF50633_REG_INT4M, 0x00); | 602 | pcf50633_reg_write(pcf, PCF50633_REG_INT4M, 0x00); |
599 | pcf50633_reg_write(pcf, PCF50633_REG_INT5M, 0x00); | 603 | pcf50633_reg_write(pcf, PCF50633_REG_INT5M, 0x00); |
600 | 604 | ||
605 | ret = request_irq(client->irq, pcf50633_irq, | ||
606 | IRQF_TRIGGER_LOW, "pcf50633", pcf); | ||
607 | |||
608 | if (ret) { | ||
609 | dev_err(pcf->dev, "Failed to request IRQ %d\n", ret); | ||
610 | goto err_destroy_workqueue; | ||
611 | } | ||
612 | |||
601 | /* Create sub devices */ | 613 | /* Create sub devices */ |
602 | pcf50633_client_dev_register(pcf, "pcf50633-input", | 614 | pcf50633_client_dev_register(pcf, "pcf50633-input", |
603 | &pcf->input_pdev); | 615 | &pcf->input_pdev); |
@@ -613,31 +625,18 @@ static int __devinit pcf50633_probe(struct i2c_client *client, | |||
613 | 625 | ||
614 | pdev = platform_device_alloc("pcf50633-regltr", i); | 626 | pdev = platform_device_alloc("pcf50633-regltr", i); |
615 | if (!pdev) { | 627 | if (!pdev) { |
616 | dev_err(pcf->dev, "Cannot create regulator\n"); | 628 | dev_err(pcf->dev, "Cannot create regulator %d\n", i); |
617 | continue; | 629 | continue; |
618 | } | 630 | } |
619 | 631 | ||
620 | pdev->dev.parent = pcf->dev; | 632 | pdev->dev.parent = pcf->dev; |
621 | pdev->dev.platform_data = &pdata->reg_init_data[i]; | 633 | platform_device_add_data(pdev, &pdata->reg_init_data[i], |
622 | dev_set_drvdata(&pdev->dev, pcf); | 634 | sizeof(pdata->reg_init_data[i])); |
623 | pcf->regulator_pdev[i] = pdev; | 635 | pcf->regulator_pdev[i] = pdev; |
624 | 636 | ||
625 | platform_device_add(pdev); | 637 | platform_device_add(pdev); |
626 | } | 638 | } |
627 | 639 | ||
628 | if (client->irq) { | ||
629 | ret = request_irq(client->irq, pcf50633_irq, | ||
630 | IRQF_TRIGGER_LOW, "pcf50633", pcf); | ||
631 | |||
632 | if (ret) { | ||
633 | dev_err(pcf->dev, "Failed to request IRQ %d\n", ret); | ||
634 | goto err; | ||
635 | } | ||
636 | } else { | ||
637 | dev_err(pcf->dev, "No IRQ configured\n"); | ||
638 | goto err; | ||
639 | } | ||
640 | |||
641 | if (enable_irq_wake(client->irq) < 0) | 640 | if (enable_irq_wake(client->irq) < 0) |
642 | dev_err(pcf->dev, "IRQ %u cannot be enabled as wake-up source" | 641 | dev_err(pcf->dev, "IRQ %u cannot be enabled as wake-up source" |
643 | "in this hardware revision", client->irq); | 642 | "in this hardware revision", client->irq); |
@@ -651,9 +650,12 @@ static int __devinit pcf50633_probe(struct i2c_client *client, | |||
651 | 650 | ||
652 | return 0; | 651 | return 0; |
653 | 652 | ||
654 | err: | 653 | err_destroy_workqueue: |
655 | destroy_workqueue(pcf->work_queue); | 654 | destroy_workqueue(pcf->work_queue); |
655 | err_free: | ||
656 | i2c_set_clientdata(client, NULL); | ||
656 | kfree(pcf); | 657 | kfree(pcf); |
658 | |||
657 | return ret; | 659 | return ret; |
658 | } | 660 | } |
659 | 661 | ||
@@ -686,12 +688,12 @@ static struct i2c_device_id pcf50633_id_table[] = { | |||
686 | static struct i2c_driver pcf50633_driver = { | 688 | static struct i2c_driver pcf50633_driver = { |
687 | .driver = { | 689 | .driver = { |
688 | .name = "pcf50633", | 690 | .name = "pcf50633", |
689 | .suspend = pcf50633_suspend, | ||
690 | .resume = pcf50633_resume, | ||
691 | }, | 691 | }, |
692 | .id_table = pcf50633_id_table, | 692 | .id_table = pcf50633_id_table, |
693 | .probe = pcf50633_probe, | 693 | .probe = pcf50633_probe, |
694 | .remove = __devexit_p(pcf50633_remove), | 694 | .remove = __devexit_p(pcf50633_remove), |
695 | .suspend = pcf50633_suspend, | ||
696 | .resume = pcf50633_resume, | ||
695 | }; | 697 | }; |
696 | 698 | ||
697 | static int __init pcf50633_init(void) | 699 | static int __init pcf50633_init(void) |
diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c new file mode 100644 index 000000000000..03efae8041ab --- /dev/null +++ b/drivers/mfd/sh_mobile_sdhi.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * SuperH Mobile SDHI | ||
3 | * | ||
4 | * Copyright (C) 2009 Magnus Damm | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * Based on "Compaq ASIC3 support": | ||
11 | * | ||
12 | * Copyright 2001 Compaq Computer Corporation. | ||
13 | * Copyright 2004-2005 Phil Blundell | ||
14 | * Copyright 2007-2008 OpenedHand Ltd. | ||
15 | * | ||
16 | * Authors: Phil Blundell <pb@handhelds.org>, | ||
17 | * Samuel Ortiz <sameo@openedhand.com> | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/clk.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | #include <linux/mfd/core.h> | ||
26 | #include <linux/mfd/tmio.h> | ||
27 | #include <linux/mfd/sh_mobile_sdhi.h> | ||
28 | |||
29 | struct sh_mobile_sdhi { | ||
30 | struct clk *clk; | ||
31 | struct tmio_mmc_data mmc_data; | ||
32 | struct mfd_cell cell_mmc; | ||
33 | }; | ||
34 | |||
35 | static struct resource sh_mobile_sdhi_resources[] = { | ||
36 | { | ||
37 | .start = 0x000, | ||
38 | .end = 0x1ff, | ||
39 | .flags = IORESOURCE_MEM, | ||
40 | }, | ||
41 | { | ||
42 | .start = 0, | ||
43 | .end = 0, | ||
44 | .flags = IORESOURCE_IRQ, | ||
45 | }, | ||
46 | }; | ||
47 | |||
48 | static struct mfd_cell sh_mobile_sdhi_cell = { | ||
49 | .name = "tmio-mmc", | ||
50 | .num_resources = ARRAY_SIZE(sh_mobile_sdhi_resources), | ||
51 | .resources = sh_mobile_sdhi_resources, | ||
52 | }; | ||
53 | |||
54 | static void sh_mobile_sdhi_set_pwr(struct platform_device *tmio, int state) | ||
55 | { | ||
56 | struct platform_device *pdev = to_platform_device(tmio->dev.parent); | ||
57 | struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; | ||
58 | |||
59 | if (p && p->set_pwr) | ||
60 | p->set_pwr(pdev, state); | ||
61 | } | ||
62 | |||
63 | static int __init sh_mobile_sdhi_probe(struct platform_device *pdev) | ||
64 | { | ||
65 | struct sh_mobile_sdhi *priv; | ||
66 | struct resource *mem; | ||
67 | char clk_name[8]; | ||
68 | int ret, irq; | ||
69 | |||
70 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
71 | if (!mem) | ||
72 | dev_err(&pdev->dev, "missing MEM resource\n"); | ||
73 | |||
74 | irq = platform_get_irq(pdev, 0); | ||
75 | if (irq < 0) | ||
76 | dev_err(&pdev->dev, "missing IRQ resource\n"); | ||
77 | |||
78 | if (!mem || (irq < 0)) | ||
79 | return -EINVAL; | ||
80 | |||
81 | priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL); | ||
82 | if (priv == NULL) { | ||
83 | dev_err(&pdev->dev, "kzalloc failed\n"); | ||
84 | return -ENOMEM; | ||
85 | } | ||
86 | |||
87 | snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id); | ||
88 | priv->clk = clk_get(&pdev->dev, clk_name); | ||
89 | if (IS_ERR(priv->clk)) { | ||
90 | dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); | ||
91 | ret = PTR_ERR(priv->clk); | ||
92 | kfree(priv); | ||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | clk_enable(priv->clk); | ||
97 | |||
98 | /* FIXME: silly const unsigned int hclk */ | ||
99 | *(unsigned int *)&priv->mmc_data.hclk = clk_get_rate(priv->clk); | ||
100 | priv->mmc_data.set_pwr = sh_mobile_sdhi_set_pwr; | ||
101 | |||
102 | memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc)); | ||
103 | priv->cell_mmc.driver_data = &priv->mmc_data; | ||
104 | priv->cell_mmc.platform_data = &priv->cell_mmc; | ||
105 | priv->cell_mmc.data_size = sizeof(priv->cell_mmc); | ||
106 | |||
107 | platform_set_drvdata(pdev, priv); | ||
108 | |||
109 | ret = mfd_add_devices(&pdev->dev, pdev->id, | ||
110 | &priv->cell_mmc, 1, mem, irq); | ||
111 | if (ret) { | ||
112 | clk_disable(priv->clk); | ||
113 | clk_put(priv->clk); | ||
114 | kfree(priv); | ||
115 | } | ||
116 | |||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | static int sh_mobile_sdhi_remove(struct platform_device *pdev) | ||
121 | { | ||
122 | struct sh_mobile_sdhi *priv = platform_get_drvdata(pdev); | ||
123 | |||
124 | mfd_remove_devices(&pdev->dev); | ||
125 | clk_disable(priv->clk); | ||
126 | clk_put(priv->clk); | ||
127 | kfree(priv); | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static struct platform_driver sh_mobile_sdhi_driver = { | ||
133 | .driver = { | ||
134 | .name = "sh_mobile_sdhi", | ||
135 | .owner = THIS_MODULE, | ||
136 | }, | ||
137 | .probe = sh_mobile_sdhi_probe, | ||
138 | .remove = __devexit_p(sh_mobile_sdhi_remove), | ||
139 | }; | ||
140 | |||
141 | static int __init sh_mobile_sdhi_init(void) | ||
142 | { | ||
143 | return platform_driver_register(&sh_mobile_sdhi_driver); | ||
144 | } | ||
145 | |||
146 | static void __exit sh_mobile_sdhi_exit(void) | ||
147 | { | ||
148 | platform_driver_unregister(&sh_mobile_sdhi_driver); | ||
149 | } | ||
150 | |||
151 | module_init(sh_mobile_sdhi_init); | ||
152 | module_exit(sh_mobile_sdhi_exit); | ||
153 | |||
154 | MODULE_DESCRIPTION("SuperH Mobile SDHI driver"); | ||
155 | MODULE_AUTHOR("Magnus Damm"); | ||
156 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index acf8b9d5f575..e5955306c2fa 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c | |||
@@ -637,7 +637,7 @@ static int tps65010_probe(struct i2c_client *client, | |||
637 | tps, DEBUG_FOPS); | 637 | tps, DEBUG_FOPS); |
638 | 638 | ||
639 | /* optionally register GPIOs */ | 639 | /* optionally register GPIOs */ |
640 | if (board && board->base > 0) { | 640 | if (board && board->base != 0) { |
641 | tps->outmask = board->outmask; | 641 | tps->outmask = board->outmask; |
642 | 642 | ||
643 | tps->chip.label = client->name; | 643 | tps->chip.label = client->name; |
@@ -964,6 +964,34 @@ int tps65010_config_vregs1(unsigned value) | |||
964 | } | 964 | } |
965 | EXPORT_SYMBOL(tps65010_config_vregs1); | 965 | EXPORT_SYMBOL(tps65010_config_vregs1); |
966 | 966 | ||
967 | int tps65010_config_vdcdc2(unsigned value) | ||
968 | { | ||
969 | struct i2c_client *c; | ||
970 | int status; | ||
971 | |||
972 | if (!the_tps) | ||
973 | return -ENODEV; | ||
974 | |||
975 | c = the_tps->client; | ||
976 | mutex_lock(&the_tps->lock); | ||
977 | |||
978 | pr_debug("%s: vdcdc2 0x%02x\n", DRIVER_NAME, | ||
979 | i2c_smbus_read_byte_data(c, TPS_VDCDC2)); | ||
980 | |||
981 | status = i2c_smbus_write_byte_data(c, TPS_VDCDC2, value); | ||
982 | |||
983 | if (status != 0) | ||
984 | printk(KERN_ERR "%s: Failed to write vdcdc2 register\n", | ||
985 | DRIVER_NAME); | ||
986 | else | ||
987 | pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, | ||
988 | i2c_smbus_read_byte_data(c, TPS_VDCDC2)); | ||
989 | |||
990 | mutex_unlock(&the_tps->lock); | ||
991 | return status; | ||
992 | } | ||
993 | EXPORT_SYMBOL(tps65010_config_vdcdc2); | ||
994 | |||
967 | /*-------------------------------------------------------------------------*/ | 995 | /*-------------------------------------------------------------------------*/ |
968 | /* tps65013_set_low_pwr parameter: | 996 | /* tps65013_set_low_pwr parameter: |
969 | * mode: ON or OFF | 997 | * mode: ON or OFF |
diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl-core.c index a1c47ee95c0e..2a7606534196 100644 --- a/drivers/mfd/twl4030-core.c +++ b/drivers/mfd/twl-core.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * twl4030_core.c - driver for TWL4030/TPS659x0 PM and audio CODEC devices | 2 | * twl_core.c - driver for TWL4030/TWL5030/TWL60X0/TPS659x0 PM |
3 | * and audio CODEC devices | ||
3 | * | 4 | * |
4 | * Copyright (C) 2005-2006 Texas Instruments, Inc. | 5 | * Copyright (C) 2005-2006 Texas Instruments, Inc. |
5 | * | 6 | * |
@@ -36,10 +37,10 @@ | |||
36 | #include <linux/regulator/machine.h> | 37 | #include <linux/regulator/machine.h> |
37 | 38 | ||
38 | #include <linux/i2c.h> | 39 | #include <linux/i2c.h> |
39 | #include <linux/i2c/twl4030.h> | 40 | #include <linux/i2c/twl.h> |
40 | 41 | ||
41 | #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) | 42 | #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) |
42 | #include <mach/cpu.h> | 43 | #include <plat/cpu.h> |
43 | #endif | 44 | #endif |
44 | 45 | ||
45 | /* | 46 | /* |
@@ -55,7 +56,7 @@ | |||
55 | * (and associated registers). | 56 | * (and associated registers). |
56 | */ | 57 | */ |
57 | 58 | ||
58 | #define DRIVER_NAME "twl4030" | 59 | #define DRIVER_NAME "twl" |
59 | 60 | ||
60 | #if defined(CONFIG_TWL4030_BCI_BATTERY) || \ | 61 | #if defined(CONFIG_TWL4030_BCI_BATTERY) || \ |
61 | defined(CONFIG_TWL4030_BCI_BATTERY_MODULE) | 62 | defined(CONFIG_TWL4030_BCI_BATTERY_MODULE) |
@@ -114,12 +115,18 @@ | |||
114 | #define twl_has_watchdog() false | 115 | #define twl_has_watchdog() false |
115 | #endif | 116 | #endif |
116 | 117 | ||
118 | #if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE) | ||
119 | #define twl_has_codec() true | ||
120 | #else | ||
121 | #define twl_has_codec() false | ||
122 | #endif | ||
123 | |||
117 | /* Triton Core internal information (BEGIN) */ | 124 | /* Triton Core internal information (BEGIN) */ |
118 | 125 | ||
119 | /* Last - for index max*/ | 126 | /* Last - for index max*/ |
120 | #define TWL4030_MODULE_LAST TWL4030_MODULE_SECURED_REG | 127 | #define TWL4030_MODULE_LAST TWL4030_MODULE_SECURED_REG |
121 | 128 | ||
122 | #define TWL4030_NUM_SLAVES 4 | 129 | #define TWL_NUM_SLAVES 4 |
123 | 130 | ||
124 | #if defined(CONFIG_INPUT_TWL4030_PWRBUTTON) \ | 131 | #if defined(CONFIG_INPUT_TWL4030_PWRBUTTON) \ |
125 | || defined(CONFIG_INPUT_TWL4030_PWBUTTON_MODULE) | 132 | || defined(CONFIG_INPUT_TWL4030_PWBUTTON_MODULE) |
@@ -128,6 +135,13 @@ | |||
128 | #define twl_has_pwrbutton() false | 135 | #define twl_has_pwrbutton() false |
129 | #endif | 136 | #endif |
130 | 137 | ||
138 | #define SUB_CHIP_ID0 0 | ||
139 | #define SUB_CHIP_ID1 1 | ||
140 | #define SUB_CHIP_ID2 2 | ||
141 | #define SUB_CHIP_ID3 3 | ||
142 | |||
143 | #define TWL_MODULE_LAST TWL4030_MODULE_LAST | ||
144 | |||
131 | /* Base Address defns for twl4030_map[] */ | 145 | /* Base Address defns for twl4030_map[] */ |
132 | 146 | ||
133 | /* subchip/slave 0 - USB ID */ | 147 | /* subchip/slave 0 - USB ID */ |
@@ -152,6 +166,10 @@ | |||
152 | #define TWL4030_BASEADD_PWMB 0x00F1 | 166 | #define TWL4030_BASEADD_PWMB 0x00F1 |
153 | #define TWL4030_BASEADD_KEYPAD 0x00D2 | 167 | #define TWL4030_BASEADD_KEYPAD 0x00D2 |
154 | 168 | ||
169 | #define TWL5031_BASEADD_ACCESSORY 0x0074 /* Replaces Main Charge */ | ||
170 | #define TWL5031_BASEADD_INTERRUPTS 0x00B9 /* Different than TWL4030's | ||
171 | one */ | ||
172 | |||
155 | /* subchip/slave 3 - POWER ID */ | 173 | /* subchip/slave 3 - POWER ID */ |
156 | #define TWL4030_BASEADD_BACKUP 0x0014 | 174 | #define TWL4030_BASEADD_BACKUP 0x0014 |
157 | #define TWL4030_BASEADD_INT 0x002E | 175 | #define TWL4030_BASEADD_INT 0x002E |
@@ -163,6 +181,30 @@ | |||
163 | /* Triton Core internal information (END) */ | 181 | /* Triton Core internal information (END) */ |
164 | 182 | ||
165 | 183 | ||
184 | /* subchip/slave 0 0x48 - POWER */ | ||
185 | #define TWL6030_BASEADD_RTC 0x0000 | ||
186 | #define TWL6030_BASEADD_MEM 0x0017 | ||
187 | #define TWL6030_BASEADD_PM_MASTER 0x001F | ||
188 | #define TWL6030_BASEADD_PM_SLAVE_MISC 0x0030 /* PM_RECEIVER */ | ||
189 | #define TWL6030_BASEADD_PM_MISC 0x00E2 | ||
190 | #define TWL6030_BASEADD_PM_PUPD 0x00F0 | ||
191 | |||
192 | /* subchip/slave 1 0x49 - FEATURE */ | ||
193 | #define TWL6030_BASEADD_USB 0x0000 | ||
194 | #define TWL6030_BASEADD_GPADC_CTRL 0x002E | ||
195 | #define TWL6030_BASEADD_AUX 0x0090 | ||
196 | #define TWL6030_BASEADD_PWM 0x00BA | ||
197 | #define TWL6030_BASEADD_GASGAUGE 0x00C0 | ||
198 | #define TWL6030_BASEADD_PIH 0x00D0 | ||
199 | #define TWL6030_BASEADD_CHARGER 0x00E0 | ||
200 | |||
201 | /* subchip/slave 2 0x4A - DFT */ | ||
202 | #define TWL6030_BASEADD_DIEID 0x00C0 | ||
203 | |||
204 | /* subchip/slave 3 0x4B - AUDIO */ | ||
205 | #define TWL6030_BASEADD_AUDIO 0x0000 | ||
206 | #define TWL6030_BASEADD_RSV 0x0000 | ||
207 | |||
166 | /* Few power values */ | 208 | /* Few power values */ |
167 | #define R_CFG_BOOT 0x05 | 209 | #define R_CFG_BOOT 0x05 |
168 | #define R_PROTECT_KEY 0x0E | 210 | #define R_PROTECT_KEY 0x0E |
@@ -177,19 +219,29 @@ | |||
177 | #define HFCLK_FREQ_26_MHZ (2 << 0) | 219 | #define HFCLK_FREQ_26_MHZ (2 << 0) |
178 | #define HFCLK_FREQ_38p4_MHZ (3 << 0) | 220 | #define HFCLK_FREQ_38p4_MHZ (3 << 0) |
179 | #define HIGH_PERF_SQ (1 << 3) | 221 | #define HIGH_PERF_SQ (1 << 3) |
222 | #define CK32K_LOWPWR_EN (1 << 7) | ||
180 | 223 | ||
181 | 224 | ||
182 | /* chip-specific feature flags, for i2c_device_id.driver_data */ | 225 | /* chip-specific feature flags, for i2c_device_id.driver_data */ |
183 | #define TWL4030_VAUX2 BIT(0) /* pre-5030 voltage ranges */ | 226 | #define TWL4030_VAUX2 BIT(0) /* pre-5030 voltage ranges */ |
184 | #define TPS_SUBSET BIT(1) /* tps659[23]0 have fewer LDOs */ | 227 | #define TPS_SUBSET BIT(1) /* tps659[23]0 have fewer LDOs */ |
228 | #define TWL5031 BIT(2) /* twl5031 has different registers */ | ||
229 | #define TWL6030_CLASS BIT(3) /* TWL6030 class */ | ||
185 | 230 | ||
186 | /*----------------------------------------------------------------------*/ | 231 | /*----------------------------------------------------------------------*/ |
187 | 232 | ||
188 | /* is driver active, bound to a chip? */ | 233 | /* is driver active, bound to a chip? */ |
189 | static bool inuse; | 234 | static bool inuse; |
190 | 235 | ||
191 | /* Structure for each TWL4030 Slave */ | 236 | static unsigned int twl_id; |
192 | struct twl4030_client { | 237 | unsigned int twl_rev(void) |
238 | { | ||
239 | return twl_id; | ||
240 | } | ||
241 | EXPORT_SYMBOL(twl_rev); | ||
242 | |||
243 | /* Structure for each TWL4030/TWL6030 Slave */ | ||
244 | struct twl_client { | ||
193 | struct i2c_client *client; | 245 | struct i2c_client *client; |
194 | u8 address; | 246 | u8 address; |
195 | 247 | ||
@@ -200,19 +252,20 @@ struct twl4030_client { | |||
200 | struct mutex xfer_lock; | 252 | struct mutex xfer_lock; |
201 | }; | 253 | }; |
202 | 254 | ||
203 | static struct twl4030_client twl4030_modules[TWL4030_NUM_SLAVES]; | 255 | static struct twl_client twl_modules[TWL_NUM_SLAVES]; |
204 | 256 | ||
205 | 257 | ||
206 | /* mapping the module id to slave id and base address */ | 258 | /* mapping the module id to slave id and base address */ |
207 | struct twl4030mapping { | 259 | struct twl_mapping { |
208 | unsigned char sid; /* Slave ID */ | 260 | unsigned char sid; /* Slave ID */ |
209 | unsigned char base; /* base address */ | 261 | unsigned char base; /* base address */ |
210 | }; | 262 | }; |
263 | struct twl_mapping *twl_map; | ||
211 | 264 | ||
212 | static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { | 265 | static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { |
213 | /* | 266 | /* |
214 | * NOTE: don't change this table without updating the | 267 | * NOTE: don't change this table without updating the |
215 | * <linux/i2c/twl4030.h> defines for TWL4030_MODULE_* | 268 | * <linux/i2c/twl.h> defines for TWL4030_MODULE_* |
216 | * so they continue to match the order in this table. | 269 | * so they continue to match the order in this table. |
217 | */ | 270 | */ |
218 | 271 | ||
@@ -234,6 +287,8 @@ static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { | |||
234 | { 2, TWL4030_BASEADD_PWM1 }, | 287 | { 2, TWL4030_BASEADD_PWM1 }, |
235 | { 2, TWL4030_BASEADD_PWMA }, | 288 | { 2, TWL4030_BASEADD_PWMA }, |
236 | { 2, TWL4030_BASEADD_PWMB }, | 289 | { 2, TWL4030_BASEADD_PWMB }, |
290 | { 2, TWL5031_BASEADD_ACCESSORY }, | ||
291 | { 2, TWL5031_BASEADD_INTERRUPTS }, | ||
237 | 292 | ||
238 | { 3, TWL4030_BASEADD_BACKUP }, | 293 | { 3, TWL4030_BASEADD_BACKUP }, |
239 | { 3, TWL4030_BASEADD_INT }, | 294 | { 3, TWL4030_BASEADD_INT }, |
@@ -243,12 +298,46 @@ static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { | |||
243 | { 3, TWL4030_BASEADD_SECURED_REG }, | 298 | { 3, TWL4030_BASEADD_SECURED_REG }, |
244 | }; | 299 | }; |
245 | 300 | ||
301 | static struct twl_mapping twl6030_map[] = { | ||
302 | /* | ||
303 | * NOTE: don't change this table without updating the | ||
304 | * <linux/i2c/twl.h> defines for TWL4030_MODULE_* | ||
305 | * so they continue to match the order in this table. | ||
306 | */ | ||
307 | { SUB_CHIP_ID1, TWL6030_BASEADD_USB }, | ||
308 | { SUB_CHIP_ID3, TWL6030_BASEADD_AUDIO }, | ||
309 | { SUB_CHIP_ID2, TWL6030_BASEADD_DIEID }, | ||
310 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
311 | { SUB_CHIP_ID1, TWL6030_BASEADD_PIH }, | ||
312 | |||
313 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
314 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
315 | { SUB_CHIP_ID1, TWL6030_BASEADD_GPADC_CTRL }, | ||
316 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
317 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
318 | |||
319 | { SUB_CHIP_ID1, TWL6030_BASEADD_CHARGER }, | ||
320 | { SUB_CHIP_ID1, TWL6030_BASEADD_GASGAUGE }, | ||
321 | { SUB_CHIP_ID1, TWL6030_BASEADD_PWM }, | ||
322 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
323 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
324 | |||
325 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
326 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
327 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
328 | { SUB_CHIP_ID0, TWL6030_BASEADD_PM_MASTER }, | ||
329 | { SUB_CHIP_ID0, TWL6030_BASEADD_PM_SLAVE_MISC }, | ||
330 | |||
331 | { SUB_CHIP_ID0, TWL6030_BASEADD_RTC }, | ||
332 | { SUB_CHIP_ID0, TWL6030_BASEADD_MEM }, | ||
333 | }; | ||
334 | |||
246 | /*----------------------------------------------------------------------*/ | 335 | /*----------------------------------------------------------------------*/ |
247 | 336 | ||
248 | /* Exported Functions */ | 337 | /* Exported Functions */ |
249 | 338 | ||
250 | /** | 339 | /** |
251 | * twl4030_i2c_write - Writes a n bit register in TWL4030 | 340 | * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0 |
252 | * @mod_no: module number | 341 | * @mod_no: module number |
253 | * @value: an array of num_bytes+1 containing data to write | 342 | * @value: an array of num_bytes+1 containing data to write |
254 | * @reg: register address (just offset will do) | 343 | * @reg: register address (just offset will do) |
@@ -259,19 +348,19 @@ static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { | |||
259 | * | 348 | * |
260 | * Returns the result of operation - 0 is success | 349 | * Returns the result of operation - 0 is success |
261 | */ | 350 | */ |
262 | int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | 351 | int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) |
263 | { | 352 | { |
264 | int ret; | 353 | int ret; |
265 | int sid; | 354 | int sid; |
266 | struct twl4030_client *twl; | 355 | struct twl_client *twl; |
267 | struct i2c_msg *msg; | 356 | struct i2c_msg *msg; |
268 | 357 | ||
269 | if (unlikely(mod_no > TWL4030_MODULE_LAST)) { | 358 | if (unlikely(mod_no > TWL_MODULE_LAST)) { |
270 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); | 359 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); |
271 | return -EPERM; | 360 | return -EPERM; |
272 | } | 361 | } |
273 | sid = twl4030_map[mod_no].sid; | 362 | sid = twl_map[mod_no].sid; |
274 | twl = &twl4030_modules[sid]; | 363 | twl = &twl_modules[sid]; |
275 | 364 | ||
276 | if (unlikely(!inuse)) { | 365 | if (unlikely(!inuse)) { |
277 | pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid); | 366 | pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid); |
@@ -288,19 +377,26 @@ int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | |||
288 | msg->flags = 0; | 377 | msg->flags = 0; |
289 | msg->buf = value; | 378 | msg->buf = value; |
290 | /* over write the first byte of buffer with the register address */ | 379 | /* over write the first byte of buffer with the register address */ |
291 | *value = twl4030_map[mod_no].base + reg; | 380 | *value = twl_map[mod_no].base + reg; |
292 | ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 1); | 381 | ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 1); |
293 | mutex_unlock(&twl->xfer_lock); | 382 | mutex_unlock(&twl->xfer_lock); |
294 | 383 | ||
295 | /* i2cTransfer returns num messages.translate it pls.. */ | 384 | /* i2c_transfer returns number of messages transferred */ |
296 | if (ret >= 0) | 385 | if (ret != 1) { |
297 | ret = 0; | 386 | pr_err("%s: i2c_write failed to transfer all messages\n", |
298 | return ret; | 387 | DRIVER_NAME); |
388 | if (ret < 0) | ||
389 | return ret; | ||
390 | else | ||
391 | return -EIO; | ||
392 | } else { | ||
393 | return 0; | ||
394 | } | ||
299 | } | 395 | } |
300 | EXPORT_SYMBOL(twl4030_i2c_write); | 396 | EXPORT_SYMBOL(twl_i2c_write); |
301 | 397 | ||
302 | /** | 398 | /** |
303 | * twl4030_i2c_read - Reads a n bit register in TWL4030 | 399 | * twl_i2c_read - Reads a n bit register in TWL4030/TWL5030/TWL60X0 |
304 | * @mod_no: module number | 400 | * @mod_no: module number |
305 | * @value: an array of num_bytes containing data to be read | 401 | * @value: an array of num_bytes containing data to be read |
306 | * @reg: register address (just offset will do) | 402 | * @reg: register address (just offset will do) |
@@ -308,20 +404,20 @@ EXPORT_SYMBOL(twl4030_i2c_write); | |||
308 | * | 404 | * |
309 | * Returns result of operation - num_bytes is success else failure. | 405 | * Returns result of operation - num_bytes is success else failure. |
310 | */ | 406 | */ |
311 | int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | 407 | int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) |
312 | { | 408 | { |
313 | int ret; | 409 | int ret; |
314 | u8 val; | 410 | u8 val; |
315 | int sid; | 411 | int sid; |
316 | struct twl4030_client *twl; | 412 | struct twl_client *twl; |
317 | struct i2c_msg *msg; | 413 | struct i2c_msg *msg; |
318 | 414 | ||
319 | if (unlikely(mod_no > TWL4030_MODULE_LAST)) { | 415 | if (unlikely(mod_no > TWL_MODULE_LAST)) { |
320 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); | 416 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); |
321 | return -EPERM; | 417 | return -EPERM; |
322 | } | 418 | } |
323 | sid = twl4030_map[mod_no].sid; | 419 | sid = twl_map[mod_no].sid; |
324 | twl = &twl4030_modules[sid]; | 420 | twl = &twl_modules[sid]; |
325 | 421 | ||
326 | if (unlikely(!inuse)) { | 422 | if (unlikely(!inuse)) { |
327 | pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid); | 423 | pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid); |
@@ -333,7 +429,7 @@ int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | |||
333 | msg->addr = twl->address; | 429 | msg->addr = twl->address; |
334 | msg->len = 1; | 430 | msg->len = 1; |
335 | msg->flags = 0; /* Read the register value */ | 431 | msg->flags = 0; /* Read the register value */ |
336 | val = twl4030_map[mod_no].base + reg; | 432 | val = twl_map[mod_no].base + reg; |
337 | msg->buf = &val; | 433 | msg->buf = &val; |
338 | /* [MSG2] fill the data rx buffer */ | 434 | /* [MSG2] fill the data rx buffer */ |
339 | msg = &twl->xfer_msg[1]; | 435 | msg = &twl->xfer_msg[1]; |
@@ -344,45 +440,52 @@ int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | |||
344 | ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 2); | 440 | ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 2); |
345 | mutex_unlock(&twl->xfer_lock); | 441 | mutex_unlock(&twl->xfer_lock); |
346 | 442 | ||
347 | /* i2cTransfer returns num messages.translate it pls.. */ | 443 | /* i2c_transfer returns number of messages transferred */ |
348 | if (ret >= 0) | 444 | if (ret != 2) { |
349 | ret = 0; | 445 | pr_err("%s: i2c_read failed to transfer all messages\n", |
350 | return ret; | 446 | DRIVER_NAME); |
447 | if (ret < 0) | ||
448 | return ret; | ||
449 | else | ||
450 | return -EIO; | ||
451 | } else { | ||
452 | return 0; | ||
453 | } | ||
351 | } | 454 | } |
352 | EXPORT_SYMBOL(twl4030_i2c_read); | 455 | EXPORT_SYMBOL(twl_i2c_read); |
353 | 456 | ||
354 | /** | 457 | /** |
355 | * twl4030_i2c_write_u8 - Writes a 8 bit register in TWL4030 | 458 | * twl_i2c_write_u8 - Writes a 8 bit register in TWL4030/TWL5030/TWL60X0 |
356 | * @mod_no: module number | 459 | * @mod_no: module number |
357 | * @value: the value to be written 8 bit | 460 | * @value: the value to be written 8 bit |
358 | * @reg: register address (just offset will do) | 461 | * @reg: register address (just offset will do) |
359 | * | 462 | * |
360 | * Returns result of operation - 0 is success | 463 | * Returns result of operation - 0 is success |
361 | */ | 464 | */ |
362 | int twl4030_i2c_write_u8(u8 mod_no, u8 value, u8 reg) | 465 | int twl_i2c_write_u8(u8 mod_no, u8 value, u8 reg) |
363 | { | 466 | { |
364 | 467 | ||
365 | /* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */ | 468 | /* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */ |
366 | u8 temp_buffer[2] = { 0 }; | 469 | u8 temp_buffer[2] = { 0 }; |
367 | /* offset 1 contains the data */ | 470 | /* offset 1 contains the data */ |
368 | temp_buffer[1] = value; | 471 | temp_buffer[1] = value; |
369 | return twl4030_i2c_write(mod_no, temp_buffer, reg, 1); | 472 | return twl_i2c_write(mod_no, temp_buffer, reg, 1); |
370 | } | 473 | } |
371 | EXPORT_SYMBOL(twl4030_i2c_write_u8); | 474 | EXPORT_SYMBOL(twl_i2c_write_u8); |
372 | 475 | ||
373 | /** | 476 | /** |
374 | * twl4030_i2c_read_u8 - Reads a 8 bit register from TWL4030 | 477 | * twl_i2c_read_u8 - Reads a 8 bit register from TWL4030/TWL5030/TWL60X0 |
375 | * @mod_no: module number | 478 | * @mod_no: module number |
376 | * @value: the value read 8 bit | 479 | * @value: the value read 8 bit |
377 | * @reg: register address (just offset will do) | 480 | * @reg: register address (just offset will do) |
378 | * | 481 | * |
379 | * Returns result of operation - 0 is success | 482 | * Returns result of operation - 0 is success |
380 | */ | 483 | */ |
381 | int twl4030_i2c_read_u8(u8 mod_no, u8 *value, u8 reg) | 484 | int twl_i2c_read_u8(u8 mod_no, u8 *value, u8 reg) |
382 | { | 485 | { |
383 | return twl4030_i2c_read(mod_no, value, reg, 1); | 486 | return twl_i2c_read(mod_no, value, reg, 1); |
384 | } | 487 | } |
385 | EXPORT_SYMBOL(twl4030_i2c_read_u8); | 488 | EXPORT_SYMBOL(twl_i2c_read_u8); |
386 | 489 | ||
387 | /*----------------------------------------------------------------------*/ | 490 | /*----------------------------------------------------------------------*/ |
388 | 491 | ||
@@ -392,7 +495,7 @@ add_numbered_child(unsigned chip, const char *name, int num, | |||
392 | bool can_wakeup, int irq0, int irq1) | 495 | bool can_wakeup, int irq0, int irq1) |
393 | { | 496 | { |
394 | struct platform_device *pdev; | 497 | struct platform_device *pdev; |
395 | struct twl4030_client *twl = &twl4030_modules[chip]; | 498 | struct twl_client *twl = &twl_modules[chip]; |
396 | int status; | 499 | int status; |
397 | 500 | ||
398 | pdev = platform_device_alloc(name, num); | 501 | pdev = platform_device_alloc(name, num); |
@@ -450,6 +553,7 @@ add_regulator_linked(int num, struct regulator_init_data *pdata, | |||
450 | struct regulator_consumer_supply *consumers, | 553 | struct regulator_consumer_supply *consumers, |
451 | unsigned num_consumers) | 554 | unsigned num_consumers) |
452 | { | 555 | { |
556 | unsigned sub_chip_id; | ||
453 | /* regulator framework demands init_data ... */ | 557 | /* regulator framework demands init_data ... */ |
454 | if (!pdata) | 558 | if (!pdata) |
455 | return NULL; | 559 | return NULL; |
@@ -460,7 +564,8 @@ add_regulator_linked(int num, struct regulator_init_data *pdata, | |||
460 | } | 564 | } |
461 | 565 | ||
462 | /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ | 566 | /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ |
463 | return add_numbered_child(3, "twl4030_reg", num, | 567 | sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid; |
568 | return add_numbered_child(sub_chip_id, "twl_reg", num, | ||
464 | pdata, sizeof(*pdata), false, 0, 0); | 569 | pdata, sizeof(*pdata), false, 0, 0); |
465 | } | 570 | } |
466 | 571 | ||
@@ -480,29 +585,32 @@ static int | |||
480 | add_children(struct twl4030_platform_data *pdata, unsigned long features) | 585 | add_children(struct twl4030_platform_data *pdata, unsigned long features) |
481 | { | 586 | { |
482 | struct device *child; | 587 | struct device *child; |
588 | unsigned sub_chip_id; | ||
483 | 589 | ||
484 | if (twl_has_bci() && pdata->bci && !(features & TPS_SUBSET)) { | 590 | if (twl_has_bci() && pdata->bci && |
591 | !(features & (TPS_SUBSET | TWL5031))) { | ||
485 | child = add_child(3, "twl4030_bci", | 592 | child = add_child(3, "twl4030_bci", |
486 | pdata->bci, sizeof(*pdata->bci), | 593 | pdata->bci, sizeof(*pdata->bci), |
487 | false, | 594 | false, |
488 | /* irq0 = CHG_PRES, irq1 = BCI */ | 595 | /* irq0 = CHG_PRES, irq1 = BCI */ |
489 | pdata->irq_base + 8 + 1, pdata->irq_base + 2); | 596 | pdata->irq_base + BCI_PRES_INTR_OFFSET, |
597 | pdata->irq_base + BCI_INTR_OFFSET); | ||
490 | if (IS_ERR(child)) | 598 | if (IS_ERR(child)) |
491 | return PTR_ERR(child); | 599 | return PTR_ERR(child); |
492 | } | 600 | } |
493 | 601 | ||
494 | if (twl_has_gpio() && pdata->gpio) { | 602 | if (twl_has_gpio() && pdata->gpio) { |
495 | child = add_child(1, "twl4030_gpio", | 603 | child = add_child(SUB_CHIP_ID1, "twl4030_gpio", |
496 | pdata->gpio, sizeof(*pdata->gpio), | 604 | pdata->gpio, sizeof(*pdata->gpio), |
497 | false, pdata->irq_base + 0, 0); | 605 | false, pdata->irq_base + GPIO_INTR_OFFSET, 0); |
498 | if (IS_ERR(child)) | 606 | if (IS_ERR(child)) |
499 | return PTR_ERR(child); | 607 | return PTR_ERR(child); |
500 | } | 608 | } |
501 | 609 | ||
502 | if (twl_has_keypad() && pdata->keypad) { | 610 | if (twl_has_keypad() && pdata->keypad) { |
503 | child = add_child(2, "twl4030_keypad", | 611 | child = add_child(SUB_CHIP_ID2, "twl4030_keypad", |
504 | pdata->keypad, sizeof(*pdata->keypad), | 612 | pdata->keypad, sizeof(*pdata->keypad), |
505 | true, pdata->irq_base + 1, 0); | 613 | true, pdata->irq_base + KEYPAD_INTR_OFFSET, 0); |
506 | if (IS_ERR(child)) | 614 | if (IS_ERR(child)) |
507 | return PTR_ERR(child); | 615 | return PTR_ERR(child); |
508 | } | 616 | } |
@@ -510,7 +618,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
510 | if (twl_has_madc() && pdata->madc) { | 618 | if (twl_has_madc() && pdata->madc) { |
511 | child = add_child(2, "twl4030_madc", | 619 | child = add_child(2, "twl4030_madc", |
512 | pdata->madc, sizeof(*pdata->madc), | 620 | pdata->madc, sizeof(*pdata->madc), |
513 | true, pdata->irq_base + 3, 0); | 621 | true, pdata->irq_base + MADC_INTR_OFFSET, 0); |
514 | if (IS_ERR(child)) | 622 | if (IS_ERR(child)) |
515 | return PTR_ERR(child); | 623 | return PTR_ERR(child); |
516 | } | 624 | } |
@@ -523,14 +631,15 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
523 | * Eventually, Linux might become more aware of such | 631 | * Eventually, Linux might become more aware of such |
524 | * HW security concerns, and "least privilege". | 632 | * HW security concerns, and "least privilege". |
525 | */ | 633 | */ |
526 | child = add_child(3, "twl4030_rtc", | 634 | sub_chip_id = twl_map[TWL_MODULE_RTC].sid; |
635 | child = add_child(sub_chip_id, "twl_rtc", | ||
527 | NULL, 0, | 636 | NULL, 0, |
528 | true, pdata->irq_base + 8 + 3, 0); | 637 | true, pdata->irq_base + RTC_INTR_OFFSET, 0); |
529 | if (IS_ERR(child)) | 638 | if (IS_ERR(child)) |
530 | return PTR_ERR(child); | 639 | return PTR_ERR(child); |
531 | } | 640 | } |
532 | 641 | ||
533 | if (twl_has_usb() && pdata->usb) { | 642 | if (twl_has_usb() && pdata->usb && twl_class_is_4030()) { |
534 | 643 | ||
535 | static struct regulator_consumer_supply usb1v5 = { | 644 | static struct regulator_consumer_supply usb1v5 = { |
536 | .supply = "usb1v5", | 645 | .supply = "usb1v5", |
@@ -575,7 +684,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
575 | pdata->usb, sizeof(*pdata->usb), | 684 | pdata->usb, sizeof(*pdata->usb), |
576 | true, | 685 | true, |
577 | /* irq0 = USB_PRES, irq1 = USB */ | 686 | /* irq0 = USB_PRES, irq1 = USB */ |
578 | pdata->irq_base + 8 + 2, pdata->irq_base + 4); | 687 | pdata->irq_base + USB_PRES_INTR_OFFSET, |
688 | pdata->irq_base + USB_INTR_OFFSET); | ||
579 | 689 | ||
580 | if (IS_ERR(child)) | 690 | if (IS_ERR(child)) |
581 | return PTR_ERR(child); | 691 | return PTR_ERR(child); |
@@ -601,12 +711,31 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
601 | return PTR_ERR(child); | 711 | return PTR_ERR(child); |
602 | } | 712 | } |
603 | 713 | ||
604 | if (twl_has_regulator()) { | 714 | if (twl_has_codec() && pdata->codec) { |
605 | /* | 715 | child = add_child(1, "twl4030_codec", |
716 | pdata->codec, sizeof(*pdata->codec), | ||
717 | false, 0, 0); | ||
718 | if (IS_ERR(child)) | ||
719 | return PTR_ERR(child); | ||
720 | } | ||
721 | |||
722 | /* twl4030 regulators */ | ||
723 | if (twl_has_regulator() && twl_class_is_4030()) { | ||
606 | child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1); | 724 | child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1); |
607 | if (IS_ERR(child)) | 725 | if (IS_ERR(child)) |
608 | return PTR_ERR(child); | 726 | return PTR_ERR(child); |
609 | */ | 727 | |
728 | child = add_regulator(TWL4030_REG_VIO, pdata->vio); | ||
729 | if (IS_ERR(child)) | ||
730 | return PTR_ERR(child); | ||
731 | |||
732 | child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1); | ||
733 | if (IS_ERR(child)) | ||
734 | return PTR_ERR(child); | ||
735 | |||
736 | child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2); | ||
737 | if (IS_ERR(child)) | ||
738 | return PTR_ERR(child); | ||
610 | 739 | ||
611 | child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1); | 740 | child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1); |
612 | if (IS_ERR(child)) | 741 | if (IS_ERR(child)) |
@@ -622,10 +751,23 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
622 | pdata->vaux2); | 751 | pdata->vaux2); |
623 | if (IS_ERR(child)) | 752 | if (IS_ERR(child)) |
624 | return PTR_ERR(child); | 753 | return PTR_ERR(child); |
754 | |||
755 | child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1); | ||
756 | if (IS_ERR(child)) | ||
757 | return PTR_ERR(child); | ||
758 | |||
759 | child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2); | ||
760 | if (IS_ERR(child)) | ||
761 | return PTR_ERR(child); | ||
762 | |||
763 | child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig); | ||
764 | if (IS_ERR(child)) | ||
765 | return PTR_ERR(child); | ||
625 | } | 766 | } |
626 | 767 | ||
627 | /* maybe add LDOs that are omitted on cost-reduced parts */ | 768 | /* maybe add LDOs that are omitted on cost-reduced parts */ |
628 | if (twl_has_regulator() && !(features & TPS_SUBSET)) { | 769 | if (twl_has_regulator() && !(features & TPS_SUBSET) |
770 | && twl_class_is_4030()) { | ||
629 | child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2); | 771 | child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2); |
630 | if (IS_ERR(child)) | 772 | if (IS_ERR(child)) |
631 | return PTR_ERR(child); | 773 | return PTR_ERR(child); |
@@ -651,6 +793,49 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
651 | return PTR_ERR(child); | 793 | return PTR_ERR(child); |
652 | } | 794 | } |
653 | 795 | ||
796 | /* twl6030 regulators */ | ||
797 | if (twl_has_regulator() && twl_class_is_6030()) { | ||
798 | child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc); | ||
799 | if (IS_ERR(child)) | ||
800 | return PTR_ERR(child); | ||
801 | |||
802 | child = add_regulator(TWL6030_REG_VPP, pdata->vpp); | ||
803 | if (IS_ERR(child)) | ||
804 | return PTR_ERR(child); | ||
805 | |||
806 | child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim); | ||
807 | if (IS_ERR(child)) | ||
808 | return PTR_ERR(child); | ||
809 | |||
810 | child = add_regulator(TWL6030_REG_VANA, pdata->vana); | ||
811 | if (IS_ERR(child)) | ||
812 | return PTR_ERR(child); | ||
813 | |||
814 | child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio); | ||
815 | if (IS_ERR(child)) | ||
816 | return PTR_ERR(child); | ||
817 | |||
818 | child = add_regulator(TWL6030_REG_VDAC, pdata->vdac); | ||
819 | if (IS_ERR(child)) | ||
820 | return PTR_ERR(child); | ||
821 | |||
822 | child = add_regulator(TWL6030_REG_VUSB, pdata->vusb); | ||
823 | if (IS_ERR(child)) | ||
824 | return PTR_ERR(child); | ||
825 | |||
826 | child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1); | ||
827 | if (IS_ERR(child)) | ||
828 | return PTR_ERR(child); | ||
829 | |||
830 | child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2); | ||
831 | if (IS_ERR(child)) | ||
832 | return PTR_ERR(child); | ||
833 | |||
834 | child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3); | ||
835 | if (IS_ERR(child)) | ||
836 | return PTR_ERR(child); | ||
837 | } | ||
838 | |||
654 | return 0; | 839 | return 0; |
655 | } | 840 | } |
656 | 841 | ||
@@ -665,7 +850,7 @@ static inline int __init protect_pm_master(void) | |||
665 | { | 850 | { |
666 | int e = 0; | 851 | int e = 0; |
667 | 852 | ||
668 | e = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_LOCK, | 853 | e = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_LOCK, |
669 | R_PROTECT_KEY); | 854 | R_PROTECT_KEY); |
670 | return e; | 855 | return e; |
671 | } | 856 | } |
@@ -674,14 +859,15 @@ static inline int __init unprotect_pm_master(void) | |||
674 | { | 859 | { |
675 | int e = 0; | 860 | int e = 0; |
676 | 861 | ||
677 | e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK1, | 862 | e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_UNLOCK1, |
678 | R_PROTECT_KEY); | 863 | R_PROTECT_KEY); |
679 | e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK2, | 864 | e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_UNLOCK2, |
680 | R_PROTECT_KEY); | 865 | R_PROTECT_KEY); |
681 | return e; | 866 | return e; |
682 | } | 867 | } |
683 | 868 | ||
684 | static void clocks_init(struct device *dev) | 869 | static void clocks_init(struct device *dev, |
870 | struct twl4030_clock_init_data *clock) | ||
685 | { | 871 | { |
686 | int e = 0; | 872 | int e = 0; |
687 | struct clk *osc; | 873 | struct clk *osc; |
@@ -695,7 +881,7 @@ static void clocks_init(struct device *dev) | |||
695 | osc = clk_get(dev, "osc_sys_ck"); | 881 | osc = clk_get(dev, "osc_sys_ck"); |
696 | 882 | ||
697 | if (IS_ERR(osc)) { | 883 | if (IS_ERR(osc)) { |
698 | printk(KERN_WARNING "Skipping twl4030 internal clock init and " | 884 | printk(KERN_WARNING "Skipping twl internal clock init and " |
699 | "using bootloader value (unknown osc rate)\n"); | 885 | "using bootloader value (unknown osc rate)\n"); |
700 | return; | 886 | return; |
701 | } | 887 | } |
@@ -709,7 +895,7 @@ static void clocks_init(struct device *dev) | |||
709 | */ | 895 | */ |
710 | osc = ERR_PTR(-EIO); | 896 | osc = ERR_PTR(-EIO); |
711 | 897 | ||
712 | printk(KERN_WARNING "Skipping twl4030 internal clock init and " | 898 | printk(KERN_WARNING "Skipping twl internal clock init and " |
713 | "using bootloader value (unknown osc rate)\n"); | 899 | "using bootloader value (unknown osc rate)\n"); |
714 | 900 | ||
715 | return; | 901 | return; |
@@ -728,9 +914,12 @@ static void clocks_init(struct device *dev) | |||
728 | } | 914 | } |
729 | 915 | ||
730 | ctrl |= HIGH_PERF_SQ; | 916 | ctrl |= HIGH_PERF_SQ; |
917 | if (clock && clock->ck32k_lowpwr_enable) | ||
918 | ctrl |= CK32K_LOWPWR_EN; | ||
919 | |||
731 | e |= unprotect_pm_master(); | 920 | e |= unprotect_pm_master(); |
732 | /* effect->MADC+USB ck en */ | 921 | /* effect->MADC+USB ck en */ |
733 | e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, ctrl, R_CFG_BOOT); | 922 | e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, ctrl, R_CFG_BOOT); |
734 | e |= protect_pm_master(); | 923 | e |= protect_pm_master(); |
735 | 924 | ||
736 | if (e < 0) | 925 | if (e < 0) |
@@ -739,32 +928,39 @@ static void clocks_init(struct device *dev) | |||
739 | 928 | ||
740 | /*----------------------------------------------------------------------*/ | 929 | /*----------------------------------------------------------------------*/ |
741 | 930 | ||
742 | int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); | 931 | int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); |
743 | int twl_exit_irq(void); | 932 | int twl4030_exit_irq(void); |
933 | int twl4030_init_chip_irq(const char *chip); | ||
934 | int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); | ||
935 | int twl6030_exit_irq(void); | ||
744 | 936 | ||
745 | static int twl4030_remove(struct i2c_client *client) | 937 | static int twl_remove(struct i2c_client *client) |
746 | { | 938 | { |
747 | unsigned i; | 939 | unsigned i; |
748 | int status; | 940 | int status; |
749 | 941 | ||
750 | status = twl_exit_irq(); | 942 | if (twl_class_is_4030()) |
943 | status = twl4030_exit_irq(); | ||
944 | else | ||
945 | status = twl6030_exit_irq(); | ||
946 | |||
751 | if (status < 0) | 947 | if (status < 0) |
752 | return status; | 948 | return status; |
753 | 949 | ||
754 | for (i = 0; i < TWL4030_NUM_SLAVES; i++) { | 950 | for (i = 0; i < TWL_NUM_SLAVES; i++) { |
755 | struct twl4030_client *twl = &twl4030_modules[i]; | 951 | struct twl_client *twl = &twl_modules[i]; |
756 | 952 | ||
757 | if (twl->client && twl->client != client) | 953 | if (twl->client && twl->client != client) |
758 | i2c_unregister_device(twl->client); | 954 | i2c_unregister_device(twl->client); |
759 | twl4030_modules[i].client = NULL; | 955 | twl_modules[i].client = NULL; |
760 | } | 956 | } |
761 | inuse = false; | 957 | inuse = false; |
762 | return 0; | 958 | return 0; |
763 | } | 959 | } |
764 | 960 | ||
765 | /* NOTE: this driver only handles a single twl4030/tps659x0 chip */ | 961 | /* NOTE: this driver only handles a single twl4030/tps659x0 chip */ |
766 | static int | 962 | static int __init |
767 | twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id) | 963 | twl_probe(struct i2c_client *client, const struct i2c_device_id *id) |
768 | { | 964 | { |
769 | int status; | 965 | int status; |
770 | unsigned i; | 966 | unsigned i; |
@@ -785,8 +981,8 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
785 | return -EBUSY; | 981 | return -EBUSY; |
786 | } | 982 | } |
787 | 983 | ||
788 | for (i = 0; i < TWL4030_NUM_SLAVES; i++) { | 984 | for (i = 0; i < TWL_NUM_SLAVES; i++) { |
789 | struct twl4030_client *twl = &twl4030_modules[i]; | 985 | struct twl_client *twl = &twl_modules[i]; |
790 | 986 | ||
791 | twl->address = client->addr + i; | 987 | twl->address = client->addr + i; |
792 | if (i == 0) | 988 | if (i == 0) |
@@ -800,15 +996,20 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
800 | status = -ENOMEM; | 996 | status = -ENOMEM; |
801 | goto fail; | 997 | goto fail; |
802 | } | 998 | } |
803 | strlcpy(twl->client->name, id->name, | ||
804 | sizeof(twl->client->name)); | ||
805 | } | 999 | } |
806 | mutex_init(&twl->xfer_lock); | 1000 | mutex_init(&twl->xfer_lock); |
807 | } | 1001 | } |
808 | inuse = true; | 1002 | inuse = true; |
1003 | if ((id->driver_data) & TWL6030_CLASS) { | ||
1004 | twl_id = TWL6030_CLASS_ID; | ||
1005 | twl_map = &twl6030_map[0]; | ||
1006 | } else { | ||
1007 | twl_id = TWL4030_CLASS_ID; | ||
1008 | twl_map = &twl4030_map[0]; | ||
1009 | } | ||
809 | 1010 | ||
810 | /* setup clock framework */ | 1011 | /* setup clock framework */ |
811 | clocks_init(&client->dev); | 1012 | clocks_init(&client->dev, pdata->clock); |
812 | 1013 | ||
813 | /* load power event scripts */ | 1014 | /* load power event scripts */ |
814 | if (twl_has_power() && pdata->power) | 1015 | if (twl_has_power() && pdata->power) |
@@ -818,7 +1019,15 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
818 | if (client->irq | 1019 | if (client->irq |
819 | && pdata->irq_base | 1020 | && pdata->irq_base |
820 | && pdata->irq_end > pdata->irq_base) { | 1021 | && pdata->irq_end > pdata->irq_base) { |
821 | status = twl_init_irq(client->irq, pdata->irq_base, pdata->irq_end); | 1022 | if (twl_class_is_4030()) { |
1023 | twl4030_init_chip_irq(id->name); | ||
1024 | status = twl4030_init_irq(client->irq, pdata->irq_base, | ||
1025 | pdata->irq_end); | ||
1026 | } else { | ||
1027 | status = twl6030_init_irq(client->irq, pdata->irq_base, | ||
1028 | pdata->irq_end); | ||
1029 | } | ||
1030 | |||
822 | if (status < 0) | 1031 | if (status < 0) |
823 | goto fail; | 1032 | goto fail; |
824 | } | 1033 | } |
@@ -826,40 +1035,42 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
826 | status = add_children(pdata, id->driver_data); | 1035 | status = add_children(pdata, id->driver_data); |
827 | fail: | 1036 | fail: |
828 | if (status < 0) | 1037 | if (status < 0) |
829 | twl4030_remove(client); | 1038 | twl_remove(client); |
830 | return status; | 1039 | return status; |
831 | } | 1040 | } |
832 | 1041 | ||
833 | static const struct i2c_device_id twl4030_ids[] = { | 1042 | static const struct i2c_device_id twl_ids[] = { |
834 | { "twl4030", TWL4030_VAUX2 }, /* "Triton 2" */ | 1043 | { "twl4030", TWL4030_VAUX2 }, /* "Triton 2" */ |
835 | { "twl5030", 0 }, /* T2 updated */ | 1044 | { "twl5030", 0 }, /* T2 updated */ |
1045 | { "twl5031", TWL5031 }, /* TWL5030 updated */ | ||
836 | { "tps65950", 0 }, /* catalog version of twl5030 */ | 1046 | { "tps65950", 0 }, /* catalog version of twl5030 */ |
837 | { "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */ | 1047 | { "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */ |
838 | { "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */ | 1048 | { "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */ |
1049 | { "twl6030", TWL6030_CLASS }, /* "Phoenix power chip" */ | ||
839 | { /* end of list */ }, | 1050 | { /* end of list */ }, |
840 | }; | 1051 | }; |
841 | MODULE_DEVICE_TABLE(i2c, twl4030_ids); | 1052 | MODULE_DEVICE_TABLE(i2c, twl_ids); |
842 | 1053 | ||
843 | /* One Client Driver , 4 Clients */ | 1054 | /* One Client Driver , 4 Clients */ |
844 | static struct i2c_driver twl4030_driver = { | 1055 | static struct i2c_driver twl_driver = { |
845 | .driver.name = DRIVER_NAME, | 1056 | .driver.name = DRIVER_NAME, |
846 | .id_table = twl4030_ids, | 1057 | .id_table = twl_ids, |
847 | .probe = twl4030_probe, | 1058 | .probe = twl_probe, |
848 | .remove = twl4030_remove, | 1059 | .remove = twl_remove, |
849 | }; | 1060 | }; |
850 | 1061 | ||
851 | static int __init twl4030_init(void) | 1062 | static int __init twl_init(void) |
852 | { | 1063 | { |
853 | return i2c_add_driver(&twl4030_driver); | 1064 | return i2c_add_driver(&twl_driver); |
854 | } | 1065 | } |
855 | subsys_initcall(twl4030_init); | 1066 | subsys_initcall(twl_init); |
856 | 1067 | ||
857 | static void __exit twl4030_exit(void) | 1068 | static void __exit twl_exit(void) |
858 | { | 1069 | { |
859 | i2c_del_driver(&twl4030_driver); | 1070 | i2c_del_driver(&twl_driver); |
860 | } | 1071 | } |
861 | module_exit(twl4030_exit); | 1072 | module_exit(twl_exit); |
862 | 1073 | ||
863 | MODULE_AUTHOR("Texas Instruments, Inc."); | 1074 | MODULE_AUTHOR("Texas Instruments, Inc."); |
864 | MODULE_DESCRIPTION("I2C Core interface for TWL4030"); | 1075 | MODULE_DESCRIPTION("I2C Core interface for TWL"); |
865 | MODULE_LICENSE("GPL"); | 1076 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/mfd/twl4030-codec.c b/drivers/mfd/twl4030-codec.c new file mode 100644 index 000000000000..77b914907d7c --- /dev/null +++ b/drivers/mfd/twl4030-codec.c | |||
@@ -0,0 +1,276 @@ | |||
1 | /* | ||
2 | * MFD driver for twl4030 codec submodule | ||
3 | * | ||
4 | * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com> | ||
5 | * | ||
6 | * Copyright: (C) 2009 Nokia Corporation | ||
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/module.h> | ||
25 | #include <linux/types.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/fs.h> | ||
28 | #include <linux/platform_device.h> | ||
29 | #include <linux/i2c/twl4030.h> | ||
30 | #include <linux/mfd/core.h> | ||
31 | #include <linux/mfd/twl4030-codec.h> | ||
32 | |||
33 | #define TWL4030_CODEC_CELLS 2 | ||
34 | |||
35 | static struct platform_device *twl4030_codec_dev; | ||
36 | |||
37 | struct twl4030_codec_resource { | ||
38 | int request_count; | ||
39 | u8 reg; | ||
40 | u8 mask; | ||
41 | }; | ||
42 | |||
43 | struct twl4030_codec { | ||
44 | unsigned int audio_mclk; | ||
45 | struct mutex mutex; | ||
46 | struct twl4030_codec_resource resource[TWL4030_CODEC_RES_MAX]; | ||
47 | struct mfd_cell cells[TWL4030_CODEC_CELLS]; | ||
48 | }; | ||
49 | |||
50 | /* | ||
51 | * Modify the resource, the function returns the content of the register | ||
52 | * after the modification. | ||
53 | */ | ||
54 | static int twl4030_codec_set_resource(enum twl4030_codec_res id, int enable) | ||
55 | { | ||
56 | struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev); | ||
57 | u8 val; | ||
58 | |||
59 | twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, | ||
60 | codec->resource[id].reg); | ||
61 | |||
62 | if (enable) | ||
63 | val |= codec->resource[id].mask; | ||
64 | else | ||
65 | val &= ~codec->resource[id].mask; | ||
66 | |||
67 | twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, | ||
68 | val, codec->resource[id].reg); | ||
69 | |||
70 | return val; | ||
71 | } | ||
72 | |||
73 | static inline int twl4030_codec_get_resource(enum twl4030_codec_res id) | ||
74 | { | ||
75 | struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev); | ||
76 | u8 val; | ||
77 | |||
78 | twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, | ||
79 | codec->resource[id].reg); | ||
80 | |||
81 | return val; | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * Enable the resource. | ||
86 | * The function returns with error or the content of the register | ||
87 | */ | ||
88 | int twl4030_codec_enable_resource(enum twl4030_codec_res id) | ||
89 | { | ||
90 | struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev); | ||
91 | int val; | ||
92 | |||
93 | if (id >= TWL4030_CODEC_RES_MAX) { | ||
94 | dev_err(&twl4030_codec_dev->dev, | ||
95 | "Invalid resource ID (%u)\n", id); | ||
96 | return -EINVAL; | ||
97 | } | ||
98 | |||
99 | mutex_lock(&codec->mutex); | ||
100 | if (!codec->resource[id].request_count) | ||
101 | /* Resource was disabled, enable it */ | ||
102 | val = twl4030_codec_set_resource(id, 1); | ||
103 | else | ||
104 | val = twl4030_codec_get_resource(id); | ||
105 | |||
106 | codec->resource[id].request_count++; | ||
107 | mutex_unlock(&codec->mutex); | ||
108 | |||
109 | return val; | ||
110 | } | ||
111 | EXPORT_SYMBOL_GPL(twl4030_codec_enable_resource); | ||
112 | |||
113 | /* | ||
114 | * Disable the resource. | ||
115 | * The function returns with error or the content of the register | ||
116 | */ | ||
117 | int twl4030_codec_disable_resource(unsigned id) | ||
118 | { | ||
119 | struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev); | ||
120 | int val; | ||
121 | |||
122 | if (id >= TWL4030_CODEC_RES_MAX) { | ||
123 | dev_err(&twl4030_codec_dev->dev, | ||
124 | "Invalid resource ID (%u)\n", id); | ||
125 | return -EINVAL; | ||
126 | } | ||
127 | |||
128 | mutex_lock(&codec->mutex); | ||
129 | if (!codec->resource[id].request_count) { | ||
130 | dev_err(&twl4030_codec_dev->dev, | ||
131 | "Resource has been disabled already (%u)\n", id); | ||
132 | mutex_unlock(&codec->mutex); | ||
133 | return -EPERM; | ||
134 | } | ||
135 | codec->resource[id].request_count--; | ||
136 | |||
137 | if (!codec->resource[id].request_count) | ||
138 | /* Resource can be disabled now */ | ||
139 | val = twl4030_codec_set_resource(id, 0); | ||
140 | else | ||
141 | val = twl4030_codec_get_resource(id); | ||
142 | |||
143 | mutex_unlock(&codec->mutex); | ||
144 | |||
145 | return val; | ||
146 | } | ||
147 | EXPORT_SYMBOL_GPL(twl4030_codec_disable_resource); | ||
148 | |||
149 | unsigned int twl4030_codec_get_mclk(void) | ||
150 | { | ||
151 | struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev); | ||
152 | |||
153 | return codec->audio_mclk; | ||
154 | } | ||
155 | EXPORT_SYMBOL_GPL(twl4030_codec_get_mclk); | ||
156 | |||
157 | static int __devinit twl4030_codec_probe(struct platform_device *pdev) | ||
158 | { | ||
159 | struct twl4030_codec *codec; | ||
160 | struct twl4030_codec_data *pdata = pdev->dev.platform_data; | ||
161 | struct mfd_cell *cell = NULL; | ||
162 | int ret, childs = 0; | ||
163 | u8 val; | ||
164 | |||
165 | if (!pdata) { | ||
166 | dev_err(&pdev->dev, "Platform data is missing\n"); | ||
167 | return -EINVAL; | ||
168 | } | ||
169 | |||
170 | /* Configure APLL_INFREQ and disable APLL if enabled */ | ||
171 | val = 0; | ||
172 | switch (pdata->audio_mclk) { | ||
173 | case 19200000: | ||
174 | val |= TWL4030_APLL_INFREQ_19200KHZ; | ||
175 | break; | ||
176 | case 26000000: | ||
177 | val |= TWL4030_APLL_INFREQ_26000KHZ; | ||
178 | break; | ||
179 | case 38400000: | ||
180 | val |= TWL4030_APLL_INFREQ_38400KHZ; | ||
181 | break; | ||
182 | default: | ||
183 | dev_err(&pdev->dev, "Invalid audio_mclk\n"); | ||
184 | return -EINVAL; | ||
185 | } | ||
186 | twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, | ||
187 | val, TWL4030_REG_APLL_CTL); | ||
188 | |||
189 | codec = kzalloc(sizeof(struct twl4030_codec), GFP_KERNEL); | ||
190 | if (!codec) | ||
191 | return -ENOMEM; | ||
192 | |||
193 | platform_set_drvdata(pdev, codec); | ||
194 | |||
195 | twl4030_codec_dev = pdev; | ||
196 | mutex_init(&codec->mutex); | ||
197 | codec->audio_mclk = pdata->audio_mclk; | ||
198 | |||
199 | /* Codec power */ | ||
200 | codec->resource[TWL4030_CODEC_RES_POWER].reg = TWL4030_REG_CODEC_MODE; | ||
201 | codec->resource[TWL4030_CODEC_RES_POWER].mask = TWL4030_CODECPDZ; | ||
202 | |||
203 | /* PLL */ | ||
204 | codec->resource[TWL4030_CODEC_RES_APLL].reg = TWL4030_REG_APLL_CTL; | ||
205 | codec->resource[TWL4030_CODEC_RES_APLL].mask = TWL4030_APLL_EN; | ||
206 | |||
207 | if (pdata->audio) { | ||
208 | cell = &codec->cells[childs]; | ||
209 | cell->name = "twl4030_codec_audio"; | ||
210 | cell->platform_data = pdata->audio; | ||
211 | cell->data_size = sizeof(*pdata->audio); | ||
212 | childs++; | ||
213 | } | ||
214 | if (pdata->vibra) { | ||
215 | cell = &codec->cells[childs]; | ||
216 | cell->name = "twl4030_codec_vibra"; | ||
217 | cell->platform_data = pdata->vibra; | ||
218 | cell->data_size = sizeof(*pdata->vibra); | ||
219 | childs++; | ||
220 | } | ||
221 | |||
222 | if (childs) | ||
223 | ret = mfd_add_devices(&pdev->dev, pdev->id, codec->cells, | ||
224 | childs, NULL, 0); | ||
225 | else { | ||
226 | dev_err(&pdev->dev, "No platform data found for childs\n"); | ||
227 | ret = -ENODEV; | ||
228 | } | ||
229 | |||
230 | if (!ret) | ||
231 | return 0; | ||
232 | |||
233 | platform_set_drvdata(pdev, NULL); | ||
234 | kfree(codec); | ||
235 | twl4030_codec_dev = NULL; | ||
236 | return ret; | ||
237 | } | ||
238 | |||
239 | static int __devexit twl4030_codec_remove(struct platform_device *pdev) | ||
240 | { | ||
241 | struct twl4030_codec *codec = platform_get_drvdata(pdev); | ||
242 | |||
243 | mfd_remove_devices(&pdev->dev); | ||
244 | platform_set_drvdata(pdev, NULL); | ||
245 | kfree(codec); | ||
246 | twl4030_codec_dev = NULL; | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | MODULE_ALIAS("platform:twl4030_codec"); | ||
252 | |||
253 | static struct platform_driver twl4030_codec_driver = { | ||
254 | .probe = twl4030_codec_probe, | ||
255 | .remove = __devexit_p(twl4030_codec_remove), | ||
256 | .driver = { | ||
257 | .owner = THIS_MODULE, | ||
258 | .name = "twl4030_codec", | ||
259 | }, | ||
260 | }; | ||
261 | |||
262 | static int __devinit twl4030_codec_init(void) | ||
263 | { | ||
264 | return platform_driver_register(&twl4030_codec_driver); | ||
265 | } | ||
266 | module_init(twl4030_codec_init); | ||
267 | |||
268 | static void __devexit twl4030_codec_exit(void) | ||
269 | { | ||
270 | platform_driver_unregister(&twl4030_codec_driver); | ||
271 | } | ||
272 | module_exit(twl4030_codec_exit); | ||
273 | |||
274 | MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@nokia.com>"); | ||
275 | MODULE_LICENSE("GPL"); | ||
276 | |||
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index fb194fe244c1..20d29bafc9f5 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #include <linux/irq.h> | 32 | #include <linux/irq.h> |
33 | #include <linux/kthread.h> | 33 | #include <linux/kthread.h> |
34 | 34 | ||
35 | #include <linux/i2c/twl4030.h> | 35 | #include <linux/i2c/twl.h> |
36 | 36 | ||
37 | 37 | ||
38 | /* | 38 | /* |
@@ -74,6 +74,8 @@ struct sih { | |||
74 | u8 edr_offset; | 74 | u8 edr_offset; |
75 | u8 bytes_edr; /* bytelen of EDR */ | 75 | u8 bytes_edr; /* bytelen of EDR */ |
76 | 76 | ||
77 | u8 irq_lines; /* number of supported irq lines */ | ||
78 | |||
77 | /* SIR ignored -- set interrupt, for testing only */ | 79 | /* SIR ignored -- set interrupt, for testing only */ |
78 | struct irq_data { | 80 | struct irq_data { |
79 | u8 isr_offset; | 81 | u8 isr_offset; |
@@ -82,6 +84,9 @@ struct sih { | |||
82 | /* + 2 bytes padding */ | 84 | /* + 2 bytes padding */ |
83 | }; | 85 | }; |
84 | 86 | ||
87 | static const struct sih *sih_modules; | ||
88 | static int nr_sih_modules; | ||
89 | |||
85 | #define SIH_INITIALIZER(modname, nbits) \ | 90 | #define SIH_INITIALIZER(modname, nbits) \ |
86 | .module = TWL4030_MODULE_ ## modname, \ | 91 | .module = TWL4030_MODULE_ ## modname, \ |
87 | .control_offset = TWL4030_ ## modname ## _SIH_CTRL, \ | 92 | .control_offset = TWL4030_ ## modname ## _SIH_CTRL, \ |
@@ -89,6 +94,7 @@ struct sih { | |||
89 | .bytes_ixr = DIV_ROUND_UP(nbits, 8), \ | 94 | .bytes_ixr = DIV_ROUND_UP(nbits, 8), \ |
90 | .edr_offset = TWL4030_ ## modname ## _EDR, \ | 95 | .edr_offset = TWL4030_ ## modname ## _EDR, \ |
91 | .bytes_edr = DIV_ROUND_UP((2*(nbits)), 8), \ | 96 | .bytes_edr = DIV_ROUND_UP((2*(nbits)), 8), \ |
97 | .irq_lines = 2, \ | ||
92 | .mask = { { \ | 98 | .mask = { { \ |
93 | .isr_offset = TWL4030_ ## modname ## _ISR1, \ | 99 | .isr_offset = TWL4030_ ## modname ## _ISR1, \ |
94 | .imr_offset = TWL4030_ ## modname ## _IMR1, \ | 100 | .imr_offset = TWL4030_ ## modname ## _IMR1, \ |
@@ -107,7 +113,8 @@ struct sih { | |||
107 | /* Order in this table matches order in PIH_ISR. That is, | 113 | /* Order in this table matches order in PIH_ISR. That is, |
108 | * BIT(n) in PIH_ISR is sih_modules[n]. | 114 | * BIT(n) in PIH_ISR is sih_modules[n]. |
109 | */ | 115 | */ |
110 | static const struct sih sih_modules[6] = { | 116 | /* sih_modules_twl4030 is used both in twl4030 and twl5030 */ |
117 | static const struct sih sih_modules_twl4030[6] = { | ||
111 | [0] = { | 118 | [0] = { |
112 | .name = "gpio", | 119 | .name = "gpio", |
113 | .module = TWL4030_MODULE_GPIO, | 120 | .module = TWL4030_MODULE_GPIO, |
@@ -118,6 +125,7 @@ static const struct sih sih_modules[6] = { | |||
118 | /* Note: *all* of these IRQs default to no-trigger */ | 125 | /* Note: *all* of these IRQs default to no-trigger */ |
119 | .edr_offset = REG_GPIO_EDR1, | 126 | .edr_offset = REG_GPIO_EDR1, |
120 | .bytes_edr = 5, | 127 | .bytes_edr = 5, |
128 | .irq_lines = 2, | ||
121 | .mask = { { | 129 | .mask = { { |
122 | .isr_offset = REG_GPIO_ISR1A, | 130 | .isr_offset = REG_GPIO_ISR1A, |
123 | .imr_offset = REG_GPIO_IMR1A, | 131 | .imr_offset = REG_GPIO_IMR1A, |
@@ -140,6 +148,7 @@ static const struct sih sih_modules[6] = { | |||
140 | .edr_offset = TWL4030_INTERRUPTS_BCIEDR1, | 148 | .edr_offset = TWL4030_INTERRUPTS_BCIEDR1, |
141 | /* Note: most of these IRQs default to no-trigger */ | 149 | /* Note: most of these IRQs default to no-trigger */ |
142 | .bytes_edr = 3, | 150 | .bytes_edr = 3, |
151 | .irq_lines = 2, | ||
143 | .mask = { { | 152 | .mask = { { |
144 | .isr_offset = TWL4030_INTERRUPTS_BCIISR1A, | 153 | .isr_offset = TWL4030_INTERRUPTS_BCIISR1A, |
145 | .imr_offset = TWL4030_INTERRUPTS_BCIIMR1A, | 154 | .imr_offset = TWL4030_INTERRUPTS_BCIIMR1A, |
@@ -164,6 +173,99 @@ static const struct sih sih_modules[6] = { | |||
164 | /* there are no SIH modules #6 or #7 ... */ | 173 | /* there are no SIH modules #6 or #7 ... */ |
165 | }; | 174 | }; |
166 | 175 | ||
176 | static const struct sih sih_modules_twl5031[8] = { | ||
177 | [0] = { | ||
178 | .name = "gpio", | ||
179 | .module = TWL4030_MODULE_GPIO, | ||
180 | .control_offset = REG_GPIO_SIH_CTRL, | ||
181 | .set_cor = true, | ||
182 | .bits = TWL4030_GPIO_MAX, | ||
183 | .bytes_ixr = 3, | ||
184 | /* Note: *all* of these IRQs default to no-trigger */ | ||
185 | .edr_offset = REG_GPIO_EDR1, | ||
186 | .bytes_edr = 5, | ||
187 | .irq_lines = 2, | ||
188 | .mask = { { | ||
189 | .isr_offset = REG_GPIO_ISR1A, | ||
190 | .imr_offset = REG_GPIO_IMR1A, | ||
191 | }, { | ||
192 | .isr_offset = REG_GPIO_ISR1B, | ||
193 | .imr_offset = REG_GPIO_IMR1B, | ||
194 | }, }, | ||
195 | }, | ||
196 | [1] = { | ||
197 | .name = "keypad", | ||
198 | .set_cor = true, | ||
199 | SIH_INITIALIZER(KEYPAD_KEYP, 4) | ||
200 | }, | ||
201 | [2] = { | ||
202 | .name = "bci", | ||
203 | .module = TWL5031_MODULE_INTERRUPTS, | ||
204 | .control_offset = TWL5031_INTERRUPTS_BCISIHCTRL, | ||
205 | .bits = 7, | ||
206 | .bytes_ixr = 1, | ||
207 | .edr_offset = TWL5031_INTERRUPTS_BCIEDR1, | ||
208 | /* Note: most of these IRQs default to no-trigger */ | ||
209 | .bytes_edr = 2, | ||
210 | .irq_lines = 2, | ||
211 | .mask = { { | ||
212 | .isr_offset = TWL5031_INTERRUPTS_BCIISR1, | ||
213 | .imr_offset = TWL5031_INTERRUPTS_BCIIMR1, | ||
214 | }, { | ||
215 | .isr_offset = TWL5031_INTERRUPTS_BCIISR2, | ||
216 | .imr_offset = TWL5031_INTERRUPTS_BCIIMR2, | ||
217 | }, }, | ||
218 | }, | ||
219 | [3] = { | ||
220 | .name = "madc", | ||
221 | SIH_INITIALIZER(MADC, 4) | ||
222 | }, | ||
223 | [4] = { | ||
224 | /* USB doesn't use the same SIH organization */ | ||
225 | .name = "usb", | ||
226 | }, | ||
227 | [5] = { | ||
228 | .name = "power", | ||
229 | .set_cor = true, | ||
230 | SIH_INITIALIZER(INT_PWR, 8) | ||
231 | }, | ||
232 | [6] = { | ||
233 | /* | ||
234 | * ACI doesn't use the same SIH organization. | ||
235 | * For example, it supports only one interrupt line | ||
236 | */ | ||
237 | .name = "aci", | ||
238 | .module = TWL5031_MODULE_ACCESSORY, | ||
239 | .bits = 9, | ||
240 | .bytes_ixr = 2, | ||
241 | .irq_lines = 1, | ||
242 | .mask = { { | ||
243 | .isr_offset = TWL5031_ACIIDR_LSB, | ||
244 | .imr_offset = TWL5031_ACIIMR_LSB, | ||
245 | }, }, | ||
246 | |||
247 | }, | ||
248 | [7] = { | ||
249 | /* Accessory */ | ||
250 | .name = "acc", | ||
251 | .module = TWL5031_MODULE_ACCESSORY, | ||
252 | .control_offset = TWL5031_ACCSIHCTRL, | ||
253 | .bits = 2, | ||
254 | .bytes_ixr = 1, | ||
255 | .edr_offset = TWL5031_ACCEDR1, | ||
256 | /* Note: most of these IRQs default to no-trigger */ | ||
257 | .bytes_edr = 1, | ||
258 | .irq_lines = 2, | ||
259 | .mask = { { | ||
260 | .isr_offset = TWL5031_ACCISR1, | ||
261 | .imr_offset = TWL5031_ACCIMR1, | ||
262 | }, { | ||
263 | .isr_offset = TWL5031_ACCISR2, | ||
264 | .imr_offset = TWL5031_ACCIMR2, | ||
265 | }, }, | ||
266 | }, | ||
267 | }; | ||
268 | |||
167 | #undef TWL4030_MODULE_KEYPAD_KEYP | 269 | #undef TWL4030_MODULE_KEYPAD_KEYP |
168 | #undef TWL4030_MODULE_INT_PWR | 270 | #undef TWL4030_MODULE_INT_PWR |
169 | #undef TWL4030_INT_PWR_EDR | 271 | #undef TWL4030_INT_PWR_EDR |
@@ -194,7 +296,7 @@ static int twl4030_irq_thread(void *data) | |||
194 | /* Wait for IRQ, then read PIH irq status (also blocking) */ | 296 | /* Wait for IRQ, then read PIH irq status (also blocking) */ |
195 | wait_for_completion_interruptible(&irq_event); | 297 | wait_for_completion_interruptible(&irq_event); |
196 | 298 | ||
197 | ret = twl4030_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr, | 299 | ret = twl_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr, |
198 | REG_PIH_ISR_P1); | 300 | REG_PIH_ISR_P1); |
199 | if (ret) { | 301 | if (ret) { |
200 | pr_warning("twl4030: I2C error %d reading PIH ISR\n", | 302 | pr_warning("twl4030: I2C error %d reading PIH ISR\n", |
@@ -284,13 +386,17 @@ static int twl4030_init_sih_modules(unsigned line) | |||
284 | /* disable all interrupts on our line */ | 386 | /* disable all interrupts on our line */ |
285 | memset(buf, 0xff, sizeof buf); | 387 | memset(buf, 0xff, sizeof buf); |
286 | sih = sih_modules; | 388 | sih = sih_modules; |
287 | for (i = 0; i < ARRAY_SIZE(sih_modules); i++, sih++) { | 389 | for (i = 0; i < nr_sih_modules; i++, sih++) { |
288 | 390 | ||
289 | /* skip USB -- it's funky */ | 391 | /* skip USB -- it's funky */ |
290 | if (!sih->bytes_ixr) | 392 | if (!sih->bytes_ixr) |
291 | continue; | 393 | continue; |
292 | 394 | ||
293 | status = twl4030_i2c_write(sih->module, buf, | 395 | /* Not all the SIH modules support multiple interrupt lines */ |
396 | if (sih->irq_lines <= line) | ||
397 | continue; | ||
398 | |||
399 | status = twl_i2c_write(sih->module, buf, | ||
294 | sih->mask[line].imr_offset, sih->bytes_ixr); | 400 | sih->mask[line].imr_offset, sih->bytes_ixr); |
295 | if (status < 0) | 401 | if (status < 0) |
296 | pr_err("twl4030: err %d initializing %s %s\n", | 402 | pr_err("twl4030: err %d initializing %s %s\n", |
@@ -304,7 +410,7 @@ static int twl4030_init_sih_modules(unsigned line) | |||
304 | * And for PWR_INT it's not documented... | 410 | * And for PWR_INT it's not documented... |
305 | */ | 411 | */ |
306 | if (sih->set_cor) { | 412 | if (sih->set_cor) { |
307 | status = twl4030_i2c_write_u8(sih->module, | 413 | status = twl_i2c_write_u8(sih->module, |
308 | TWL4030_SIH_CTRL_COR_MASK, | 414 | TWL4030_SIH_CTRL_COR_MASK, |
309 | sih->control_offset); | 415 | sih->control_offset); |
310 | if (status < 0) | 416 | if (status < 0) |
@@ -314,7 +420,7 @@ static int twl4030_init_sih_modules(unsigned line) | |||
314 | } | 420 | } |
315 | 421 | ||
316 | sih = sih_modules; | 422 | sih = sih_modules; |
317 | for (i = 0; i < ARRAY_SIZE(sih_modules); i++, sih++) { | 423 | for (i = 0; i < nr_sih_modules; i++, sih++) { |
318 | u8 rxbuf[4]; | 424 | u8 rxbuf[4]; |
319 | int j; | 425 | int j; |
320 | 426 | ||
@@ -322,20 +428,24 @@ static int twl4030_init_sih_modules(unsigned line) | |||
322 | if (!sih->bytes_ixr) | 428 | if (!sih->bytes_ixr) |
323 | continue; | 429 | continue; |
324 | 430 | ||
431 | /* Not all the SIH modules support multiple interrupt lines */ | ||
432 | if (sih->irq_lines <= line) | ||
433 | continue; | ||
434 | |||
325 | /* Clear pending interrupt status. Either the read was | 435 | /* Clear pending interrupt status. Either the read was |
326 | * enough, or we need to write those bits. Repeat, in | 436 | * enough, or we need to write those bits. Repeat, in |
327 | * case an IRQ is pending (PENDDIS=0) ... that's not | 437 | * case an IRQ is pending (PENDDIS=0) ... that's not |
328 | * uncommon with PWR_INT.PWRON. | 438 | * uncommon with PWR_INT.PWRON. |
329 | */ | 439 | */ |
330 | for (j = 0; j < 2; j++) { | 440 | for (j = 0; j < 2; j++) { |
331 | status = twl4030_i2c_read(sih->module, rxbuf, | 441 | status = twl_i2c_read(sih->module, rxbuf, |
332 | sih->mask[line].isr_offset, sih->bytes_ixr); | 442 | sih->mask[line].isr_offset, sih->bytes_ixr); |
333 | if (status < 0) | 443 | if (status < 0) |
334 | pr_err("twl4030: err %d initializing %s %s\n", | 444 | pr_err("twl4030: err %d initializing %s %s\n", |
335 | status, sih->name, "ISR"); | 445 | status, sih->name, "ISR"); |
336 | 446 | ||
337 | if (!sih->set_cor) | 447 | if (!sih->set_cor) |
338 | status = twl4030_i2c_write(sih->module, buf, | 448 | status = twl_i2c_write(sih->module, buf, |
339 | sih->mask[line].isr_offset, | 449 | sih->mask[line].isr_offset, |
340 | sih->bytes_ixr); | 450 | sih->bytes_ixr); |
341 | /* else COR=1 means read sufficed. | 451 | /* else COR=1 means read sufficed. |
@@ -404,7 +514,7 @@ static void twl4030_sih_do_mask(struct work_struct *work) | |||
404 | return; | 514 | return; |
405 | 515 | ||
406 | /* write the whole mask ... simpler than subsetting it */ | 516 | /* write the whole mask ... simpler than subsetting it */ |
407 | status = twl4030_i2c_write(sih->module, imr.bytes, | 517 | status = twl_i2c_write(sih->module, imr.bytes, |
408 | sih->mask[irq_line].imr_offset, sih->bytes_ixr); | 518 | sih->mask[irq_line].imr_offset, sih->bytes_ixr); |
409 | if (status) | 519 | if (status) |
410 | pr_err("twl4030: %s, %s --> %d\n", __func__, | 520 | pr_err("twl4030: %s, %s --> %d\n", __func__, |
@@ -435,7 +545,7 @@ static void twl4030_sih_do_edge(struct work_struct *work) | |||
435 | * any processor on the other IRQ line, EDR registers are | 545 | * any processor on the other IRQ line, EDR registers are |
436 | * shared. | 546 | * shared. |
437 | */ | 547 | */ |
438 | status = twl4030_i2c_read(sih->module, bytes + 1, | 548 | status = twl_i2c_read(sih->module, bytes + 1, |
439 | sih->edr_offset, sih->bytes_edr); | 549 | sih->edr_offset, sih->bytes_edr); |
440 | if (status) { | 550 | if (status) { |
441 | pr_err("twl4030: %s, %s --> %d\n", __func__, | 551 | pr_err("twl4030: %s, %s --> %d\n", __func__, |
@@ -469,7 +579,7 @@ static void twl4030_sih_do_edge(struct work_struct *work) | |||
469 | } | 579 | } |
470 | 580 | ||
471 | /* Write */ | 581 | /* Write */ |
472 | status = twl4030_i2c_write(sih->module, bytes, | 582 | status = twl_i2c_write(sih->module, bytes, |
473 | sih->edr_offset, sih->bytes_edr); | 583 | sih->edr_offset, sih->bytes_edr); |
474 | if (status) | 584 | if (status) |
475 | pr_err("twl4030: %s, %s --> %d\n", __func__, | 585 | pr_err("twl4030: %s, %s --> %d\n", __func__, |
@@ -554,7 +664,7 @@ static inline int sih_read_isr(const struct sih *sih) | |||
554 | /* FIXME need retry-on-error ... */ | 664 | /* FIXME need retry-on-error ... */ |
555 | 665 | ||
556 | isr.word = 0; | 666 | isr.word = 0; |
557 | status = twl4030_i2c_read(sih->module, isr.bytes, | 667 | status = twl_i2c_read(sih->module, isr.bytes, |
558 | sih->mask[irq_line].isr_offset, sih->bytes_ixr); | 668 | sih->mask[irq_line].isr_offset, sih->bytes_ixr); |
559 | 669 | ||
560 | return (status < 0) ? status : le32_to_cpu(isr.word); | 670 | return (status < 0) ? status : le32_to_cpu(isr.word); |
@@ -611,7 +721,7 @@ int twl4030_sih_setup(int module) | |||
611 | 721 | ||
612 | /* only support modules with standard clear-on-read for now */ | 722 | /* only support modules with standard clear-on-read for now */ |
613 | for (sih_mod = 0, sih = sih_modules; | 723 | for (sih_mod = 0, sih = sih_modules; |
614 | sih_mod < ARRAY_SIZE(sih_modules); | 724 | sih_mod < nr_sih_modules; |
615 | sih_mod++, sih++) { | 725 | sih_mod++, sih++) { |
616 | if (sih->module == module && sih->set_cor) { | 726 | if (sih->module == module && sih->set_cor) { |
617 | if (!WARN((irq_base + sih->bits) > NR_IRQS, | 727 | if (!WARN((irq_base + sih->bits) > NR_IRQS, |
@@ -668,7 +778,7 @@ int twl4030_sih_setup(int module) | |||
668 | /* FIXME pass in which interrupt line we'll use ... */ | 778 | /* FIXME pass in which interrupt line we'll use ... */ |
669 | #define twl_irq_line 0 | 779 | #define twl_irq_line 0 |
670 | 780 | ||
671 | int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | 781 | int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) |
672 | { | 782 | { |
673 | static struct irq_chip twl4030_irq_chip; | 783 | static struct irq_chip twl4030_irq_chip; |
674 | 784 | ||
@@ -728,7 +838,8 @@ int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | |||
728 | goto fail_rqirq; | 838 | goto fail_rqirq; |
729 | } | 839 | } |
730 | 840 | ||
731 | task = kthread_run(twl4030_irq_thread, (void *)irq_num, "twl4030-irq"); | 841 | task = kthread_run(twl4030_irq_thread, (void *)(long)irq_num, |
842 | "twl4030-irq"); | ||
732 | if (IS_ERR(task)) { | 843 | if (IS_ERR(task)) { |
733 | pr_err("twl4030: could not create irq %d thread!\n", irq_num); | 844 | pr_err("twl4030: could not create irq %d thread!\n", irq_num); |
734 | status = PTR_ERR(task); | 845 | status = PTR_ERR(task); |
@@ -747,7 +858,7 @@ fail: | |||
747 | return status; | 858 | return status; |
748 | } | 859 | } |
749 | 860 | ||
750 | int twl_exit_irq(void) | 861 | int twl4030_exit_irq(void) |
751 | { | 862 | { |
752 | /* FIXME undo twl_init_irq() */ | 863 | /* FIXME undo twl_init_irq() */ |
753 | if (twl4030_irq_base) { | 864 | if (twl4030_irq_base) { |
@@ -756,3 +867,16 @@ int twl_exit_irq(void) | |||
756 | } | 867 | } |
757 | return 0; | 868 | return 0; |
758 | } | 869 | } |
870 | |||
871 | int twl4030_init_chip_irq(const char *chip) | ||
872 | { | ||
873 | if (!strcmp(chip, "twl5031")) { | ||
874 | sih_modules = sih_modules_twl5031; | ||
875 | nr_sih_modules = ARRAY_SIZE(sih_modules_twl5031); | ||
876 | } else { | ||
877 | sih_modules = sih_modules_twl4030; | ||
878 | nr_sih_modules = ARRAY_SIZE(sih_modules_twl4030); | ||
879 | } | ||
880 | |||
881 | return 0; | ||
882 | } | ||
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index d423e0c4176b..0815292fdafc 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c | |||
@@ -26,7 +26,7 @@ | |||
26 | 26 | ||
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/pm.h> | 28 | #include <linux/pm.h> |
29 | #include <linux/i2c/twl4030.h> | 29 | #include <linux/i2c/twl.h> |
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | 31 | ||
32 | #include <asm/mach-types.h> | 32 | #include <asm/mach-types.h> |
@@ -67,19 +67,35 @@ static u8 twl4030_start_script_address = 0x2b; | |||
67 | #define R_KEY_1 0xC0 | 67 | #define R_KEY_1 0xC0 |
68 | #define R_KEY_2 0x0C | 68 | #define R_KEY_2 0x0C |
69 | 69 | ||
70 | /* resource configuration registers */ | 70 | /* resource configuration registers |
71 | 71 | <RESOURCE>_DEV_GRP at address 'n+0' | |
72 | #define DEVGROUP_OFFSET 0 | 72 | <RESOURCE>_TYPE at address 'n+1' |
73 | <RESOURCE>_REMAP at address 'n+2' | ||
74 | <RESOURCE>_DEDICATED at address 'n+3' | ||
75 | */ | ||
76 | #define DEV_GRP_OFFSET 0 | ||
73 | #define TYPE_OFFSET 1 | 77 | #define TYPE_OFFSET 1 |
78 | #define REMAP_OFFSET 2 | ||
79 | #define DEDICATED_OFFSET 3 | ||
80 | |||
81 | /* Bit positions in the registers */ | ||
82 | |||
83 | /* <RESOURCE>_DEV_GRP */ | ||
84 | #define DEV_GRP_SHIFT 5 | ||
85 | #define DEV_GRP_MASK (7 << DEV_GRP_SHIFT) | ||
74 | 86 | ||
75 | /* Bit positions */ | 87 | /* <RESOURCE>_TYPE */ |
76 | #define DEVGROUP_SHIFT 5 | ||
77 | #define DEVGROUP_MASK (7 << DEVGROUP_SHIFT) | ||
78 | #define TYPE_SHIFT 0 | 88 | #define TYPE_SHIFT 0 |
79 | #define TYPE_MASK (7 << TYPE_SHIFT) | 89 | #define TYPE_MASK (7 << TYPE_SHIFT) |
80 | #define TYPE2_SHIFT 3 | 90 | #define TYPE2_SHIFT 3 |
81 | #define TYPE2_MASK (3 << TYPE2_SHIFT) | 91 | #define TYPE2_MASK (3 << TYPE2_SHIFT) |
82 | 92 | ||
93 | /* <RESOURCE>_REMAP */ | ||
94 | #define SLEEP_STATE_SHIFT 0 | ||
95 | #define SLEEP_STATE_MASK (0xf << SLEEP_STATE_SHIFT) | ||
96 | #define OFF_STATE_SHIFT 4 | ||
97 | #define OFF_STATE_MASK (0xf << OFF_STATE_SHIFT) | ||
98 | |||
83 | static u8 res_config_addrs[] = { | 99 | static u8 res_config_addrs[] = { |
84 | [RES_VAUX1] = 0x17, | 100 | [RES_VAUX1] = 0x17, |
85 | [RES_VAUX2] = 0x1b, | 101 | [RES_VAUX2] = 0x1b, |
@@ -115,11 +131,11 @@ static int __init twl4030_write_script_byte(u8 address, u8 byte) | |||
115 | { | 131 | { |
116 | int err; | 132 | int err; |
117 | 133 | ||
118 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, | 134 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, |
119 | R_MEMORY_ADDRESS); | 135 | R_MEMORY_ADDRESS); |
120 | if (err) | 136 | if (err) |
121 | goto out; | 137 | goto out; |
122 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte, | 138 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte, |
123 | R_MEMORY_DATA); | 139 | R_MEMORY_DATA); |
124 | out: | 140 | out: |
125 | return err; | 141 | return err; |
@@ -176,18 +192,18 @@ static int __init twl4030_config_wakeup3_sequence(u8 address) | |||
176 | u8 data; | 192 | u8 data; |
177 | 193 | ||
178 | /* Set SLEEP to ACTIVE SEQ address for P3 */ | 194 | /* Set SLEEP to ACTIVE SEQ address for P3 */ |
179 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, | 195 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, |
180 | R_SEQ_ADD_S2A3); | 196 | R_SEQ_ADD_S2A3); |
181 | if (err) | 197 | if (err) |
182 | goto out; | 198 | goto out; |
183 | 199 | ||
184 | /* P3 LVL_WAKEUP should be on LEVEL */ | 200 | /* P3 LVL_WAKEUP should be on LEVEL */ |
185 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, | 201 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, |
186 | R_P3_SW_EVENTS); | 202 | R_P3_SW_EVENTS); |
187 | if (err) | 203 | if (err) |
188 | goto out; | 204 | goto out; |
189 | data |= LVL_WAKEUP; | 205 | data |= LVL_WAKEUP; |
190 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data, | 206 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data, |
191 | R_P3_SW_EVENTS); | 207 | R_P3_SW_EVENTS); |
192 | out: | 208 | out: |
193 | if (err) | 209 | if (err) |
@@ -201,42 +217,42 @@ static int __init twl4030_config_wakeup12_sequence(u8 address) | |||
201 | u8 data; | 217 | u8 data; |
202 | 218 | ||
203 | /* Set SLEEP to ACTIVE SEQ address for P1 and P2 */ | 219 | /* Set SLEEP to ACTIVE SEQ address for P1 and P2 */ |
204 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, | 220 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, |
205 | R_SEQ_ADD_S2A12); | 221 | R_SEQ_ADD_S2A12); |
206 | if (err) | 222 | if (err) |
207 | goto out; | 223 | goto out; |
208 | 224 | ||
209 | /* P1/P2 LVL_WAKEUP should be on LEVEL */ | 225 | /* P1/P2 LVL_WAKEUP should be on LEVEL */ |
210 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, | 226 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, |
211 | R_P1_SW_EVENTS); | 227 | R_P1_SW_EVENTS); |
212 | if (err) | 228 | if (err) |
213 | goto out; | 229 | goto out; |
214 | 230 | ||
215 | data |= LVL_WAKEUP; | 231 | data |= LVL_WAKEUP; |
216 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data, | 232 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data, |
217 | R_P1_SW_EVENTS); | 233 | R_P1_SW_EVENTS); |
218 | if (err) | 234 | if (err) |
219 | goto out; | 235 | goto out; |
220 | 236 | ||
221 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, | 237 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, |
222 | R_P2_SW_EVENTS); | 238 | R_P2_SW_EVENTS); |
223 | if (err) | 239 | if (err) |
224 | goto out; | 240 | goto out; |
225 | 241 | ||
226 | data |= LVL_WAKEUP; | 242 | data |= LVL_WAKEUP; |
227 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data, | 243 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data, |
228 | R_P2_SW_EVENTS); | 244 | R_P2_SW_EVENTS); |
229 | if (err) | 245 | if (err) |
230 | goto out; | 246 | goto out; |
231 | 247 | ||
232 | if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) { | 248 | if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) { |
233 | /* Disabling AC charger effect on sleep-active transitions */ | 249 | /* Disabling AC charger effect on sleep-active transitions */ |
234 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, | 250 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, |
235 | R_CFG_P1_TRANSITION); | 251 | R_CFG_P1_TRANSITION); |
236 | if (err) | 252 | if (err) |
237 | goto out; | 253 | goto out; |
238 | data &= ~(1<<1); | 254 | data &= ~(1<<1); |
239 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data , | 255 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data , |
240 | R_CFG_P1_TRANSITION); | 256 | R_CFG_P1_TRANSITION); |
241 | if (err) | 257 | if (err) |
242 | goto out; | 258 | goto out; |
@@ -254,7 +270,7 @@ static int __init twl4030_config_sleep_sequence(u8 address) | |||
254 | int err; | 270 | int err; |
255 | 271 | ||
256 | /* Set ACTIVE to SLEEP SEQ address in T2 memory*/ | 272 | /* Set ACTIVE to SLEEP SEQ address in T2 memory*/ |
257 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, | 273 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, |
258 | R_SEQ_ADD_A2S); | 274 | R_SEQ_ADD_A2S); |
259 | 275 | ||
260 | if (err) | 276 | if (err) |
@@ -269,41 +285,41 @@ static int __init twl4030_config_warmreset_sequence(u8 address) | |||
269 | u8 rd_data; | 285 | u8 rd_data; |
270 | 286 | ||
271 | /* Set WARM RESET SEQ address for P1 */ | 287 | /* Set WARM RESET SEQ address for P1 */ |
272 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, | 288 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, |
273 | R_SEQ_ADD_WARM); | 289 | R_SEQ_ADD_WARM); |
274 | if (err) | 290 | if (err) |
275 | goto out; | 291 | goto out; |
276 | 292 | ||
277 | /* P1/P2/P3 enable WARMRESET */ | 293 | /* P1/P2/P3 enable WARMRESET */ |
278 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data, | 294 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data, |
279 | R_P1_SW_EVENTS); | 295 | R_P1_SW_EVENTS); |
280 | if (err) | 296 | if (err) |
281 | goto out; | 297 | goto out; |
282 | 298 | ||
283 | rd_data |= ENABLE_WARMRESET; | 299 | rd_data |= ENABLE_WARMRESET; |
284 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data, | 300 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data, |
285 | R_P1_SW_EVENTS); | 301 | R_P1_SW_EVENTS); |
286 | if (err) | 302 | if (err) |
287 | goto out; | 303 | goto out; |
288 | 304 | ||
289 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data, | 305 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data, |
290 | R_P2_SW_EVENTS); | 306 | R_P2_SW_EVENTS); |
291 | if (err) | 307 | if (err) |
292 | goto out; | 308 | goto out; |
293 | 309 | ||
294 | rd_data |= ENABLE_WARMRESET; | 310 | rd_data |= ENABLE_WARMRESET; |
295 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data, | 311 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data, |
296 | R_P2_SW_EVENTS); | 312 | R_P2_SW_EVENTS); |
297 | if (err) | 313 | if (err) |
298 | goto out; | 314 | goto out; |
299 | 315 | ||
300 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data, | 316 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data, |
301 | R_P3_SW_EVENTS); | 317 | R_P3_SW_EVENTS); |
302 | if (err) | 318 | if (err) |
303 | goto out; | 319 | goto out; |
304 | 320 | ||
305 | rd_data |= ENABLE_WARMRESET; | 321 | rd_data |= ENABLE_WARMRESET; |
306 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data, | 322 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data, |
307 | R_P3_SW_EVENTS); | 323 | R_P3_SW_EVENTS); |
308 | out: | 324 | out: |
309 | if (err) | 325 | if (err) |
@@ -317,6 +333,7 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig) | |||
317 | int err; | 333 | int err; |
318 | u8 type; | 334 | u8 type; |
319 | u8 grp; | 335 | u8 grp; |
336 | u8 remap; | ||
320 | 337 | ||
321 | if (rconfig->resource > TOTAL_RESOURCES) { | 338 | if (rconfig->resource > TOTAL_RESOURCES) { |
322 | pr_err("TWL4030 Resource %d does not exist\n", | 339 | pr_err("TWL4030 Resource %d does not exist\n", |
@@ -327,19 +344,19 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig) | |||
327 | rconfig_addr = res_config_addrs[rconfig->resource]; | 344 | rconfig_addr = res_config_addrs[rconfig->resource]; |
328 | 345 | ||
329 | /* Set resource group */ | 346 | /* Set resource group */ |
330 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp, | 347 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp, |
331 | rconfig_addr + DEVGROUP_OFFSET); | 348 | rconfig_addr + DEV_GRP_OFFSET); |
332 | if (err) { | 349 | if (err) { |
333 | pr_err("TWL4030 Resource %d group could not be read\n", | 350 | pr_err("TWL4030 Resource %d group could not be read\n", |
334 | rconfig->resource); | 351 | rconfig->resource); |
335 | return err; | 352 | return err; |
336 | } | 353 | } |
337 | 354 | ||
338 | if (rconfig->devgroup >= 0) { | 355 | if (rconfig->devgroup != TWL4030_RESCONFIG_UNDEF) { |
339 | grp &= ~DEVGROUP_MASK; | 356 | grp &= ~DEV_GRP_MASK; |
340 | grp |= rconfig->devgroup << DEVGROUP_SHIFT; | 357 | grp |= rconfig->devgroup << DEV_GRP_SHIFT; |
341 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, | 358 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, |
342 | grp, rconfig_addr + DEVGROUP_OFFSET); | 359 | grp, rconfig_addr + DEV_GRP_OFFSET); |
343 | if (err < 0) { | 360 | if (err < 0) { |
344 | pr_err("TWL4030 failed to program devgroup\n"); | 361 | pr_err("TWL4030 failed to program devgroup\n"); |
345 | return err; | 362 | return err; |
@@ -347,7 +364,7 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig) | |||
347 | } | 364 | } |
348 | 365 | ||
349 | /* Set resource types */ | 366 | /* Set resource types */ |
350 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &type, | 367 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &type, |
351 | rconfig_addr + TYPE_OFFSET); | 368 | rconfig_addr + TYPE_OFFSET); |
352 | if (err < 0) { | 369 | if (err < 0) { |
353 | pr_err("TWL4030 Resource %d type could not be read\n", | 370 | pr_err("TWL4030 Resource %d type could not be read\n", |
@@ -355,23 +372,50 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig) | |||
355 | return err; | 372 | return err; |
356 | } | 373 | } |
357 | 374 | ||
358 | if (rconfig->type >= 0) { | 375 | if (rconfig->type != TWL4030_RESCONFIG_UNDEF) { |
359 | type &= ~TYPE_MASK; | 376 | type &= ~TYPE_MASK; |
360 | type |= rconfig->type << TYPE_SHIFT; | 377 | type |= rconfig->type << TYPE_SHIFT; |
361 | } | 378 | } |
362 | 379 | ||
363 | if (rconfig->type2 >= 0) { | 380 | if (rconfig->type2 != TWL4030_RESCONFIG_UNDEF) { |
364 | type &= ~TYPE2_MASK; | 381 | type &= ~TYPE2_MASK; |
365 | type |= rconfig->type2 << TYPE2_SHIFT; | 382 | type |= rconfig->type2 << TYPE2_SHIFT; |
366 | } | 383 | } |
367 | 384 | ||
368 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, | 385 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, |
369 | type, rconfig_addr + TYPE_OFFSET); | 386 | type, rconfig_addr + TYPE_OFFSET); |
370 | if (err < 0) { | 387 | if (err < 0) { |
371 | pr_err("TWL4030 failed to program resource type\n"); | 388 | pr_err("TWL4030 failed to program resource type\n"); |
372 | return err; | 389 | return err; |
373 | } | 390 | } |
374 | 391 | ||
392 | /* Set remap states */ | ||
393 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &remap, | ||
394 | rconfig_addr + REMAP_OFFSET); | ||
395 | if (err < 0) { | ||
396 | pr_err("TWL4030 Resource %d remap could not be read\n", | ||
397 | rconfig->resource); | ||
398 | return err; | ||
399 | } | ||
400 | |||
401 | if (rconfig->remap_off != TWL4030_RESCONFIG_UNDEF) { | ||
402 | remap &= ~OFF_STATE_MASK; | ||
403 | remap |= rconfig->remap_off << OFF_STATE_SHIFT; | ||
404 | } | ||
405 | |||
406 | if (rconfig->remap_sleep != TWL4030_RESCONFIG_UNDEF) { | ||
407 | remap &= ~SLEEP_STATE_MASK; | ||
408 | remap |= rconfig->remap_off << SLEEP_STATE_SHIFT; | ||
409 | } | ||
410 | |||
411 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, | ||
412 | remap, | ||
413 | rconfig_addr + REMAP_OFFSET); | ||
414 | if (err < 0) { | ||
415 | pr_err("TWL4030 failed to program remap\n"); | ||
416 | return err; | ||
417 | } | ||
418 | |||
375 | return 0; | 419 | return 0; |
376 | } | 420 | } |
377 | 421 | ||
@@ -424,12 +468,12 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) | |||
424 | struct twl4030_resconfig *resconfig; | 468 | struct twl4030_resconfig *resconfig; |
425 | u8 address = twl4030_start_script_address; | 469 | u8 address = twl4030_start_script_address; |
426 | 470 | ||
427 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1, | 471 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1, |
428 | R_PROTECT_KEY); | 472 | R_PROTECT_KEY); |
429 | if (err) | 473 | if (err) |
430 | goto unlock; | 474 | goto unlock; |
431 | 475 | ||
432 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2, | 476 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2, |
433 | R_PROTECT_KEY); | 477 | R_PROTECT_KEY); |
434 | if (err) | 478 | if (err) |
435 | goto unlock; | 479 | goto unlock; |
@@ -452,7 +496,7 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) | |||
452 | } | 496 | } |
453 | } | 497 | } |
454 | 498 | ||
455 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY); | 499 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY); |
456 | if (err) | 500 | if (err) |
457 | pr_err("TWL4030 Unable to relock registers\n"); | 501 | pr_err("TWL4030 Unable to relock registers\n"); |
458 | return; | 502 | return; |
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c new file mode 100644 index 000000000000..10bf228ad626 --- /dev/null +++ b/drivers/mfd/twl6030-irq.c | |||
@@ -0,0 +1,299 @@ | |||
1 | /* | ||
2 | * twl6030-irq.c - TWL6030 irq support | ||
3 | * | ||
4 | * Copyright (C) 2005-2009 Texas Instruments, Inc. | ||
5 | * | ||
6 | * Modifications to defer interrupt handling to a kernel thread: | ||
7 | * Copyright (C) 2006 MontaVista Software, Inc. | ||
8 | * | ||
9 | * Based on tlv320aic23.c: | ||
10 | * Copyright (c) by Kai Svahn <kai.svahn@nokia.com> | ||
11 | * | ||
12 | * Code cleanup and modifications to IRQ handler. | ||
13 | * by syed khasim <x0khasim@ti.com> | ||
14 | * | ||
15 | * TWL6030 specific code and IRQ handling changes by | ||
16 | * Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com> | ||
17 | * Balaji T K <balajitk@ti.com> | ||
18 | * | ||
19 | * This program is free software; you can redistribute it and/or modify | ||
20 | * it under the terms of the GNU General Public License as published by | ||
21 | * the Free Software Foundation; either version 2 of the License, or | ||
22 | * (at your option) any later version. | ||
23 | * | ||
24 | * This program is distributed in the hope that it will be useful, | ||
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
27 | * GNU General Public License for more details. | ||
28 | * | ||
29 | * You should have received a copy of the GNU General Public License | ||
30 | * along with this program; if not, write to the Free Software | ||
31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
32 | */ | ||
33 | |||
34 | #include <linux/init.h> | ||
35 | #include <linux/interrupt.h> | ||
36 | #include <linux/irq.h> | ||
37 | #include <linux/kthread.h> | ||
38 | #include <linux/i2c/twl.h> | ||
39 | |||
40 | /* | ||
41 | * TWL6030 (unlike its predecessors, which had two level interrupt handling) | ||
42 | * three interrupt registers INT_STS_A, INT_STS_B and INT_STS_C. | ||
43 | * It exposes status bits saying who has raised an interrupt. There are | ||
44 | * three mask registers that corresponds to these status registers, that | ||
45 | * enables/disables these interrupts. | ||
46 | * | ||
47 | * We set up IRQs starting at a platform-specified base. An interrupt map table, | ||
48 | * specifies mapping between interrupt number and the associated module. | ||
49 | * | ||
50 | */ | ||
51 | |||
52 | static int twl6030_interrupt_mapping[24] = { | ||
53 | PWR_INTR_OFFSET, /* Bit 0 PWRON */ | ||
54 | PWR_INTR_OFFSET, /* Bit 1 RPWRON */ | ||
55 | PWR_INTR_OFFSET, /* Bit 2 BAT_VLOW */ | ||
56 | RTC_INTR_OFFSET, /* Bit 3 RTC_ALARM */ | ||
57 | RTC_INTR_OFFSET, /* Bit 4 RTC_PERIOD */ | ||
58 | HOTDIE_INTR_OFFSET, /* Bit 5 HOT_DIE */ | ||
59 | SMPSLDO_INTR_OFFSET, /* Bit 6 VXXX_SHORT */ | ||
60 | SMPSLDO_INTR_OFFSET, /* Bit 7 VMMC_SHORT */ | ||
61 | |||
62 | SMPSLDO_INTR_OFFSET, /* Bit 8 VUSIM_SHORT */ | ||
63 | BATDETECT_INTR_OFFSET, /* Bit 9 BAT */ | ||
64 | SIMDETECT_INTR_OFFSET, /* Bit 10 SIM */ | ||
65 | MMCDETECT_INTR_OFFSET, /* Bit 11 MMC */ | ||
66 | RSV_INTR_OFFSET, /* Bit 12 Reserved */ | ||
67 | MADC_INTR_OFFSET, /* Bit 13 GPADC_RT_EOC */ | ||
68 | MADC_INTR_OFFSET, /* Bit 14 GPADC_SW_EOC */ | ||
69 | GASGAUGE_INTR_OFFSET, /* Bit 15 CC_AUTOCAL */ | ||
70 | |||
71 | USBOTG_INTR_OFFSET, /* Bit 16 ID_WKUP */ | ||
72 | USBOTG_INTR_OFFSET, /* Bit 17 VBUS_WKUP */ | ||
73 | USBOTG_INTR_OFFSET, /* Bit 18 ID */ | ||
74 | USBOTG_INTR_OFFSET, /* Bit 19 VBUS */ | ||
75 | CHARGER_INTR_OFFSET, /* Bit 20 CHRG_CTRL */ | ||
76 | CHARGER_INTR_OFFSET, /* Bit 21 EXT_CHRG */ | ||
77 | CHARGER_INTR_OFFSET, /* Bit 22 INT_CHRG */ | ||
78 | RSV_INTR_OFFSET, /* Bit 23 Reserved */ | ||
79 | }; | ||
80 | /*----------------------------------------------------------------------*/ | ||
81 | |||
82 | static unsigned twl6030_irq_base; | ||
83 | |||
84 | static struct completion irq_event; | ||
85 | |||
86 | /* | ||
87 | * This thread processes interrupts reported by the Primary Interrupt Handler. | ||
88 | */ | ||
89 | static int twl6030_irq_thread(void *data) | ||
90 | { | ||
91 | long irq = (long)data; | ||
92 | static unsigned i2c_errors; | ||
93 | static const unsigned max_i2c_errors = 100; | ||
94 | int ret; | ||
95 | |||
96 | current->flags |= PF_NOFREEZE; | ||
97 | |||
98 | while (!kthread_should_stop()) { | ||
99 | int i; | ||
100 | union { | ||
101 | u8 bytes[4]; | ||
102 | u32 int_sts; | ||
103 | } sts; | ||
104 | |||
105 | /* Wait for IRQ, then read PIH irq status (also blocking) */ | ||
106 | wait_for_completion_interruptible(&irq_event); | ||
107 | |||
108 | /* read INT_STS_A, B and C in one shot using a burst read */ | ||
109 | ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes, | ||
110 | REG_INT_STS_A, 3); | ||
111 | if (ret) { | ||
112 | pr_warning("twl6030: I2C error %d reading PIH ISR\n", | ||
113 | ret); | ||
114 | if (++i2c_errors >= max_i2c_errors) { | ||
115 | printk(KERN_ERR "Maximum I2C error count" | ||
116 | " exceeded. Terminating %s.\n", | ||
117 | __func__); | ||
118 | break; | ||
119 | } | ||
120 | complete(&irq_event); | ||
121 | continue; | ||
122 | } | ||
123 | |||
124 | |||
125 | |||
126 | sts.bytes[3] = 0; /* Only 24 bits are valid*/ | ||
127 | |||
128 | for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) { | ||
129 | local_irq_disable(); | ||
130 | if (sts.int_sts & 0x1) { | ||
131 | int module_irq = twl6030_irq_base + | ||
132 | twl6030_interrupt_mapping[i]; | ||
133 | struct irq_desc *d = irq_to_desc(module_irq); | ||
134 | |||
135 | if (!d) { | ||
136 | pr_err("twl6030: Invalid SIH IRQ: %d\n", | ||
137 | module_irq); | ||
138 | return -EINVAL; | ||
139 | } | ||
140 | |||
141 | /* These can't be masked ... always warn | ||
142 | * if we get any surprises. | ||
143 | */ | ||
144 | if (d->status & IRQ_DISABLED) | ||
145 | note_interrupt(module_irq, d, | ||
146 | IRQ_NONE); | ||
147 | else | ||
148 | d->handle_irq(module_irq, d); | ||
149 | |||
150 | } | ||
151 | local_irq_enable(); | ||
152 | } | ||
153 | ret = twl_i2c_write(TWL_MODULE_PIH, sts.bytes, | ||
154 | REG_INT_STS_A, 3); /* clear INT_STS_A */ | ||
155 | if (ret) | ||
156 | pr_warning("twl6030: I2C error in clearing PIH ISR\n"); | ||
157 | |||
158 | enable_irq(irq); | ||
159 | } | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * handle_twl6030_int() is the desc->handle method for the twl6030 interrupt. | ||
166 | * This is a chained interrupt, so there is no desc->action method for it. | ||
167 | * Now we need to query the interrupt controller in the twl6030 to determine | ||
168 | * which module is generating the interrupt request. However, we can't do i2c | ||
169 | * transactions in interrupt context, so we must defer that work to a kernel | ||
170 | * thread. All we do here is acknowledge and mask the interrupt and wakeup | ||
171 | * the kernel thread. | ||
172 | */ | ||
173 | static irqreturn_t handle_twl6030_pih(int irq, void *devid) | ||
174 | { | ||
175 | disable_irq_nosync(irq); | ||
176 | complete(devid); | ||
177 | return IRQ_HANDLED; | ||
178 | } | ||
179 | |||
180 | /*----------------------------------------------------------------------*/ | ||
181 | |||
182 | static inline void activate_irq(int irq) | ||
183 | { | ||
184 | #ifdef CONFIG_ARM | ||
185 | /* ARM requires an extra step to clear IRQ_NOREQUEST, which it | ||
186 | * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE. | ||
187 | */ | ||
188 | set_irq_flags(irq, IRQF_VALID); | ||
189 | #else | ||
190 | /* same effect on other architectures */ | ||
191 | set_irq_noprobe(irq); | ||
192 | #endif | ||
193 | } | ||
194 | |||
195 | /*----------------------------------------------------------------------*/ | ||
196 | |||
197 | static unsigned twl6030_irq_next; | ||
198 | |||
199 | /*----------------------------------------------------------------------*/ | ||
200 | int twl6030_interrupt_unmask(u8 bit_mask, u8 offset) | ||
201 | { | ||
202 | int ret; | ||
203 | u8 unmask_value; | ||
204 | ret = twl_i2c_read_u8(TWL_MODULE_PIH, &unmask_value, | ||
205 | REG_INT_STS_A + offset); | ||
206 | unmask_value &= (~(bit_mask)); | ||
207 | ret |= twl_i2c_write_u8(TWL_MODULE_PIH, unmask_value, | ||
208 | REG_INT_STS_A + offset); /* unmask INT_MSK_A/B/C */ | ||
209 | return ret; | ||
210 | } | ||
211 | EXPORT_SYMBOL(twl6030_interrupt_unmask); | ||
212 | |||
213 | int twl6030_interrupt_mask(u8 bit_mask, u8 offset) | ||
214 | { | ||
215 | int ret; | ||
216 | u8 mask_value; | ||
217 | ret = twl_i2c_read_u8(TWL_MODULE_PIH, &mask_value, | ||
218 | REG_INT_STS_A + offset); | ||
219 | mask_value |= (bit_mask); | ||
220 | ret |= twl_i2c_write_u8(TWL_MODULE_PIH, mask_value, | ||
221 | REG_INT_STS_A + offset); /* mask INT_MSK_A/B/C */ | ||
222 | return ret; | ||
223 | } | ||
224 | EXPORT_SYMBOL(twl6030_interrupt_mask); | ||
225 | |||
226 | int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | ||
227 | { | ||
228 | |||
229 | int status = 0; | ||
230 | int i; | ||
231 | struct task_struct *task; | ||
232 | int ret; | ||
233 | u8 mask[4]; | ||
234 | |||
235 | static struct irq_chip twl6030_irq_chip; | ||
236 | mask[1] = 0xFF; | ||
237 | mask[2] = 0xFF; | ||
238 | mask[3] = 0xFF; | ||
239 | ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], | ||
240 | REG_INT_MSK_LINE_A, 3); /* MASK ALL INT LINES */ | ||
241 | ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], | ||
242 | REG_INT_MSK_STS_A, 3); /* MASK ALL INT STS */ | ||
243 | ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], | ||
244 | REG_INT_STS_A, 3); /* clear INT_STS_A,B,C */ | ||
245 | |||
246 | twl6030_irq_base = irq_base; | ||
247 | |||
248 | /* install an irq handler for each of the modules; | ||
249 | * clone dummy irq_chip since PIH can't *do* anything | ||
250 | */ | ||
251 | twl6030_irq_chip = dummy_irq_chip; | ||
252 | twl6030_irq_chip.name = "twl6030"; | ||
253 | twl6030_irq_chip.set_type = NULL; | ||
254 | |||
255 | for (i = irq_base; i < irq_end; i++) { | ||
256 | set_irq_chip_and_handler(i, &twl6030_irq_chip, | ||
257 | handle_simple_irq); | ||
258 | activate_irq(i); | ||
259 | } | ||
260 | |||
261 | twl6030_irq_next = i; | ||
262 | pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH", | ||
263 | irq_num, irq_base, twl6030_irq_next - 1); | ||
264 | |||
265 | /* install an irq handler to demultiplex the TWL6030 interrupt */ | ||
266 | init_completion(&irq_event); | ||
267 | task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq"); | ||
268 | if (IS_ERR(task)) { | ||
269 | pr_err("twl6030: could not create irq %d thread!\n", irq_num); | ||
270 | status = PTR_ERR(task); | ||
271 | goto fail_kthread; | ||
272 | } | ||
273 | |||
274 | status = request_irq(irq_num, handle_twl6030_pih, IRQF_DISABLED, | ||
275 | "TWL6030-PIH", &irq_event); | ||
276 | if (status < 0) { | ||
277 | pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status); | ||
278 | goto fail_irq; | ||
279 | } | ||
280 | return status; | ||
281 | fail_irq: | ||
282 | free_irq(irq_num, &irq_event); | ||
283 | |||
284 | fail_kthread: | ||
285 | for (i = irq_base; i < irq_end; i++) | ||
286 | set_irq_chip_and_handler(i, NULL, NULL); | ||
287 | return status; | ||
288 | } | ||
289 | |||
290 | int twl6030_exit_irq(void) | ||
291 | { | ||
292 | |||
293 | if (twl6030_irq_base) { | ||
294 | pr_err("twl6030: can't yet clean up IRQs?\n"); | ||
295 | return -ENOSYS; | ||
296 | } | ||
297 | return 0; | ||
298 | } | ||
299 | |||
diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c index fa294b6d600a..85fd9421be94 100644 --- a/drivers/mfd/ucb1400_core.c +++ b/drivers/mfd/ucb1400_core.c | |||
@@ -51,6 +51,7 @@ static int ucb1400_core_probe(struct device *dev) | |||
51 | struct ucb1400_ts ucb_ts; | 51 | struct ucb1400_ts ucb_ts; |
52 | struct ucb1400_gpio ucb_gpio; | 52 | struct ucb1400_gpio ucb_gpio; |
53 | struct snd_ac97 *ac97; | 53 | struct snd_ac97 *ac97; |
54 | struct ucb1400_pdata *pdata = dev->platform_data; | ||
54 | 55 | ||
55 | memset(&ucb_ts, 0, sizeof(ucb_ts)); | 56 | memset(&ucb_ts, 0, sizeof(ucb_ts)); |
56 | memset(&ucb_gpio, 0, sizeof(ucb_gpio)); | 57 | memset(&ucb_gpio, 0, sizeof(ucb_gpio)); |
@@ -88,6 +89,12 @@ static int ucb1400_core_probe(struct device *dev) | |||
88 | 89 | ||
89 | /* TOUCHSCREEN */ | 90 | /* TOUCHSCREEN */ |
90 | ucb_ts.ac97 = ac97; | 91 | ucb_ts.ac97 = ac97; |
92 | |||
93 | if (pdata != NULL && pdata->irq >= 0) | ||
94 | ucb_ts.irq = pdata->irq; | ||
95 | else | ||
96 | ucb_ts.irq = -1; | ||
97 | |||
91 | ucb->ucb1400_ts = platform_device_alloc("ucb1400_ts", -1); | 98 | ucb->ucb1400_ts = platform_device_alloc("ucb1400_ts", -1); |
92 | if (!ucb->ucb1400_ts) { | 99 | if (!ucb->ucb1400_ts) { |
93 | err = -ENOMEM; | 100 | err = -ENOMEM; |
diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c index 86fed4870f93..cea9da60850d 100644 --- a/drivers/mfd/ucb1x00-assabet.c +++ b/drivers/mfd/ucb1x00-assabet.c | |||
@@ -14,10 +14,10 @@ | |||
14 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
15 | #include <linux/proc_fs.h> | 15 | #include <linux/proc_fs.h> |
16 | #include <linux/device.h> | 16 | #include <linux/device.h> |
17 | #include <linux/mfd/ucb1x00.h> | ||
17 | 18 | ||
18 | #include <mach/dma.h> | 19 | #include <mach/dma.h> |
19 | 20 | ||
20 | #include "ucb1x00.h" | ||
21 | 21 | ||
22 | #define UCB1X00_ATTR(name,input)\ | 22 | #define UCB1X00_ATTR(name,input)\ |
23 | static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \ | 23 | static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \ |
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index 60c3988f3cf3..252b74188ec2 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c | |||
@@ -25,12 +25,12 @@ | |||
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/device.h> | 26 | #include <linux/device.h> |
27 | #include <linux/mutex.h> | 27 | #include <linux/mutex.h> |
28 | #include <linux/mfd/ucb1x00.h> | ||
29 | #include <linux/gpio.h> | ||
28 | 30 | ||
29 | #include <mach/dma.h> | 31 | #include <mach/dma.h> |
30 | #include <mach/hardware.h> | 32 | #include <mach/hardware.h> |
31 | 33 | ||
32 | #include "ucb1x00.h" | ||
33 | |||
34 | static DEFINE_MUTEX(ucb1x00_mutex); | 34 | static DEFINE_MUTEX(ucb1x00_mutex); |
35 | static LIST_HEAD(ucb1x00_drivers); | 35 | static LIST_HEAD(ucb1x00_drivers); |
36 | static LIST_HEAD(ucb1x00_devices); | 36 | static LIST_HEAD(ucb1x00_devices); |
@@ -108,6 +108,60 @@ unsigned int ucb1x00_io_read(struct ucb1x00 *ucb) | |||
108 | return ucb1x00_reg_read(ucb, UCB_IO_DATA); | 108 | return ucb1x00_reg_read(ucb, UCB_IO_DATA); |
109 | } | 109 | } |
110 | 110 | ||
111 | static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
112 | { | ||
113 | struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); | ||
114 | unsigned long flags; | ||
115 | |||
116 | spin_lock_irqsave(&ucb->io_lock, flags); | ||
117 | if (value) | ||
118 | ucb->io_out |= 1 << offset; | ||
119 | else | ||
120 | ucb->io_out &= ~(1 << offset); | ||
121 | |||
122 | ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); | ||
123 | spin_unlock_irqrestore(&ucb->io_lock, flags); | ||
124 | } | ||
125 | |||
126 | static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
127 | { | ||
128 | struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); | ||
129 | return ucb1x00_reg_read(ucb, UCB_IO_DATA) & (1 << offset); | ||
130 | } | ||
131 | |||
132 | static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
133 | { | ||
134 | struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); | ||
135 | unsigned long flags; | ||
136 | |||
137 | spin_lock_irqsave(&ucb->io_lock, flags); | ||
138 | ucb->io_dir &= ~(1 << offset); | ||
139 | ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); | ||
140 | spin_unlock_irqrestore(&ucb->io_lock, flags); | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset | ||
146 | , int value) | ||
147 | { | ||
148 | struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); | ||
149 | unsigned long flags; | ||
150 | |||
151 | spin_lock_irqsave(&ucb->io_lock, flags); | ||
152 | ucb->io_dir |= (1 << offset); | ||
153 | ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); | ||
154 | |||
155 | if (value) | ||
156 | ucb->io_out |= 1 << offset; | ||
157 | else | ||
158 | ucb->io_out &= ~(1 << offset); | ||
159 | ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); | ||
160 | spin_unlock_irqrestore(&ucb->io_lock, flags); | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
111 | /* | 165 | /* |
112 | * UCB1300 data sheet says we must: | 166 | * UCB1300 data sheet says we must: |
113 | * 1. enable ADC => 5us (including reference startup time) | 167 | * 1. enable ADC => 5us (including reference startup time) |
@@ -476,6 +530,7 @@ static int ucb1x00_probe(struct mcp *mcp) | |||
476 | struct ucb1x00_driver *drv; | 530 | struct ucb1x00_driver *drv; |
477 | unsigned int id; | 531 | unsigned int id; |
478 | int ret = -ENODEV; | 532 | int ret = -ENODEV; |
533 | int temp; | ||
479 | 534 | ||
480 | mcp_enable(mcp); | 535 | mcp_enable(mcp); |
481 | id = mcp_reg_read(mcp, UCB_ID); | 536 | id = mcp_reg_read(mcp, UCB_ID); |
@@ -508,12 +563,27 @@ static int ucb1x00_probe(struct mcp *mcp) | |||
508 | goto err_free; | 563 | goto err_free; |
509 | } | 564 | } |
510 | 565 | ||
566 | ucb->gpio.base = -1; | ||
567 | if (mcp->gpio_base != 0) { | ||
568 | ucb->gpio.label = dev_name(&ucb->dev); | ||
569 | ucb->gpio.base = mcp->gpio_base; | ||
570 | ucb->gpio.ngpio = 10; | ||
571 | ucb->gpio.set = ucb1x00_gpio_set; | ||
572 | ucb->gpio.get = ucb1x00_gpio_get; | ||
573 | ucb->gpio.direction_input = ucb1x00_gpio_direction_input; | ||
574 | ucb->gpio.direction_output = ucb1x00_gpio_direction_output; | ||
575 | ret = gpiochip_add(&ucb->gpio); | ||
576 | if (ret) | ||
577 | goto err_free; | ||
578 | } else | ||
579 | dev_info(&ucb->dev, "gpio_base not set so no gpiolib support"); | ||
580 | |||
511 | ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING, | 581 | ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING, |
512 | "UCB1x00", ucb); | 582 | "UCB1x00", ucb); |
513 | if (ret) { | 583 | if (ret) { |
514 | printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n", | 584 | printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n", |
515 | ucb->irq, ret); | 585 | ucb->irq, ret); |
516 | goto err_free; | 586 | goto err_gpio; |
517 | } | 587 | } |
518 | 588 | ||
519 | mcp_set_drvdata(mcp, ucb); | 589 | mcp_set_drvdata(mcp, ucb); |
@@ -522,6 +592,7 @@ static int ucb1x00_probe(struct mcp *mcp) | |||
522 | if (ret) | 592 | if (ret) |
523 | goto err_irq; | 593 | goto err_irq; |
524 | 594 | ||
595 | |||
525 | INIT_LIST_HEAD(&ucb->devs); | 596 | INIT_LIST_HEAD(&ucb->devs); |
526 | mutex_lock(&ucb1x00_mutex); | 597 | mutex_lock(&ucb1x00_mutex); |
527 | list_add(&ucb->node, &ucb1x00_devices); | 598 | list_add(&ucb->node, &ucb1x00_devices); |
@@ -529,10 +600,14 @@ static int ucb1x00_probe(struct mcp *mcp) | |||
529 | ucb1x00_add_dev(ucb, drv); | 600 | ucb1x00_add_dev(ucb, drv); |
530 | } | 601 | } |
531 | mutex_unlock(&ucb1x00_mutex); | 602 | mutex_unlock(&ucb1x00_mutex); |
603 | |||
532 | goto out; | 604 | goto out; |
533 | 605 | ||
534 | err_irq: | 606 | err_irq: |
535 | free_irq(ucb->irq, ucb); | 607 | free_irq(ucb->irq, ucb); |
608 | err_gpio: | ||
609 | if (ucb->gpio.base != -1) | ||
610 | temp = gpiochip_remove(&ucb->gpio); | ||
536 | err_free: | 611 | err_free: |
537 | kfree(ucb); | 612 | kfree(ucb); |
538 | err_disable: | 613 | err_disable: |
@@ -545,6 +620,7 @@ static void ucb1x00_remove(struct mcp *mcp) | |||
545 | { | 620 | { |
546 | struct ucb1x00 *ucb = mcp_get_drvdata(mcp); | 621 | struct ucb1x00 *ucb = mcp_get_drvdata(mcp); |
547 | struct list_head *l, *n; | 622 | struct list_head *l, *n; |
623 | int ret; | ||
548 | 624 | ||
549 | mutex_lock(&ucb1x00_mutex); | 625 | mutex_lock(&ucb1x00_mutex); |
550 | list_del(&ucb->node); | 626 | list_del(&ucb->node); |
@@ -554,6 +630,12 @@ static void ucb1x00_remove(struct mcp *mcp) | |||
554 | } | 630 | } |
555 | mutex_unlock(&ucb1x00_mutex); | 631 | mutex_unlock(&ucb1x00_mutex); |
556 | 632 | ||
633 | if (ucb->gpio.base != -1) { | ||
634 | ret = gpiochip_remove(&ucb->gpio); | ||
635 | if (ret) | ||
636 | dev_err(&ucb->dev, "Can't remove gpio chip: %d\n", ret); | ||
637 | } | ||
638 | |||
557 | free_irq(ucb->irq, ucb); | 639 | free_irq(ucb->irq, ucb); |
558 | device_unregister(&ucb->dev); | 640 | device_unregister(&ucb->dev); |
559 | } | 641 | } |
@@ -604,6 +686,7 @@ static int ucb1x00_resume(struct mcp *mcp) | |||
604 | struct ucb1x00 *ucb = mcp_get_drvdata(mcp); | 686 | struct ucb1x00 *ucb = mcp_get_drvdata(mcp); |
605 | struct ucb1x00_dev *dev; | 687 | struct ucb1x00_dev *dev; |
606 | 688 | ||
689 | ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); | ||
607 | mutex_lock(&ucb1x00_mutex); | 690 | mutex_lock(&ucb1x00_mutex); |
608 | list_for_each_entry(dev, &ucb->devs, dev_node) { | 691 | list_for_each_entry(dev, &ucb->devs, dev_node) { |
609 | if (dev->drv->resume) | 692 | if (dev->drv->resume) |
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 61b7d3eb9a2f..000cb414a78a 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c | |||
@@ -30,12 +30,12 @@ | |||
30 | #include <linux/freezer.h> | 30 | #include <linux/freezer.h> |
31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
32 | #include <linux/kthread.h> | 32 | #include <linux/kthread.h> |
33 | #include <linux/mfd/ucb1x00.h> | ||
33 | 34 | ||
34 | #include <mach/dma.h> | 35 | #include <mach/dma.h> |
35 | #include <mach/collie.h> | 36 | #include <mach/collie.h> |
36 | #include <asm/mach-types.h> | 37 | #include <asm/mach-types.h> |
37 | 38 | ||
38 | #include "ucb1x00.h" | ||
39 | 39 | ||
40 | 40 | ||
41 | struct ucb1x00_ts { | 41 | struct ucb1x00_ts { |
diff --git a/drivers/mfd/ucb1x00.h b/drivers/mfd/ucb1x00.h deleted file mode 100644 index a8ad8a0ed5db..000000000000 --- a/drivers/mfd/ucb1x00.h +++ /dev/null | |||
@@ -1,255 +0,0 @@ | |||
1 | /* | ||
2 | * linux/drivers/mfd/ucb1x00.h | ||
3 | * | ||
4 | * Copyright (C) 2001 Russell King, All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License. | ||
9 | */ | ||
10 | #ifndef UCB1200_H | ||
11 | #define UCB1200_H | ||
12 | |||
13 | #define UCB_IO_DATA 0x00 | ||
14 | #define UCB_IO_DIR 0x01 | ||
15 | |||
16 | #define UCB_IO_0 (1 << 0) | ||
17 | #define UCB_IO_1 (1 << 1) | ||
18 | #define UCB_IO_2 (1 << 2) | ||
19 | #define UCB_IO_3 (1 << 3) | ||
20 | #define UCB_IO_4 (1 << 4) | ||
21 | #define UCB_IO_5 (1 << 5) | ||
22 | #define UCB_IO_6 (1 << 6) | ||
23 | #define UCB_IO_7 (1 << 7) | ||
24 | #define UCB_IO_8 (1 << 8) | ||
25 | #define UCB_IO_9 (1 << 9) | ||
26 | |||
27 | #define UCB_IE_RIS 0x02 | ||
28 | #define UCB_IE_FAL 0x03 | ||
29 | #define UCB_IE_STATUS 0x04 | ||
30 | #define UCB_IE_CLEAR 0x04 | ||
31 | #define UCB_IE_ADC (1 << 11) | ||
32 | #define UCB_IE_TSPX (1 << 12) | ||
33 | #define UCB_IE_TSMX (1 << 13) | ||
34 | #define UCB_IE_TCLIP (1 << 14) | ||
35 | #define UCB_IE_ACLIP (1 << 15) | ||
36 | |||
37 | #define UCB_IRQ_TSPX 12 | ||
38 | |||
39 | #define UCB_TC_A 0x05 | ||
40 | #define UCB_TC_A_LOOP (1 << 7) /* UCB1200 */ | ||
41 | #define UCB_TC_A_AMPL (1 << 7) /* UCB1300 */ | ||
42 | |||
43 | #define UCB_TC_B 0x06 | ||
44 | #define UCB_TC_B_VOICE_ENA (1 << 3) | ||
45 | #define UCB_TC_B_CLIP (1 << 4) | ||
46 | #define UCB_TC_B_ATT (1 << 6) | ||
47 | #define UCB_TC_B_SIDE_ENA (1 << 11) | ||
48 | #define UCB_TC_B_MUTE (1 << 13) | ||
49 | #define UCB_TC_B_IN_ENA (1 << 14) | ||
50 | #define UCB_TC_B_OUT_ENA (1 << 15) | ||
51 | |||
52 | #define UCB_AC_A 0x07 | ||
53 | #define UCB_AC_B 0x08 | ||
54 | #define UCB_AC_B_LOOP (1 << 8) | ||
55 | #define UCB_AC_B_MUTE (1 << 13) | ||
56 | #define UCB_AC_B_IN_ENA (1 << 14) | ||
57 | #define UCB_AC_B_OUT_ENA (1 << 15) | ||
58 | |||
59 | #define UCB_TS_CR 0x09 | ||
60 | #define UCB_TS_CR_TSMX_POW (1 << 0) | ||
61 | #define UCB_TS_CR_TSPX_POW (1 << 1) | ||
62 | #define UCB_TS_CR_TSMY_POW (1 << 2) | ||
63 | #define UCB_TS_CR_TSPY_POW (1 << 3) | ||
64 | #define UCB_TS_CR_TSMX_GND (1 << 4) | ||
65 | #define UCB_TS_CR_TSPX_GND (1 << 5) | ||
66 | #define UCB_TS_CR_TSMY_GND (1 << 6) | ||
67 | #define UCB_TS_CR_TSPY_GND (1 << 7) | ||
68 | #define UCB_TS_CR_MODE_INT (0 << 8) | ||
69 | #define UCB_TS_CR_MODE_PRES (1 << 8) | ||
70 | #define UCB_TS_CR_MODE_POS (2 << 8) | ||
71 | #define UCB_TS_CR_BIAS_ENA (1 << 11) | ||
72 | #define UCB_TS_CR_TSPX_LOW (1 << 12) | ||
73 | #define UCB_TS_CR_TSMX_LOW (1 << 13) | ||
74 | |||
75 | #define UCB_ADC_CR 0x0a | ||
76 | #define UCB_ADC_SYNC_ENA (1 << 0) | ||
77 | #define UCB_ADC_VREFBYP_CON (1 << 1) | ||
78 | #define UCB_ADC_INP_TSPX (0 << 2) | ||
79 | #define UCB_ADC_INP_TSMX (1 << 2) | ||
80 | #define UCB_ADC_INP_TSPY (2 << 2) | ||
81 | #define UCB_ADC_INP_TSMY (3 << 2) | ||
82 | #define UCB_ADC_INP_AD0 (4 << 2) | ||
83 | #define UCB_ADC_INP_AD1 (5 << 2) | ||
84 | #define UCB_ADC_INP_AD2 (6 << 2) | ||
85 | #define UCB_ADC_INP_AD3 (7 << 2) | ||
86 | #define UCB_ADC_EXT_REF (1 << 5) | ||
87 | #define UCB_ADC_START (1 << 7) | ||
88 | #define UCB_ADC_ENA (1 << 15) | ||
89 | |||
90 | #define UCB_ADC_DATA 0x0b | ||
91 | #define UCB_ADC_DAT_VAL (1 << 15) | ||
92 | #define UCB_ADC_DAT(x) (((x) & 0x7fe0) >> 5) | ||
93 | |||
94 | #define UCB_ID 0x0c | ||
95 | #define UCB_ID_1200 0x1004 | ||
96 | #define UCB_ID_1300 0x1005 | ||
97 | #define UCB_ID_TC35143 0x9712 | ||
98 | |||
99 | #define UCB_MODE 0x0d | ||
100 | #define UCB_MODE_DYN_VFLAG_ENA (1 << 12) | ||
101 | #define UCB_MODE_AUD_OFF_CAN (1 << 13) | ||
102 | |||
103 | #include "mcp.h" | ||
104 | |||
105 | struct ucb1x00_irq { | ||
106 | void *devid; | ||
107 | void (*fn)(int, void *); | ||
108 | }; | ||
109 | |||
110 | struct ucb1x00 { | ||
111 | spinlock_t lock; | ||
112 | struct mcp *mcp; | ||
113 | unsigned int irq; | ||
114 | struct semaphore adc_sem; | ||
115 | spinlock_t io_lock; | ||
116 | u16 id; | ||
117 | u16 io_dir; | ||
118 | u16 io_out; | ||
119 | u16 adc_cr; | ||
120 | u16 irq_fal_enbl; | ||
121 | u16 irq_ris_enbl; | ||
122 | struct ucb1x00_irq irq_handler[16]; | ||
123 | struct device dev; | ||
124 | struct list_head node; | ||
125 | struct list_head devs; | ||
126 | }; | ||
127 | |||
128 | struct ucb1x00_driver; | ||
129 | |||
130 | struct ucb1x00_dev { | ||
131 | struct list_head dev_node; | ||
132 | struct list_head drv_node; | ||
133 | struct ucb1x00 *ucb; | ||
134 | struct ucb1x00_driver *drv; | ||
135 | void *priv; | ||
136 | }; | ||
137 | |||
138 | struct ucb1x00_driver { | ||
139 | struct list_head node; | ||
140 | struct list_head devs; | ||
141 | int (*add)(struct ucb1x00_dev *dev); | ||
142 | void (*remove)(struct ucb1x00_dev *dev); | ||
143 | int (*suspend)(struct ucb1x00_dev *dev, pm_message_t state); | ||
144 | int (*resume)(struct ucb1x00_dev *dev); | ||
145 | }; | ||
146 | |||
147 | #define classdev_to_ucb1x00(cd) container_of(cd, struct ucb1x00, dev) | ||
148 | |||
149 | int ucb1x00_register_driver(struct ucb1x00_driver *); | ||
150 | void ucb1x00_unregister_driver(struct ucb1x00_driver *); | ||
151 | |||
152 | /** | ||
153 | * ucb1x00_clkrate - return the UCB1x00 SIB clock rate | ||
154 | * @ucb: UCB1x00 structure describing chip | ||
155 | * | ||
156 | * Return the SIB clock rate in Hz. | ||
157 | */ | ||
158 | static inline unsigned int ucb1x00_clkrate(struct ucb1x00 *ucb) | ||
159 | { | ||
160 | return mcp_get_sclk_rate(ucb->mcp); | ||
161 | } | ||
162 | |||
163 | /** | ||
164 | * ucb1x00_enable - enable the UCB1x00 SIB clock | ||
165 | * @ucb: UCB1x00 structure describing chip | ||
166 | * | ||
167 | * Enable the SIB clock. This can be called multiple times. | ||
168 | */ | ||
169 | static inline void ucb1x00_enable(struct ucb1x00 *ucb) | ||
170 | { | ||
171 | mcp_enable(ucb->mcp); | ||
172 | } | ||
173 | |||
174 | /** | ||
175 | * ucb1x00_disable - disable the UCB1x00 SIB clock | ||
176 | * @ucb: UCB1x00 structure describing chip | ||
177 | * | ||
178 | * Disable the SIB clock. The SIB clock will only be disabled | ||
179 | * when the number of ucb1x00_enable calls match the number of | ||
180 | * ucb1x00_disable calls. | ||
181 | */ | ||
182 | static inline void ucb1x00_disable(struct ucb1x00 *ucb) | ||
183 | { | ||
184 | mcp_disable(ucb->mcp); | ||
185 | } | ||
186 | |||
187 | /** | ||
188 | * ucb1x00_reg_write - write a UCB1x00 register | ||
189 | * @ucb: UCB1x00 structure describing chip | ||
190 | * @reg: UCB1x00 4-bit register index to write | ||
191 | * @val: UCB1x00 16-bit value to write | ||
192 | * | ||
193 | * Write the UCB1x00 register @reg with value @val. The SIB | ||
194 | * clock must be running for this function to return. | ||
195 | */ | ||
196 | static inline void ucb1x00_reg_write(struct ucb1x00 *ucb, unsigned int reg, unsigned int val) | ||
197 | { | ||
198 | mcp_reg_write(ucb->mcp, reg, val); | ||
199 | } | ||
200 | |||
201 | /** | ||
202 | * ucb1x00_reg_read - read a UCB1x00 register | ||
203 | * @ucb: UCB1x00 structure describing chip | ||
204 | * @reg: UCB1x00 4-bit register index to write | ||
205 | * | ||
206 | * Read the UCB1x00 register @reg and return its value. The SIB | ||
207 | * clock must be running for this function to return. | ||
208 | */ | ||
209 | static inline unsigned int ucb1x00_reg_read(struct ucb1x00 *ucb, unsigned int reg) | ||
210 | { | ||
211 | return mcp_reg_read(ucb->mcp, reg); | ||
212 | } | ||
213 | /** | ||
214 | * ucb1x00_set_audio_divisor - | ||
215 | * @ucb: UCB1x00 structure describing chip | ||
216 | * @div: SIB clock divisor | ||
217 | */ | ||
218 | static inline void ucb1x00_set_audio_divisor(struct ucb1x00 *ucb, unsigned int div) | ||
219 | { | ||
220 | mcp_set_audio_divisor(ucb->mcp, div); | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * ucb1x00_set_telecom_divisor - | ||
225 | * @ucb: UCB1x00 structure describing chip | ||
226 | * @div: SIB clock divisor | ||
227 | */ | ||
228 | static inline void ucb1x00_set_telecom_divisor(struct ucb1x00 *ucb, unsigned int div) | ||
229 | { | ||
230 | mcp_set_telecom_divisor(ucb->mcp, div); | ||
231 | } | ||
232 | |||
233 | void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int, unsigned int); | ||
234 | void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int, unsigned int); | ||
235 | unsigned int ucb1x00_io_read(struct ucb1x00 *ucb); | ||
236 | |||
237 | #define UCB_NOSYNC (0) | ||
238 | #define UCB_SYNC (1) | ||
239 | |||
240 | unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync); | ||
241 | void ucb1x00_adc_enable(struct ucb1x00 *ucb); | ||
242 | void ucb1x00_adc_disable(struct ucb1x00 *ucb); | ||
243 | |||
244 | /* | ||
245 | * Which edges of the IRQ do you want to control today? | ||
246 | */ | ||
247 | #define UCB_RISING (1 << 0) | ||
248 | #define UCB_FALLING (1 << 1) | ||
249 | |||
250 | int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid); | ||
251 | void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges); | ||
252 | void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges); | ||
253 | int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid); | ||
254 | |||
255 | #endif | ||
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 6a35f2a2702c..4b2021af1d96 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c | |||
@@ -29,7 +29,7 @@ | |||
29 | /* Current settings - values are 2*2^(reg_val/4) microamps. These are | 29 | /* Current settings - values are 2*2^(reg_val/4) microamps. These are |
30 | * exported since they are used by multiple drivers. | 30 | * exported since they are used by multiple drivers. |
31 | */ | 31 | */ |
32 | int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL] = { | 32 | int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = { |
33 | 2, | 33 | 2, |
34 | 2, | 34 | 2, |
35 | 3, | 35 | 3, |
@@ -90,9 +90,10 @@ int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL] = { | |||
90 | EXPORT_SYMBOL_GPL(wm831x_isinkv_values); | 90 | EXPORT_SYMBOL_GPL(wm831x_isinkv_values); |
91 | 91 | ||
92 | enum wm831x_parent { | 92 | enum wm831x_parent { |
93 | WM8310 = 0, | 93 | WM8310 = 0x8310, |
94 | WM8311 = 1, | 94 | WM8311 = 0x8311, |
95 | WM8312 = 2, | 95 | WM8312 = 0x8312, |
96 | WM8320 = 0x8320, | ||
96 | }; | 97 | }; |
97 | 98 | ||
98 | static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg) | 99 | static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg) |
@@ -478,6 +479,20 @@ static struct resource wm831x_dcdc4_resources[] = { | |||
478 | }, | 479 | }, |
479 | }; | 480 | }; |
480 | 481 | ||
482 | static struct resource wm8320_dcdc4_buck_resources[] = { | ||
483 | { | ||
484 | .start = WM831X_DC4_CONTROL, | ||
485 | .end = WM832X_DC4_SLEEP_CONTROL, | ||
486 | .flags = IORESOURCE_IO, | ||
487 | }, | ||
488 | { | ||
489 | .name = "UV", | ||
490 | .start = WM831X_IRQ_UV_DC4, | ||
491 | .end = WM831X_IRQ_UV_DC4, | ||
492 | .flags = IORESOURCE_IRQ, | ||
493 | }, | ||
494 | }; | ||
495 | |||
481 | static struct resource wm831x_gpio_resources[] = { | 496 | static struct resource wm831x_gpio_resources[] = { |
482 | { | 497 | { |
483 | .start = WM831X_IRQ_GPIO_1, | 498 | .start = WM831X_IRQ_GPIO_1, |
@@ -1246,6 +1261,137 @@ static struct mfd_cell wm8312_devs[] = { | |||
1246 | }, | 1261 | }, |
1247 | }; | 1262 | }; |
1248 | 1263 | ||
1264 | static struct mfd_cell wm8320_devs[] = { | ||
1265 | { | ||
1266 | .name = "wm831x-backup", | ||
1267 | }, | ||
1268 | { | ||
1269 | .name = "wm831x-buckv", | ||
1270 | .id = 1, | ||
1271 | .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources), | ||
1272 | .resources = wm831x_dcdc1_resources, | ||
1273 | }, | ||
1274 | { | ||
1275 | .name = "wm831x-buckv", | ||
1276 | .id = 2, | ||
1277 | .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources), | ||
1278 | .resources = wm831x_dcdc2_resources, | ||
1279 | }, | ||
1280 | { | ||
1281 | .name = "wm831x-buckp", | ||
1282 | .id = 3, | ||
1283 | .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources), | ||
1284 | .resources = wm831x_dcdc3_resources, | ||
1285 | }, | ||
1286 | { | ||
1287 | .name = "wm831x-buckp", | ||
1288 | .id = 4, | ||
1289 | .num_resources = ARRAY_SIZE(wm8320_dcdc4_buck_resources), | ||
1290 | .resources = wm8320_dcdc4_buck_resources, | ||
1291 | }, | ||
1292 | { | ||
1293 | .name = "wm831x-gpio", | ||
1294 | .num_resources = ARRAY_SIZE(wm831x_gpio_resources), | ||
1295 | .resources = wm831x_gpio_resources, | ||
1296 | }, | ||
1297 | { | ||
1298 | .name = "wm831x-hwmon", | ||
1299 | }, | ||
1300 | { | ||
1301 | .name = "wm831x-ldo", | ||
1302 | .id = 1, | ||
1303 | .num_resources = ARRAY_SIZE(wm831x_ldo1_resources), | ||
1304 | .resources = wm831x_ldo1_resources, | ||
1305 | }, | ||
1306 | { | ||
1307 | .name = "wm831x-ldo", | ||
1308 | .id = 2, | ||
1309 | .num_resources = ARRAY_SIZE(wm831x_ldo2_resources), | ||
1310 | .resources = wm831x_ldo2_resources, | ||
1311 | }, | ||
1312 | { | ||
1313 | .name = "wm831x-ldo", | ||
1314 | .id = 3, | ||
1315 | .num_resources = ARRAY_SIZE(wm831x_ldo3_resources), | ||
1316 | .resources = wm831x_ldo3_resources, | ||
1317 | }, | ||
1318 | { | ||
1319 | .name = "wm831x-ldo", | ||
1320 | .id = 4, | ||
1321 | .num_resources = ARRAY_SIZE(wm831x_ldo4_resources), | ||
1322 | .resources = wm831x_ldo4_resources, | ||
1323 | }, | ||
1324 | { | ||
1325 | .name = "wm831x-ldo", | ||
1326 | .id = 5, | ||
1327 | .num_resources = ARRAY_SIZE(wm831x_ldo5_resources), | ||
1328 | .resources = wm831x_ldo5_resources, | ||
1329 | }, | ||
1330 | { | ||
1331 | .name = "wm831x-ldo", | ||
1332 | .id = 6, | ||
1333 | .num_resources = ARRAY_SIZE(wm831x_ldo6_resources), | ||
1334 | .resources = wm831x_ldo6_resources, | ||
1335 | }, | ||
1336 | { | ||
1337 | .name = "wm831x-aldo", | ||
1338 | .id = 7, | ||
1339 | .num_resources = ARRAY_SIZE(wm831x_ldo7_resources), | ||
1340 | .resources = wm831x_ldo7_resources, | ||
1341 | }, | ||
1342 | { | ||
1343 | .name = "wm831x-aldo", | ||
1344 | .id = 8, | ||
1345 | .num_resources = ARRAY_SIZE(wm831x_ldo8_resources), | ||
1346 | .resources = wm831x_ldo8_resources, | ||
1347 | }, | ||
1348 | { | ||
1349 | .name = "wm831x-aldo", | ||
1350 | .id = 9, | ||
1351 | .num_resources = ARRAY_SIZE(wm831x_ldo9_resources), | ||
1352 | .resources = wm831x_ldo9_resources, | ||
1353 | }, | ||
1354 | { | ||
1355 | .name = "wm831x-aldo", | ||
1356 | .id = 10, | ||
1357 | .num_resources = ARRAY_SIZE(wm831x_ldo10_resources), | ||
1358 | .resources = wm831x_ldo10_resources, | ||
1359 | }, | ||
1360 | { | ||
1361 | .name = "wm831x-alive-ldo", | ||
1362 | .id = 11, | ||
1363 | .num_resources = ARRAY_SIZE(wm831x_ldo11_resources), | ||
1364 | .resources = wm831x_ldo11_resources, | ||
1365 | }, | ||
1366 | { | ||
1367 | .name = "wm831x-on", | ||
1368 | .num_resources = ARRAY_SIZE(wm831x_on_resources), | ||
1369 | .resources = wm831x_on_resources, | ||
1370 | }, | ||
1371 | { | ||
1372 | .name = "wm831x-rtc", | ||
1373 | .num_resources = ARRAY_SIZE(wm831x_rtc_resources), | ||
1374 | .resources = wm831x_rtc_resources, | ||
1375 | }, | ||
1376 | { | ||
1377 | .name = "wm831x-status", | ||
1378 | .id = 1, | ||
1379 | .num_resources = ARRAY_SIZE(wm831x_status1_resources), | ||
1380 | .resources = wm831x_status1_resources, | ||
1381 | }, | ||
1382 | { | ||
1383 | .name = "wm831x-status", | ||
1384 | .id = 2, | ||
1385 | .num_resources = ARRAY_SIZE(wm831x_status2_resources), | ||
1386 | .resources = wm831x_status2_resources, | ||
1387 | }, | ||
1388 | { | ||
1389 | .name = "wm831x-watchdog", | ||
1390 | .num_resources = ARRAY_SIZE(wm831x_wdt_resources), | ||
1391 | .resources = wm831x_wdt_resources, | ||
1392 | }, | ||
1393 | }; | ||
1394 | |||
1249 | static struct mfd_cell backlight_devs[] = { | 1395 | static struct mfd_cell backlight_devs[] = { |
1250 | { | 1396 | { |
1251 | .name = "wm831x-backlight", | 1397 | .name = "wm831x-backlight", |
@@ -1291,50 +1437,37 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
1291 | goto err; | 1437 | goto err; |
1292 | } | 1438 | } |
1293 | 1439 | ||
1440 | /* Some engineering samples do not have the ID set, rely on | ||
1441 | * the device being registered correctly. | ||
1442 | */ | ||
1443 | if (ret == 0) { | ||
1444 | dev_info(wm831x->dev, "Device is an engineering sample\n"); | ||
1445 | ret = id; | ||
1446 | } | ||
1447 | |||
1294 | switch (ret) { | 1448 | switch (ret) { |
1295 | case 0x8310: | 1449 | case WM8310: |
1296 | parent = WM8310; | 1450 | parent = WM8310; |
1297 | switch (rev) { | 1451 | wm831x->num_gpio = 16; |
1298 | case 0: | 1452 | dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev); |
1299 | dev_info(wm831x->dev, "WM8310 revision %c\n", | ||
1300 | 'A' + rev); | ||
1301 | break; | ||
1302 | } | ||
1303 | break; | 1453 | break; |
1304 | 1454 | ||
1305 | case 0x8311: | 1455 | case WM8311: |
1306 | parent = WM8311; | 1456 | parent = WM8311; |
1307 | switch (rev) { | 1457 | wm831x->num_gpio = 16; |
1308 | case 0: | 1458 | dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev); |
1309 | dev_info(wm831x->dev, "WM8311 revision %c\n", | ||
1310 | 'A' + rev); | ||
1311 | break; | ||
1312 | } | ||
1313 | break; | 1459 | break; |
1314 | 1460 | ||
1315 | case 0x8312: | 1461 | case WM8312: |
1316 | parent = WM8312; | 1462 | parent = WM8312; |
1317 | switch (rev) { | 1463 | wm831x->num_gpio = 16; |
1318 | case 0: | 1464 | dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev); |
1319 | dev_info(wm831x->dev, "WM8312 revision %c\n", | ||
1320 | 'A' + rev); | ||
1321 | break; | ||
1322 | } | ||
1323 | break; | 1465 | break; |
1324 | 1466 | ||
1325 | case 0: | 1467 | case WM8320: |
1326 | /* Some engineering samples do not have the ID set, | 1468 | parent = WM8320; |
1327 | * rely on the device being registered correctly. | 1469 | wm831x->num_gpio = 12; |
1328 | * This will need revisiting for future devices with | 1470 | dev_info(wm831x->dev, "WM8320 revision %c\n", 'A' + rev); |
1329 | * multiple dies. | ||
1330 | */ | ||
1331 | parent = id; | ||
1332 | switch (rev) { | ||
1333 | case 0: | ||
1334 | dev_info(wm831x->dev, "WM831%d ES revision %c\n", | ||
1335 | parent, 'A' + rev); | ||
1336 | break; | ||
1337 | } | ||
1338 | break; | 1471 | break; |
1339 | 1472 | ||
1340 | default: | 1473 | default: |
@@ -1347,7 +1480,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
1347 | * current parts. | 1480 | * current parts. |
1348 | */ | 1481 | */ |
1349 | if (parent != id) | 1482 | if (parent != id) |
1350 | dev_warn(wm831x->dev, "Device was registered as a WM831%lu\n", | 1483 | dev_warn(wm831x->dev, "Device was registered as a WM%lx\n", |
1351 | id); | 1484 | id); |
1352 | 1485 | ||
1353 | /* Bootstrap the user key */ | 1486 | /* Bootstrap the user key */ |
@@ -1380,18 +1513,24 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
1380 | case WM8310: | 1513 | case WM8310: |
1381 | ret = mfd_add_devices(wm831x->dev, -1, | 1514 | ret = mfd_add_devices(wm831x->dev, -1, |
1382 | wm8310_devs, ARRAY_SIZE(wm8310_devs), | 1515 | wm8310_devs, ARRAY_SIZE(wm8310_devs), |
1383 | NULL, 0); | 1516 | NULL, wm831x->irq_base); |
1384 | break; | 1517 | break; |
1385 | 1518 | ||
1386 | case WM8311: | 1519 | case WM8311: |
1387 | ret = mfd_add_devices(wm831x->dev, -1, | 1520 | ret = mfd_add_devices(wm831x->dev, -1, |
1388 | wm8311_devs, ARRAY_SIZE(wm8311_devs), | 1521 | wm8311_devs, ARRAY_SIZE(wm8311_devs), |
1389 | NULL, 0); | 1522 | NULL, wm831x->irq_base); |
1390 | break; | 1523 | break; |
1391 | 1524 | ||
1392 | case WM8312: | 1525 | case WM8312: |
1393 | ret = mfd_add_devices(wm831x->dev, -1, | 1526 | ret = mfd_add_devices(wm831x->dev, -1, |
1394 | wm8312_devs, ARRAY_SIZE(wm8312_devs), | 1527 | wm8312_devs, ARRAY_SIZE(wm8312_devs), |
1528 | NULL, wm831x->irq_base); | ||
1529 | break; | ||
1530 | |||
1531 | case WM8320: | ||
1532 | ret = mfd_add_devices(wm831x->dev, -1, | ||
1533 | wm8320_devs, ARRAY_SIZE(wm8320_devs), | ||
1395 | NULL, 0); | 1534 | NULL, 0); |
1396 | break; | 1535 | break; |
1397 | 1536 | ||
@@ -1408,7 +1547,8 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
1408 | if (pdata && pdata->backlight) { | 1547 | if (pdata && pdata->backlight) { |
1409 | /* Treat errors as non-critical */ | 1548 | /* Treat errors as non-critical */ |
1410 | ret = mfd_add_devices(wm831x->dev, -1, backlight_devs, | 1549 | ret = mfd_add_devices(wm831x->dev, -1, backlight_devs, |
1411 | ARRAY_SIZE(backlight_devs), NULL, 0); | 1550 | ARRAY_SIZE(backlight_devs), NULL, |
1551 | wm831x->irq_base); | ||
1412 | if (ret < 0) | 1552 | if (ret < 0) |
1413 | dev_err(wm831x->dev, "Failed to add backlight: %d\n", | 1553 | dev_err(wm831x->dev, "Failed to add backlight: %d\n", |
1414 | ret); | 1554 | ret); |
@@ -1520,6 +1660,7 @@ static const struct i2c_device_id wm831x_i2c_id[] = { | |||
1520 | { "wm8310", WM8310 }, | 1660 | { "wm8310", WM8310 }, |
1521 | { "wm8311", WM8311 }, | 1661 | { "wm8311", WM8311 }, |
1522 | { "wm8312", WM8312 }, | 1662 | { "wm8312", WM8312 }, |
1663 | { "wm8320", WM8320 }, | ||
1523 | { } | 1664 | { } |
1524 | }; | 1665 | }; |
1525 | MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id); | 1666 | MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id); |
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index ac056ea6b66e..301327697117 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <linux/irq.h> | ||
18 | #include <linux/mfd/core.h> | 19 | #include <linux/mfd/core.h> |
19 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
20 | 21 | ||
@@ -339,110 +340,71 @@ static inline int irq_data_to_mask_reg(struct wm831x_irq_data *irq_data) | |||
339 | return WM831X_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg; | 340 | return WM831X_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg; |
340 | } | 341 | } |
341 | 342 | ||
342 | static void __wm831x_enable_irq(struct wm831x *wm831x, int irq) | 343 | static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x, |
344 | int irq) | ||
343 | { | 345 | { |
344 | struct wm831x_irq_data *irq_data = &wm831x_irqs[irq]; | 346 | return &wm831x_irqs[irq - wm831x->irq_base]; |
345 | |||
346 | wm831x->irq_masks[irq_data->reg - 1] &= ~irq_data->mask; | ||
347 | wm831x_reg_write(wm831x, irq_data_to_mask_reg(irq_data), | ||
348 | wm831x->irq_masks[irq_data->reg - 1]); | ||
349 | } | 347 | } |
350 | 348 | ||
351 | void wm831x_enable_irq(struct wm831x *wm831x, int irq) | 349 | static void wm831x_irq_lock(unsigned int irq) |
352 | { | 350 | { |
353 | mutex_lock(&wm831x->irq_lock); | 351 | struct wm831x *wm831x = get_irq_chip_data(irq); |
354 | __wm831x_enable_irq(wm831x, irq); | ||
355 | mutex_unlock(&wm831x->irq_lock); | ||
356 | } | ||
357 | EXPORT_SYMBOL_GPL(wm831x_enable_irq); | ||
358 | 352 | ||
359 | static void __wm831x_disable_irq(struct wm831x *wm831x, int irq) | ||
360 | { | ||
361 | struct wm831x_irq_data *irq_data = &wm831x_irqs[irq]; | ||
362 | |||
363 | wm831x->irq_masks[irq_data->reg - 1] |= irq_data->mask; | ||
364 | wm831x_reg_write(wm831x, irq_data_to_mask_reg(irq_data), | ||
365 | wm831x->irq_masks[irq_data->reg - 1]); | ||
366 | } | ||
367 | |||
368 | void wm831x_disable_irq(struct wm831x *wm831x, int irq) | ||
369 | { | ||
370 | mutex_lock(&wm831x->irq_lock); | 353 | mutex_lock(&wm831x->irq_lock); |
371 | __wm831x_disable_irq(wm831x, irq); | ||
372 | mutex_unlock(&wm831x->irq_lock); | ||
373 | } | 354 | } |
374 | EXPORT_SYMBOL_GPL(wm831x_disable_irq); | ||
375 | 355 | ||
376 | int wm831x_request_irq(struct wm831x *wm831x, | 356 | static void wm831x_irq_sync_unlock(unsigned int irq) |
377 | unsigned int irq, irq_handler_t handler, | ||
378 | unsigned long flags, const char *name, | ||
379 | void *dev) | ||
380 | { | 357 | { |
381 | int ret = 0; | 358 | struct wm831x *wm831x = get_irq_chip_data(irq); |
382 | 359 | int i; | |
383 | if (irq < 0 || irq >= WM831X_NUM_IRQS) | 360 | |
384 | return -EINVAL; | 361 | for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) { |
385 | 362 | /* If there's been a change in the mask write it back | |
386 | mutex_lock(&wm831x->irq_lock); | 363 | * to the hardware. */ |
387 | 364 | if (wm831x->irq_masks_cur[i] != wm831x->irq_masks_cache[i]) { | |
388 | if (wm831x_irqs[irq].handler) { | 365 | wm831x->irq_masks_cache[i] = wm831x->irq_masks_cur[i]; |
389 | dev_err(wm831x->dev, "Already have handler for IRQ %d\n", irq); | 366 | wm831x_reg_write(wm831x, |
390 | ret = -EINVAL; | 367 | WM831X_INTERRUPT_STATUS_1_MASK + i, |
391 | goto out; | 368 | wm831x->irq_masks_cur[i]); |
369 | } | ||
392 | } | 370 | } |
393 | 371 | ||
394 | wm831x_irqs[irq].handler = handler; | ||
395 | wm831x_irqs[irq].handler_data = dev; | ||
396 | |||
397 | __wm831x_enable_irq(wm831x, irq); | ||
398 | |||
399 | out: | ||
400 | mutex_unlock(&wm831x->irq_lock); | 372 | mutex_unlock(&wm831x->irq_lock); |
401 | |||
402 | return ret; | ||
403 | } | 373 | } |
404 | EXPORT_SYMBOL_GPL(wm831x_request_irq); | ||
405 | 374 | ||
406 | void wm831x_free_irq(struct wm831x *wm831x, unsigned int irq, void *data) | 375 | static void wm831x_irq_unmask(unsigned int irq) |
407 | { | 376 | { |
408 | if (irq < 0 || irq >= WM831X_NUM_IRQS) | 377 | struct wm831x *wm831x = get_irq_chip_data(irq); |
409 | return; | 378 | struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq); |
410 | |||
411 | mutex_lock(&wm831x->irq_lock); | ||
412 | 379 | ||
413 | wm831x_irqs[irq].handler = NULL; | 380 | wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; |
414 | wm831x_irqs[irq].handler_data = NULL; | ||
415 | |||
416 | __wm831x_disable_irq(wm831x, irq); | ||
417 | |||
418 | mutex_unlock(&wm831x->irq_lock); | ||
419 | } | 381 | } |
420 | EXPORT_SYMBOL_GPL(wm831x_free_irq); | ||
421 | 382 | ||
422 | 383 | static void wm831x_irq_mask(unsigned int irq) | |
423 | static void wm831x_handle_irq(struct wm831x *wm831x, int irq, int status) | ||
424 | { | 384 | { |
425 | struct wm831x_irq_data *irq_data = &wm831x_irqs[irq]; | 385 | struct wm831x *wm831x = get_irq_chip_data(irq); |
426 | 386 | struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq); | |
427 | if (irq_data->handler) { | 387 | |
428 | irq_data->handler(irq, irq_data->handler_data); | 388 | wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; |
429 | wm831x_reg_write(wm831x, irq_data_to_status_reg(irq_data), | ||
430 | irq_data->mask); | ||
431 | } else { | ||
432 | dev_err(wm831x->dev, "Unhandled IRQ %d, masking\n", irq); | ||
433 | __wm831x_disable_irq(wm831x, irq); | ||
434 | } | ||
435 | } | 389 | } |
436 | 390 | ||
437 | /* Main interrupt handling occurs in a workqueue since we need | 391 | static struct irq_chip wm831x_irq_chip = { |
438 | * interrupts enabled to interact with the chip. */ | 392 | .name = "wm831x", |
439 | static void wm831x_irq_worker(struct work_struct *work) | 393 | .bus_lock = wm831x_irq_lock, |
394 | .bus_sync_unlock = wm831x_irq_sync_unlock, | ||
395 | .mask = wm831x_irq_mask, | ||
396 | .unmask = wm831x_irq_unmask, | ||
397 | }; | ||
398 | |||
399 | /* The processing of the primary interrupt occurs in a thread so that | ||
400 | * we can interact with the device over I2C or SPI. */ | ||
401 | static irqreturn_t wm831x_irq_thread(int irq, void *data) | ||
440 | { | 402 | { |
441 | struct wm831x *wm831x = container_of(work, struct wm831x, irq_work); | 403 | struct wm831x *wm831x = data; |
442 | unsigned int i; | 404 | unsigned int i; |
443 | int primary; | 405 | int primary; |
444 | int status_regs[5]; | 406 | int status_regs[WM831X_NUM_IRQ_REGS] = { 0 }; |
445 | int read[5] = { 0 }; | 407 | int read[WM831X_NUM_IRQ_REGS] = { 0 }; |
446 | int *status; | 408 | int *status; |
447 | 409 | ||
448 | primary = wm831x_reg_read(wm831x, WM831X_SYSTEM_INTERRUPTS); | 410 | primary = wm831x_reg_read(wm831x, WM831X_SYSTEM_INTERRUPTS); |
@@ -452,8 +414,6 @@ static void wm831x_irq_worker(struct work_struct *work) | |||
452 | goto out; | 414 | goto out; |
453 | } | 415 | } |
454 | 416 | ||
455 | mutex_lock(&wm831x->irq_lock); | ||
456 | |||
457 | for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { | 417 | for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { |
458 | int offset = wm831x_irqs[i].reg - 1; | 418 | int offset = wm831x_irqs[i].reg - 1; |
459 | 419 | ||
@@ -471,41 +431,34 @@ static void wm831x_irq_worker(struct work_struct *work) | |||
471 | dev_err(wm831x->dev, | 431 | dev_err(wm831x->dev, |
472 | "Failed to read IRQ status: %d\n", | 432 | "Failed to read IRQ status: %d\n", |
473 | *status); | 433 | *status); |
474 | goto out_lock; | 434 | goto out; |
475 | } | 435 | } |
476 | 436 | ||
477 | /* Mask out the disabled IRQs */ | ||
478 | *status &= ~wm831x->irq_masks[offset]; | ||
479 | read[offset] = 1; | 437 | read[offset] = 1; |
480 | } | 438 | } |
481 | 439 | ||
482 | if (*status & wm831x_irqs[i].mask) | 440 | /* Report it if it isn't masked, or forget the status. */ |
483 | wm831x_handle_irq(wm831x, i, *status); | 441 | if ((*status & ~wm831x->irq_masks_cur[offset]) |
442 | & wm831x_irqs[i].mask) | ||
443 | handle_nested_irq(wm831x->irq_base + i); | ||
444 | else | ||
445 | *status &= ~wm831x_irqs[i].mask; | ||
484 | } | 446 | } |
485 | 447 | ||
486 | out_lock: | ||
487 | mutex_unlock(&wm831x->irq_lock); | ||
488 | out: | 448 | out: |
489 | enable_irq(wm831x->irq); | 449 | for (i = 0; i < ARRAY_SIZE(status_regs); i++) { |
490 | } | 450 | if (status_regs[i]) |
491 | 451 | wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1 + i, | |
492 | 452 | status_regs[i]); | |
493 | static irqreturn_t wm831x_cpu_irq(int irq, void *data) | 453 | } |
494 | { | ||
495 | struct wm831x *wm831x = data; | ||
496 | |||
497 | /* Shut the interrupt to the CPU up and schedule the actual | ||
498 | * handler; we can't check that the IRQ is asserted. */ | ||
499 | disable_irq_nosync(irq); | ||
500 | |||
501 | queue_work(wm831x->irq_wq, &wm831x->irq_work); | ||
502 | 454 | ||
503 | return IRQ_HANDLED; | 455 | return IRQ_HANDLED; |
504 | } | 456 | } |
505 | 457 | ||
506 | int wm831x_irq_init(struct wm831x *wm831x, int irq) | 458 | int wm831x_irq_init(struct wm831x *wm831x, int irq) |
507 | { | 459 | { |
508 | int i, ret; | 460 | struct wm831x_pdata *pdata = wm831x->dev->platform_data; |
461 | int i, cur_irq, ret; | ||
509 | 462 | ||
510 | mutex_init(&wm831x->irq_lock); | 463 | mutex_init(&wm831x->irq_lock); |
511 | 464 | ||
@@ -515,41 +468,53 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) | |||
515 | return 0; | 468 | return 0; |
516 | } | 469 | } |
517 | 470 | ||
518 | 471 | if (!pdata || !pdata->irq_base) { | |
519 | wm831x->irq_wq = create_singlethread_workqueue("wm831x-irq"); | 472 | dev_err(wm831x->dev, |
520 | if (!wm831x->irq_wq) { | 473 | "No interrupt base specified, no interrupts\n"); |
521 | dev_err(wm831x->dev, "Failed to allocate IRQ worker\n"); | 474 | return 0; |
522 | return -ESRCH; | ||
523 | } | 475 | } |
524 | 476 | ||
525 | wm831x->irq = irq; | 477 | wm831x->irq = irq; |
526 | INIT_WORK(&wm831x->irq_work, wm831x_irq_worker); | 478 | wm831x->irq_base = pdata->irq_base; |
527 | 479 | ||
528 | /* Mask the individual interrupt sources */ | 480 | /* Mask the individual interrupt sources */ |
529 | for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks); i++) { | 481 | for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) { |
530 | wm831x->irq_masks[i] = 0xffff; | 482 | wm831x->irq_masks_cur[i] = 0xffff; |
483 | wm831x->irq_masks_cache[i] = 0xffff; | ||
531 | wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1_MASK + i, | 484 | wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1_MASK + i, |
532 | 0xffff); | 485 | 0xffff); |
533 | } | 486 | } |
534 | 487 | ||
535 | /* Enable top level interrupts, we mask at secondary level */ | 488 | /* Register them with genirq */ |
536 | wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0); | 489 | for (cur_irq = wm831x->irq_base; |
490 | cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base; | ||
491 | cur_irq++) { | ||
492 | set_irq_chip_data(cur_irq, wm831x); | ||
493 | set_irq_chip_and_handler(cur_irq, &wm831x_irq_chip, | ||
494 | handle_edge_irq); | ||
495 | set_irq_nested_thread(cur_irq, 1); | ||
496 | |||
497 | /* ARM needs us to explicitly flag the IRQ as valid | ||
498 | * and will set them noprobe when we do so. */ | ||
499 | #ifdef CONFIG_ARM | ||
500 | set_irq_flags(cur_irq, IRQF_VALID); | ||
501 | #else | ||
502 | set_irq_noprobe(cur_irq); | ||
503 | #endif | ||
504 | } | ||
537 | 505 | ||
538 | /* We're good to go. We set IRQF_SHARED since there's a | 506 | ret = request_threaded_irq(irq, NULL, wm831x_irq_thread, |
539 | * chance the driver will interoperate with another driver but | 507 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
540 | * the need to disable the IRQ while handing via I2C/SPI means | 508 | "wm831x", wm831x); |
541 | * that this may break and performance will be impacted. If | ||
542 | * this does happen it's a hardware design issue and the only | ||
543 | * other alternative would be polling. | ||
544 | */ | ||
545 | ret = request_irq(irq, wm831x_cpu_irq, IRQF_TRIGGER_LOW | IRQF_SHARED, | ||
546 | "wm831x", wm831x); | ||
547 | if (ret != 0) { | 509 | if (ret != 0) { |
548 | dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n", | 510 | dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n", |
549 | irq, ret); | 511 | irq, ret); |
550 | return ret; | 512 | return ret; |
551 | } | 513 | } |
552 | 514 | ||
515 | /* Enable top level interrupts, we mask at secondary level */ | ||
516 | wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0); | ||
517 | |||
553 | return 0; | 518 | return 0; |
554 | } | 519 | } |
555 | 520 | ||
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c index ba27c9dc1ad3..8485a7018060 100644 --- a/drivers/mfd/wm8350-core.c +++ b/drivers/mfd/wm8350-core.c | |||
@@ -337,733 +337,6 @@ int wm8350_reg_unlock(struct wm8350 *wm8350) | |||
337 | } | 337 | } |
338 | EXPORT_SYMBOL_GPL(wm8350_reg_unlock); | 338 | EXPORT_SYMBOL_GPL(wm8350_reg_unlock); |
339 | 339 | ||
340 | static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq) | ||
341 | { | ||
342 | mutex_lock(&wm8350->irq_mutex); | ||
343 | |||
344 | if (wm8350->irq[irq].handler) | ||
345 | wm8350->irq[irq].handler(wm8350, irq, wm8350->irq[irq].data); | ||
346 | else { | ||
347 | dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n", | ||
348 | irq); | ||
349 | wm8350_mask_irq(wm8350, irq); | ||
350 | } | ||
351 | |||
352 | mutex_unlock(&wm8350->irq_mutex); | ||
353 | } | ||
354 | |||
355 | /* | ||
356 | * This is a threaded IRQ handler so can access I2C/SPI. Since all | ||
357 | * interrupts are clear on read the IRQ line will be reasserted and | ||
358 | * the physical IRQ will be handled again if another interrupt is | ||
359 | * asserted while we run - in the normal course of events this is a | ||
360 | * rare occurrence so we save I2C/SPI reads. | ||
361 | */ | ||
362 | static irqreturn_t wm8350_irq(int irq, void *data) | ||
363 | { | ||
364 | struct wm8350 *wm8350 = data; | ||
365 | u16 level_one, status1, status2, comp; | ||
366 | |||
367 | /* TODO: Use block reads to improve performance? */ | ||
368 | level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS) | ||
369 | & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK); | ||
370 | status1 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_1) | ||
371 | & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_1_MASK); | ||
372 | status2 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_2) | ||
373 | & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_2_MASK); | ||
374 | comp = wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS) | ||
375 | & ~wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK); | ||
376 | |||
377 | /* over current */ | ||
378 | if (level_one & WM8350_OC_INT) { | ||
379 | u16 oc; | ||
380 | |||
381 | oc = wm8350_reg_read(wm8350, WM8350_OVER_CURRENT_INT_STATUS); | ||
382 | oc &= ~wm8350_reg_read(wm8350, | ||
383 | WM8350_OVER_CURRENT_INT_STATUS_MASK); | ||
384 | |||
385 | if (oc & WM8350_OC_LS_EINT) /* limit switch */ | ||
386 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_OC_LS); | ||
387 | } | ||
388 | |||
389 | /* under voltage */ | ||
390 | if (level_one & WM8350_UV_INT) { | ||
391 | u16 uv; | ||
392 | |||
393 | uv = wm8350_reg_read(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS); | ||
394 | uv &= ~wm8350_reg_read(wm8350, | ||
395 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK); | ||
396 | |||
397 | if (uv & WM8350_UV_DC1_EINT) | ||
398 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC1); | ||
399 | if (uv & WM8350_UV_DC2_EINT) | ||
400 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC2); | ||
401 | if (uv & WM8350_UV_DC3_EINT) | ||
402 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC3); | ||
403 | if (uv & WM8350_UV_DC4_EINT) | ||
404 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC4); | ||
405 | if (uv & WM8350_UV_DC5_EINT) | ||
406 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC5); | ||
407 | if (uv & WM8350_UV_DC6_EINT) | ||
408 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC6); | ||
409 | if (uv & WM8350_UV_LDO1_EINT) | ||
410 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO1); | ||
411 | if (uv & WM8350_UV_LDO2_EINT) | ||
412 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO2); | ||
413 | if (uv & WM8350_UV_LDO3_EINT) | ||
414 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO3); | ||
415 | if (uv & WM8350_UV_LDO4_EINT) | ||
416 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO4); | ||
417 | } | ||
418 | |||
419 | /* charger, RTC */ | ||
420 | if (status1) { | ||
421 | if (status1 & WM8350_CHG_BAT_HOT_EINT) | ||
422 | wm8350_irq_call_handler(wm8350, | ||
423 | WM8350_IRQ_CHG_BAT_HOT); | ||
424 | if (status1 & WM8350_CHG_BAT_COLD_EINT) | ||
425 | wm8350_irq_call_handler(wm8350, | ||
426 | WM8350_IRQ_CHG_BAT_COLD); | ||
427 | if (status1 & WM8350_CHG_BAT_FAIL_EINT) | ||
428 | wm8350_irq_call_handler(wm8350, | ||
429 | WM8350_IRQ_CHG_BAT_FAIL); | ||
430 | if (status1 & WM8350_CHG_TO_EINT) | ||
431 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_TO); | ||
432 | if (status1 & WM8350_CHG_END_EINT) | ||
433 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_END); | ||
434 | if (status1 & WM8350_CHG_START_EINT) | ||
435 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_START); | ||
436 | if (status1 & WM8350_CHG_FAST_RDY_EINT) | ||
437 | wm8350_irq_call_handler(wm8350, | ||
438 | WM8350_IRQ_CHG_FAST_RDY); | ||
439 | if (status1 & WM8350_CHG_VBATT_LT_3P9_EINT) | ||
440 | wm8350_irq_call_handler(wm8350, | ||
441 | WM8350_IRQ_CHG_VBATT_LT_3P9); | ||
442 | if (status1 & WM8350_CHG_VBATT_LT_3P1_EINT) | ||
443 | wm8350_irq_call_handler(wm8350, | ||
444 | WM8350_IRQ_CHG_VBATT_LT_3P1); | ||
445 | if (status1 & WM8350_CHG_VBATT_LT_2P85_EINT) | ||
446 | wm8350_irq_call_handler(wm8350, | ||
447 | WM8350_IRQ_CHG_VBATT_LT_2P85); | ||
448 | if (status1 & WM8350_RTC_ALM_EINT) | ||
449 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_ALM); | ||
450 | if (status1 & WM8350_RTC_SEC_EINT) | ||
451 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_SEC); | ||
452 | if (status1 & WM8350_RTC_PER_EINT) | ||
453 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_PER); | ||
454 | } | ||
455 | |||
456 | /* current sink, system, aux adc */ | ||
457 | if (status2) { | ||
458 | if (status2 & WM8350_CS1_EINT) | ||
459 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS1); | ||
460 | if (status2 & WM8350_CS2_EINT) | ||
461 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS2); | ||
462 | |||
463 | if (status2 & WM8350_SYS_HYST_COMP_FAIL_EINT) | ||
464 | wm8350_irq_call_handler(wm8350, | ||
465 | WM8350_IRQ_SYS_HYST_COMP_FAIL); | ||
466 | if (status2 & WM8350_SYS_CHIP_GT115_EINT) | ||
467 | wm8350_irq_call_handler(wm8350, | ||
468 | WM8350_IRQ_SYS_CHIP_GT115); | ||
469 | if (status2 & WM8350_SYS_CHIP_GT140_EINT) | ||
470 | wm8350_irq_call_handler(wm8350, | ||
471 | WM8350_IRQ_SYS_CHIP_GT140); | ||
472 | if (status2 & WM8350_SYS_WDOG_TO_EINT) | ||
473 | wm8350_irq_call_handler(wm8350, | ||
474 | WM8350_IRQ_SYS_WDOG_TO); | ||
475 | |||
476 | if (status2 & WM8350_AUXADC_DATARDY_EINT) | ||
477 | wm8350_irq_call_handler(wm8350, | ||
478 | WM8350_IRQ_AUXADC_DATARDY); | ||
479 | if (status2 & WM8350_AUXADC_DCOMP4_EINT) | ||
480 | wm8350_irq_call_handler(wm8350, | ||
481 | WM8350_IRQ_AUXADC_DCOMP4); | ||
482 | if (status2 & WM8350_AUXADC_DCOMP3_EINT) | ||
483 | wm8350_irq_call_handler(wm8350, | ||
484 | WM8350_IRQ_AUXADC_DCOMP3); | ||
485 | if (status2 & WM8350_AUXADC_DCOMP2_EINT) | ||
486 | wm8350_irq_call_handler(wm8350, | ||
487 | WM8350_IRQ_AUXADC_DCOMP2); | ||
488 | if (status2 & WM8350_AUXADC_DCOMP1_EINT) | ||
489 | wm8350_irq_call_handler(wm8350, | ||
490 | WM8350_IRQ_AUXADC_DCOMP1); | ||
491 | |||
492 | if (status2 & WM8350_USB_LIMIT_EINT) | ||
493 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_USB_LIMIT); | ||
494 | } | ||
495 | |||
496 | /* wake, codec, ext */ | ||
497 | if (comp) { | ||
498 | if (comp & WM8350_WKUP_OFF_STATE_EINT) | ||
499 | wm8350_irq_call_handler(wm8350, | ||
500 | WM8350_IRQ_WKUP_OFF_STATE); | ||
501 | if (comp & WM8350_WKUP_HIB_STATE_EINT) | ||
502 | wm8350_irq_call_handler(wm8350, | ||
503 | WM8350_IRQ_WKUP_HIB_STATE); | ||
504 | if (comp & WM8350_WKUP_CONV_FAULT_EINT) | ||
505 | wm8350_irq_call_handler(wm8350, | ||
506 | WM8350_IRQ_WKUP_CONV_FAULT); | ||
507 | if (comp & WM8350_WKUP_WDOG_RST_EINT) | ||
508 | wm8350_irq_call_handler(wm8350, | ||
509 | WM8350_IRQ_WKUP_WDOG_RST); | ||
510 | if (comp & WM8350_WKUP_GP_PWR_ON_EINT) | ||
511 | wm8350_irq_call_handler(wm8350, | ||
512 | WM8350_IRQ_WKUP_GP_PWR_ON); | ||
513 | if (comp & WM8350_WKUP_ONKEY_EINT) | ||
514 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_WKUP_ONKEY); | ||
515 | if (comp & WM8350_WKUP_GP_WAKEUP_EINT) | ||
516 | wm8350_irq_call_handler(wm8350, | ||
517 | WM8350_IRQ_WKUP_GP_WAKEUP); | ||
518 | |||
519 | if (comp & WM8350_CODEC_JCK_DET_L_EINT) | ||
520 | wm8350_irq_call_handler(wm8350, | ||
521 | WM8350_IRQ_CODEC_JCK_DET_L); | ||
522 | if (comp & WM8350_CODEC_JCK_DET_R_EINT) | ||
523 | wm8350_irq_call_handler(wm8350, | ||
524 | WM8350_IRQ_CODEC_JCK_DET_R); | ||
525 | if (comp & WM8350_CODEC_MICSCD_EINT) | ||
526 | wm8350_irq_call_handler(wm8350, | ||
527 | WM8350_IRQ_CODEC_MICSCD); | ||
528 | if (comp & WM8350_CODEC_MICD_EINT) | ||
529 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CODEC_MICD); | ||
530 | |||
531 | if (comp & WM8350_EXT_USB_FB_EINT) | ||
532 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_USB_FB); | ||
533 | if (comp & WM8350_EXT_WALL_FB_EINT) | ||
534 | wm8350_irq_call_handler(wm8350, | ||
535 | WM8350_IRQ_EXT_WALL_FB); | ||
536 | if (comp & WM8350_EXT_BAT_FB_EINT) | ||
537 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_BAT_FB); | ||
538 | } | ||
539 | |||
540 | if (level_one & WM8350_GP_INT) { | ||
541 | int i; | ||
542 | u16 gpio; | ||
543 | |||
544 | gpio = wm8350_reg_read(wm8350, WM8350_GPIO_INT_STATUS); | ||
545 | gpio &= ~wm8350_reg_read(wm8350, | ||
546 | WM8350_GPIO_INT_STATUS_MASK); | ||
547 | |||
548 | for (i = 0; i < 12; i++) { | ||
549 | if (gpio & (1 << i)) | ||
550 | wm8350_irq_call_handler(wm8350, | ||
551 | WM8350_IRQ_GPIO(i)); | ||
552 | } | ||
553 | } | ||
554 | |||
555 | return IRQ_HANDLED; | ||
556 | } | ||
557 | |||
558 | int wm8350_register_irq(struct wm8350 *wm8350, int irq, | ||
559 | void (*handler) (struct wm8350 *, int, void *), | ||
560 | void *data) | ||
561 | { | ||
562 | if (irq < 0 || irq > WM8350_NUM_IRQ || !handler) | ||
563 | return -EINVAL; | ||
564 | |||
565 | if (wm8350->irq[irq].handler) | ||
566 | return -EBUSY; | ||
567 | |||
568 | mutex_lock(&wm8350->irq_mutex); | ||
569 | wm8350->irq[irq].handler = handler; | ||
570 | wm8350->irq[irq].data = data; | ||
571 | mutex_unlock(&wm8350->irq_mutex); | ||
572 | |||
573 | return 0; | ||
574 | } | ||
575 | EXPORT_SYMBOL_GPL(wm8350_register_irq); | ||
576 | |||
577 | int wm8350_free_irq(struct wm8350 *wm8350, int irq) | ||
578 | { | ||
579 | if (irq < 0 || irq > WM8350_NUM_IRQ) | ||
580 | return -EINVAL; | ||
581 | |||
582 | mutex_lock(&wm8350->irq_mutex); | ||
583 | wm8350->irq[irq].handler = NULL; | ||
584 | mutex_unlock(&wm8350->irq_mutex); | ||
585 | return 0; | ||
586 | } | ||
587 | EXPORT_SYMBOL_GPL(wm8350_free_irq); | ||
588 | |||
589 | int wm8350_mask_irq(struct wm8350 *wm8350, int irq) | ||
590 | { | ||
591 | switch (irq) { | ||
592 | case WM8350_IRQ_CHG_BAT_HOT: | ||
593 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
594 | WM8350_IM_CHG_BAT_HOT_EINT); | ||
595 | case WM8350_IRQ_CHG_BAT_COLD: | ||
596 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
597 | WM8350_IM_CHG_BAT_COLD_EINT); | ||
598 | case WM8350_IRQ_CHG_BAT_FAIL: | ||
599 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
600 | WM8350_IM_CHG_BAT_FAIL_EINT); | ||
601 | case WM8350_IRQ_CHG_TO: | ||
602 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
603 | WM8350_IM_CHG_TO_EINT); | ||
604 | case WM8350_IRQ_CHG_END: | ||
605 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
606 | WM8350_IM_CHG_END_EINT); | ||
607 | case WM8350_IRQ_CHG_START: | ||
608 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
609 | WM8350_IM_CHG_START_EINT); | ||
610 | case WM8350_IRQ_CHG_FAST_RDY: | ||
611 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
612 | WM8350_IM_CHG_FAST_RDY_EINT); | ||
613 | case WM8350_IRQ_RTC_PER: | ||
614 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
615 | WM8350_IM_RTC_PER_EINT); | ||
616 | case WM8350_IRQ_RTC_SEC: | ||
617 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
618 | WM8350_IM_RTC_SEC_EINT); | ||
619 | case WM8350_IRQ_RTC_ALM: | ||
620 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
621 | WM8350_IM_RTC_ALM_EINT); | ||
622 | case WM8350_IRQ_CHG_VBATT_LT_3P9: | ||
623 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
624 | WM8350_IM_CHG_VBATT_LT_3P9_EINT); | ||
625 | case WM8350_IRQ_CHG_VBATT_LT_3P1: | ||
626 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
627 | WM8350_IM_CHG_VBATT_LT_3P1_EINT); | ||
628 | case WM8350_IRQ_CHG_VBATT_LT_2P85: | ||
629 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
630 | WM8350_IM_CHG_VBATT_LT_2P85_EINT); | ||
631 | case WM8350_IRQ_CS1: | ||
632 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
633 | WM8350_IM_CS1_EINT); | ||
634 | case WM8350_IRQ_CS2: | ||
635 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
636 | WM8350_IM_CS2_EINT); | ||
637 | case WM8350_IRQ_USB_LIMIT: | ||
638 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
639 | WM8350_IM_USB_LIMIT_EINT); | ||
640 | case WM8350_IRQ_AUXADC_DATARDY: | ||
641 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
642 | WM8350_IM_AUXADC_DATARDY_EINT); | ||
643 | case WM8350_IRQ_AUXADC_DCOMP4: | ||
644 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
645 | WM8350_IM_AUXADC_DCOMP4_EINT); | ||
646 | case WM8350_IRQ_AUXADC_DCOMP3: | ||
647 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
648 | WM8350_IM_AUXADC_DCOMP3_EINT); | ||
649 | case WM8350_IRQ_AUXADC_DCOMP2: | ||
650 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
651 | WM8350_IM_AUXADC_DCOMP2_EINT); | ||
652 | case WM8350_IRQ_AUXADC_DCOMP1: | ||
653 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
654 | WM8350_IM_AUXADC_DCOMP1_EINT); | ||
655 | case WM8350_IRQ_SYS_HYST_COMP_FAIL: | ||
656 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
657 | WM8350_IM_SYS_HYST_COMP_FAIL_EINT); | ||
658 | case WM8350_IRQ_SYS_CHIP_GT115: | ||
659 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
660 | WM8350_IM_SYS_CHIP_GT115_EINT); | ||
661 | case WM8350_IRQ_SYS_CHIP_GT140: | ||
662 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
663 | WM8350_IM_SYS_CHIP_GT140_EINT); | ||
664 | case WM8350_IRQ_SYS_WDOG_TO: | ||
665 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
666 | WM8350_IM_SYS_WDOG_TO_EINT); | ||
667 | case WM8350_IRQ_UV_LDO4: | ||
668 | return wm8350_set_bits(wm8350, | ||
669 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
670 | WM8350_IM_UV_LDO4_EINT); | ||
671 | case WM8350_IRQ_UV_LDO3: | ||
672 | return wm8350_set_bits(wm8350, | ||
673 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
674 | WM8350_IM_UV_LDO3_EINT); | ||
675 | case WM8350_IRQ_UV_LDO2: | ||
676 | return wm8350_set_bits(wm8350, | ||
677 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
678 | WM8350_IM_UV_LDO2_EINT); | ||
679 | case WM8350_IRQ_UV_LDO1: | ||
680 | return wm8350_set_bits(wm8350, | ||
681 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
682 | WM8350_IM_UV_LDO1_EINT); | ||
683 | case WM8350_IRQ_UV_DC6: | ||
684 | return wm8350_set_bits(wm8350, | ||
685 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
686 | WM8350_IM_UV_DC6_EINT); | ||
687 | case WM8350_IRQ_UV_DC5: | ||
688 | return wm8350_set_bits(wm8350, | ||
689 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
690 | WM8350_IM_UV_DC5_EINT); | ||
691 | case WM8350_IRQ_UV_DC4: | ||
692 | return wm8350_set_bits(wm8350, | ||
693 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
694 | WM8350_IM_UV_DC4_EINT); | ||
695 | case WM8350_IRQ_UV_DC3: | ||
696 | return wm8350_set_bits(wm8350, | ||
697 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
698 | WM8350_IM_UV_DC3_EINT); | ||
699 | case WM8350_IRQ_UV_DC2: | ||
700 | return wm8350_set_bits(wm8350, | ||
701 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
702 | WM8350_IM_UV_DC2_EINT); | ||
703 | case WM8350_IRQ_UV_DC1: | ||
704 | return wm8350_set_bits(wm8350, | ||
705 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
706 | WM8350_IM_UV_DC1_EINT); | ||
707 | case WM8350_IRQ_OC_LS: | ||
708 | return wm8350_set_bits(wm8350, | ||
709 | WM8350_OVER_CURRENT_INT_STATUS_MASK, | ||
710 | WM8350_IM_OC_LS_EINT); | ||
711 | case WM8350_IRQ_EXT_USB_FB: | ||
712 | return wm8350_set_bits(wm8350, | ||
713 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
714 | WM8350_IM_EXT_USB_FB_EINT); | ||
715 | case WM8350_IRQ_EXT_WALL_FB: | ||
716 | return wm8350_set_bits(wm8350, | ||
717 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
718 | WM8350_IM_EXT_WALL_FB_EINT); | ||
719 | case WM8350_IRQ_EXT_BAT_FB: | ||
720 | return wm8350_set_bits(wm8350, | ||
721 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
722 | WM8350_IM_EXT_BAT_FB_EINT); | ||
723 | case WM8350_IRQ_CODEC_JCK_DET_L: | ||
724 | return wm8350_set_bits(wm8350, | ||
725 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
726 | WM8350_IM_CODEC_JCK_DET_L_EINT); | ||
727 | case WM8350_IRQ_CODEC_JCK_DET_R: | ||
728 | return wm8350_set_bits(wm8350, | ||
729 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
730 | WM8350_IM_CODEC_JCK_DET_R_EINT); | ||
731 | case WM8350_IRQ_CODEC_MICSCD: | ||
732 | return wm8350_set_bits(wm8350, | ||
733 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
734 | WM8350_IM_CODEC_MICSCD_EINT); | ||
735 | case WM8350_IRQ_CODEC_MICD: | ||
736 | return wm8350_set_bits(wm8350, | ||
737 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
738 | WM8350_IM_CODEC_MICD_EINT); | ||
739 | case WM8350_IRQ_WKUP_OFF_STATE: | ||
740 | return wm8350_set_bits(wm8350, | ||
741 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
742 | WM8350_IM_WKUP_OFF_STATE_EINT); | ||
743 | case WM8350_IRQ_WKUP_HIB_STATE: | ||
744 | return wm8350_set_bits(wm8350, | ||
745 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
746 | WM8350_IM_WKUP_HIB_STATE_EINT); | ||
747 | case WM8350_IRQ_WKUP_CONV_FAULT: | ||
748 | return wm8350_set_bits(wm8350, | ||
749 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
750 | WM8350_IM_WKUP_CONV_FAULT_EINT); | ||
751 | case WM8350_IRQ_WKUP_WDOG_RST: | ||
752 | return wm8350_set_bits(wm8350, | ||
753 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
754 | WM8350_IM_WKUP_OFF_STATE_EINT); | ||
755 | case WM8350_IRQ_WKUP_GP_PWR_ON: | ||
756 | return wm8350_set_bits(wm8350, | ||
757 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
758 | WM8350_IM_WKUP_GP_PWR_ON_EINT); | ||
759 | case WM8350_IRQ_WKUP_ONKEY: | ||
760 | return wm8350_set_bits(wm8350, | ||
761 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
762 | WM8350_IM_WKUP_ONKEY_EINT); | ||
763 | case WM8350_IRQ_WKUP_GP_WAKEUP: | ||
764 | return wm8350_set_bits(wm8350, | ||
765 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
766 | WM8350_IM_WKUP_GP_WAKEUP_EINT); | ||
767 | case WM8350_IRQ_GPIO(0): | ||
768 | return wm8350_set_bits(wm8350, | ||
769 | WM8350_GPIO_INT_STATUS_MASK, | ||
770 | WM8350_IM_GP0_EINT); | ||
771 | case WM8350_IRQ_GPIO(1): | ||
772 | return wm8350_set_bits(wm8350, | ||
773 | WM8350_GPIO_INT_STATUS_MASK, | ||
774 | WM8350_IM_GP1_EINT); | ||
775 | case WM8350_IRQ_GPIO(2): | ||
776 | return wm8350_set_bits(wm8350, | ||
777 | WM8350_GPIO_INT_STATUS_MASK, | ||
778 | WM8350_IM_GP2_EINT); | ||
779 | case WM8350_IRQ_GPIO(3): | ||
780 | return wm8350_set_bits(wm8350, | ||
781 | WM8350_GPIO_INT_STATUS_MASK, | ||
782 | WM8350_IM_GP3_EINT); | ||
783 | case WM8350_IRQ_GPIO(4): | ||
784 | return wm8350_set_bits(wm8350, | ||
785 | WM8350_GPIO_INT_STATUS_MASK, | ||
786 | WM8350_IM_GP4_EINT); | ||
787 | case WM8350_IRQ_GPIO(5): | ||
788 | return wm8350_set_bits(wm8350, | ||
789 | WM8350_GPIO_INT_STATUS_MASK, | ||
790 | WM8350_IM_GP5_EINT); | ||
791 | case WM8350_IRQ_GPIO(6): | ||
792 | return wm8350_set_bits(wm8350, | ||
793 | WM8350_GPIO_INT_STATUS_MASK, | ||
794 | WM8350_IM_GP6_EINT); | ||
795 | case WM8350_IRQ_GPIO(7): | ||
796 | return wm8350_set_bits(wm8350, | ||
797 | WM8350_GPIO_INT_STATUS_MASK, | ||
798 | WM8350_IM_GP7_EINT); | ||
799 | case WM8350_IRQ_GPIO(8): | ||
800 | return wm8350_set_bits(wm8350, | ||
801 | WM8350_GPIO_INT_STATUS_MASK, | ||
802 | WM8350_IM_GP8_EINT); | ||
803 | case WM8350_IRQ_GPIO(9): | ||
804 | return wm8350_set_bits(wm8350, | ||
805 | WM8350_GPIO_INT_STATUS_MASK, | ||
806 | WM8350_IM_GP9_EINT); | ||
807 | case WM8350_IRQ_GPIO(10): | ||
808 | return wm8350_set_bits(wm8350, | ||
809 | WM8350_GPIO_INT_STATUS_MASK, | ||
810 | WM8350_IM_GP10_EINT); | ||
811 | case WM8350_IRQ_GPIO(11): | ||
812 | return wm8350_set_bits(wm8350, | ||
813 | WM8350_GPIO_INT_STATUS_MASK, | ||
814 | WM8350_IM_GP11_EINT); | ||
815 | case WM8350_IRQ_GPIO(12): | ||
816 | return wm8350_set_bits(wm8350, | ||
817 | WM8350_GPIO_INT_STATUS_MASK, | ||
818 | WM8350_IM_GP12_EINT); | ||
819 | default: | ||
820 | dev_warn(wm8350->dev, "Attempting to mask unknown IRQ %d\n", | ||
821 | irq); | ||
822 | return -EINVAL; | ||
823 | } | ||
824 | return 0; | ||
825 | } | ||
826 | EXPORT_SYMBOL_GPL(wm8350_mask_irq); | ||
827 | |||
828 | int wm8350_unmask_irq(struct wm8350 *wm8350, int irq) | ||
829 | { | ||
830 | switch (irq) { | ||
831 | case WM8350_IRQ_CHG_BAT_HOT: | ||
832 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
833 | WM8350_IM_CHG_BAT_HOT_EINT); | ||
834 | case WM8350_IRQ_CHG_BAT_COLD: | ||
835 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
836 | WM8350_IM_CHG_BAT_COLD_EINT); | ||
837 | case WM8350_IRQ_CHG_BAT_FAIL: | ||
838 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
839 | WM8350_IM_CHG_BAT_FAIL_EINT); | ||
840 | case WM8350_IRQ_CHG_TO: | ||
841 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
842 | WM8350_IM_CHG_TO_EINT); | ||
843 | case WM8350_IRQ_CHG_END: | ||
844 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
845 | WM8350_IM_CHG_END_EINT); | ||
846 | case WM8350_IRQ_CHG_START: | ||
847 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
848 | WM8350_IM_CHG_START_EINT); | ||
849 | case WM8350_IRQ_CHG_FAST_RDY: | ||
850 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
851 | WM8350_IM_CHG_FAST_RDY_EINT); | ||
852 | case WM8350_IRQ_RTC_PER: | ||
853 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
854 | WM8350_IM_RTC_PER_EINT); | ||
855 | case WM8350_IRQ_RTC_SEC: | ||
856 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
857 | WM8350_IM_RTC_SEC_EINT); | ||
858 | case WM8350_IRQ_RTC_ALM: | ||
859 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
860 | WM8350_IM_RTC_ALM_EINT); | ||
861 | case WM8350_IRQ_CHG_VBATT_LT_3P9: | ||
862 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
863 | WM8350_IM_CHG_VBATT_LT_3P9_EINT); | ||
864 | case WM8350_IRQ_CHG_VBATT_LT_3P1: | ||
865 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
866 | WM8350_IM_CHG_VBATT_LT_3P1_EINT); | ||
867 | case WM8350_IRQ_CHG_VBATT_LT_2P85: | ||
868 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
869 | WM8350_IM_CHG_VBATT_LT_2P85_EINT); | ||
870 | case WM8350_IRQ_CS1: | ||
871 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
872 | WM8350_IM_CS1_EINT); | ||
873 | case WM8350_IRQ_CS2: | ||
874 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
875 | WM8350_IM_CS2_EINT); | ||
876 | case WM8350_IRQ_USB_LIMIT: | ||
877 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
878 | WM8350_IM_USB_LIMIT_EINT); | ||
879 | case WM8350_IRQ_AUXADC_DATARDY: | ||
880 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
881 | WM8350_IM_AUXADC_DATARDY_EINT); | ||
882 | case WM8350_IRQ_AUXADC_DCOMP4: | ||
883 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
884 | WM8350_IM_AUXADC_DCOMP4_EINT); | ||
885 | case WM8350_IRQ_AUXADC_DCOMP3: | ||
886 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
887 | WM8350_IM_AUXADC_DCOMP3_EINT); | ||
888 | case WM8350_IRQ_AUXADC_DCOMP2: | ||
889 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
890 | WM8350_IM_AUXADC_DCOMP2_EINT); | ||
891 | case WM8350_IRQ_AUXADC_DCOMP1: | ||
892 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
893 | WM8350_IM_AUXADC_DCOMP1_EINT); | ||
894 | case WM8350_IRQ_SYS_HYST_COMP_FAIL: | ||
895 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
896 | WM8350_IM_SYS_HYST_COMP_FAIL_EINT); | ||
897 | case WM8350_IRQ_SYS_CHIP_GT115: | ||
898 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
899 | WM8350_IM_SYS_CHIP_GT115_EINT); | ||
900 | case WM8350_IRQ_SYS_CHIP_GT140: | ||
901 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
902 | WM8350_IM_SYS_CHIP_GT140_EINT); | ||
903 | case WM8350_IRQ_SYS_WDOG_TO: | ||
904 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
905 | WM8350_IM_SYS_WDOG_TO_EINT); | ||
906 | case WM8350_IRQ_UV_LDO4: | ||
907 | return wm8350_clear_bits(wm8350, | ||
908 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
909 | WM8350_IM_UV_LDO4_EINT); | ||
910 | case WM8350_IRQ_UV_LDO3: | ||
911 | return wm8350_clear_bits(wm8350, | ||
912 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
913 | WM8350_IM_UV_LDO3_EINT); | ||
914 | case WM8350_IRQ_UV_LDO2: | ||
915 | return wm8350_clear_bits(wm8350, | ||
916 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
917 | WM8350_IM_UV_LDO2_EINT); | ||
918 | case WM8350_IRQ_UV_LDO1: | ||
919 | return wm8350_clear_bits(wm8350, | ||
920 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
921 | WM8350_IM_UV_LDO1_EINT); | ||
922 | case WM8350_IRQ_UV_DC6: | ||
923 | return wm8350_clear_bits(wm8350, | ||
924 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
925 | WM8350_IM_UV_DC6_EINT); | ||
926 | case WM8350_IRQ_UV_DC5: | ||
927 | return wm8350_clear_bits(wm8350, | ||
928 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
929 | WM8350_IM_UV_DC5_EINT); | ||
930 | case WM8350_IRQ_UV_DC4: | ||
931 | return wm8350_clear_bits(wm8350, | ||
932 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
933 | WM8350_IM_UV_DC4_EINT); | ||
934 | case WM8350_IRQ_UV_DC3: | ||
935 | return wm8350_clear_bits(wm8350, | ||
936 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
937 | WM8350_IM_UV_DC3_EINT); | ||
938 | case WM8350_IRQ_UV_DC2: | ||
939 | return wm8350_clear_bits(wm8350, | ||
940 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
941 | WM8350_IM_UV_DC2_EINT); | ||
942 | case WM8350_IRQ_UV_DC1: | ||
943 | return wm8350_clear_bits(wm8350, | ||
944 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
945 | WM8350_IM_UV_DC1_EINT); | ||
946 | case WM8350_IRQ_OC_LS: | ||
947 | return wm8350_clear_bits(wm8350, | ||
948 | WM8350_OVER_CURRENT_INT_STATUS_MASK, | ||
949 | WM8350_IM_OC_LS_EINT); | ||
950 | case WM8350_IRQ_EXT_USB_FB: | ||
951 | return wm8350_clear_bits(wm8350, | ||
952 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
953 | WM8350_IM_EXT_USB_FB_EINT); | ||
954 | case WM8350_IRQ_EXT_WALL_FB: | ||
955 | return wm8350_clear_bits(wm8350, | ||
956 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
957 | WM8350_IM_EXT_WALL_FB_EINT); | ||
958 | case WM8350_IRQ_EXT_BAT_FB: | ||
959 | return wm8350_clear_bits(wm8350, | ||
960 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
961 | WM8350_IM_EXT_BAT_FB_EINT); | ||
962 | case WM8350_IRQ_CODEC_JCK_DET_L: | ||
963 | return wm8350_clear_bits(wm8350, | ||
964 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
965 | WM8350_IM_CODEC_JCK_DET_L_EINT); | ||
966 | case WM8350_IRQ_CODEC_JCK_DET_R: | ||
967 | return wm8350_clear_bits(wm8350, | ||
968 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
969 | WM8350_IM_CODEC_JCK_DET_R_EINT); | ||
970 | case WM8350_IRQ_CODEC_MICSCD: | ||
971 | return wm8350_clear_bits(wm8350, | ||
972 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
973 | WM8350_IM_CODEC_MICSCD_EINT); | ||
974 | case WM8350_IRQ_CODEC_MICD: | ||
975 | return wm8350_clear_bits(wm8350, | ||
976 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
977 | WM8350_IM_CODEC_MICD_EINT); | ||
978 | case WM8350_IRQ_WKUP_OFF_STATE: | ||
979 | return wm8350_clear_bits(wm8350, | ||
980 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
981 | WM8350_IM_WKUP_OFF_STATE_EINT); | ||
982 | case WM8350_IRQ_WKUP_HIB_STATE: | ||
983 | return wm8350_clear_bits(wm8350, | ||
984 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
985 | WM8350_IM_WKUP_HIB_STATE_EINT); | ||
986 | case WM8350_IRQ_WKUP_CONV_FAULT: | ||
987 | return wm8350_clear_bits(wm8350, | ||
988 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
989 | WM8350_IM_WKUP_CONV_FAULT_EINT); | ||
990 | case WM8350_IRQ_WKUP_WDOG_RST: | ||
991 | return wm8350_clear_bits(wm8350, | ||
992 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
993 | WM8350_IM_WKUP_OFF_STATE_EINT); | ||
994 | case WM8350_IRQ_WKUP_GP_PWR_ON: | ||
995 | return wm8350_clear_bits(wm8350, | ||
996 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
997 | WM8350_IM_WKUP_GP_PWR_ON_EINT); | ||
998 | case WM8350_IRQ_WKUP_ONKEY: | ||
999 | return wm8350_clear_bits(wm8350, | ||
1000 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
1001 | WM8350_IM_WKUP_ONKEY_EINT); | ||
1002 | case WM8350_IRQ_WKUP_GP_WAKEUP: | ||
1003 | return wm8350_clear_bits(wm8350, | ||
1004 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
1005 | WM8350_IM_WKUP_GP_WAKEUP_EINT); | ||
1006 | case WM8350_IRQ_GPIO(0): | ||
1007 | return wm8350_clear_bits(wm8350, | ||
1008 | WM8350_GPIO_INT_STATUS_MASK, | ||
1009 | WM8350_IM_GP0_EINT); | ||
1010 | case WM8350_IRQ_GPIO(1): | ||
1011 | return wm8350_clear_bits(wm8350, | ||
1012 | WM8350_GPIO_INT_STATUS_MASK, | ||
1013 | WM8350_IM_GP1_EINT); | ||
1014 | case WM8350_IRQ_GPIO(2): | ||
1015 | return wm8350_clear_bits(wm8350, | ||
1016 | WM8350_GPIO_INT_STATUS_MASK, | ||
1017 | WM8350_IM_GP2_EINT); | ||
1018 | case WM8350_IRQ_GPIO(3): | ||
1019 | return wm8350_clear_bits(wm8350, | ||
1020 | WM8350_GPIO_INT_STATUS_MASK, | ||
1021 | WM8350_IM_GP3_EINT); | ||
1022 | case WM8350_IRQ_GPIO(4): | ||
1023 | return wm8350_clear_bits(wm8350, | ||
1024 | WM8350_GPIO_INT_STATUS_MASK, | ||
1025 | WM8350_IM_GP4_EINT); | ||
1026 | case WM8350_IRQ_GPIO(5): | ||
1027 | return wm8350_clear_bits(wm8350, | ||
1028 | WM8350_GPIO_INT_STATUS_MASK, | ||
1029 | WM8350_IM_GP5_EINT); | ||
1030 | case WM8350_IRQ_GPIO(6): | ||
1031 | return wm8350_clear_bits(wm8350, | ||
1032 | WM8350_GPIO_INT_STATUS_MASK, | ||
1033 | WM8350_IM_GP6_EINT); | ||
1034 | case WM8350_IRQ_GPIO(7): | ||
1035 | return wm8350_clear_bits(wm8350, | ||
1036 | WM8350_GPIO_INT_STATUS_MASK, | ||
1037 | WM8350_IM_GP7_EINT); | ||
1038 | case WM8350_IRQ_GPIO(8): | ||
1039 | return wm8350_clear_bits(wm8350, | ||
1040 | WM8350_GPIO_INT_STATUS_MASK, | ||
1041 | WM8350_IM_GP8_EINT); | ||
1042 | case WM8350_IRQ_GPIO(9): | ||
1043 | return wm8350_clear_bits(wm8350, | ||
1044 | WM8350_GPIO_INT_STATUS_MASK, | ||
1045 | WM8350_IM_GP9_EINT); | ||
1046 | case WM8350_IRQ_GPIO(10): | ||
1047 | return wm8350_clear_bits(wm8350, | ||
1048 | WM8350_GPIO_INT_STATUS_MASK, | ||
1049 | WM8350_IM_GP10_EINT); | ||
1050 | case WM8350_IRQ_GPIO(11): | ||
1051 | return wm8350_clear_bits(wm8350, | ||
1052 | WM8350_GPIO_INT_STATUS_MASK, | ||
1053 | WM8350_IM_GP11_EINT); | ||
1054 | case WM8350_IRQ_GPIO(12): | ||
1055 | return wm8350_clear_bits(wm8350, | ||
1056 | WM8350_GPIO_INT_STATUS_MASK, | ||
1057 | WM8350_IM_GP12_EINT); | ||
1058 | default: | ||
1059 | dev_warn(wm8350->dev, "Attempting to unmask unknown IRQ %d\n", | ||
1060 | irq); | ||
1061 | return -EINVAL; | ||
1062 | } | ||
1063 | return 0; | ||
1064 | } | ||
1065 | EXPORT_SYMBOL_GPL(wm8350_unmask_irq); | ||
1066 | |||
1067 | int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref) | 340 | int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref) |
1068 | { | 341 | { |
1069 | u16 reg, result = 0; | 342 | u16 reg, result = 0; |
@@ -1264,7 +537,7 @@ static void wm8350_client_dev_register(struct wm8350 *wm8350, | |||
1264 | int ret; | 537 | int ret; |
1265 | 538 | ||
1266 | *pdev = platform_device_alloc(name, -1); | 539 | *pdev = platform_device_alloc(name, -1); |
1267 | if (pdev == NULL) { | 540 | if (*pdev == NULL) { |
1268 | dev_err(wm8350->dev, "Failed to allocate %s\n", name); | 541 | dev_err(wm8350->dev, "Failed to allocate %s\n", name); |
1269 | return; | 542 | return; |
1270 | } | 543 | } |
@@ -1409,49 +682,18 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq, | |||
1409 | return ret; | 682 | return ret; |
1410 | } | 683 | } |
1411 | 684 | ||
1412 | wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF); | ||
1413 | wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF); | ||
1414 | wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF); | ||
1415 | wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF); | ||
1416 | wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF); | ||
1417 | wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF); | ||
1418 | |||
1419 | mutex_init(&wm8350->auxadc_mutex); | 685 | mutex_init(&wm8350->auxadc_mutex); |
1420 | mutex_init(&wm8350->irq_mutex); | ||
1421 | if (irq) { | ||
1422 | int flags = IRQF_ONESHOT; | ||
1423 | |||
1424 | if (pdata && pdata->irq_high) { | ||
1425 | flags |= IRQF_TRIGGER_HIGH; | ||
1426 | |||
1427 | wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1, | ||
1428 | WM8350_IRQ_POL); | ||
1429 | } else { | ||
1430 | flags |= IRQF_TRIGGER_LOW; | ||
1431 | |||
1432 | wm8350_clear_bits(wm8350, WM8350_SYSTEM_CONTROL_1, | ||
1433 | WM8350_IRQ_POL); | ||
1434 | } | ||
1435 | 686 | ||
1436 | ret = request_threaded_irq(irq, NULL, wm8350_irq, flags, | 687 | ret = wm8350_irq_init(wm8350, irq, pdata); |
1437 | "wm8350", wm8350); | 688 | if (ret < 0) |
1438 | if (ret != 0) { | ||
1439 | dev_err(wm8350->dev, "Failed to request IRQ: %d\n", | ||
1440 | ret); | ||
1441 | goto err; | ||
1442 | } | ||
1443 | } else { | ||
1444 | dev_err(wm8350->dev, "No IRQ configured\n"); | ||
1445 | goto err; | 689 | goto err; |
1446 | } | ||
1447 | wm8350->chip_irq = irq; | ||
1448 | 690 | ||
1449 | if (pdata && pdata->init) { | 691 | if (pdata && pdata->init) { |
1450 | ret = pdata->init(wm8350); | 692 | ret = pdata->init(wm8350); |
1451 | if (ret != 0) { | 693 | if (ret != 0) { |
1452 | dev_err(wm8350->dev, "Platform init() failed: %d\n", | 694 | dev_err(wm8350->dev, "Platform init() failed: %d\n", |
1453 | ret); | 695 | ret); |
1454 | goto err; | 696 | goto err_irq; |
1455 | } | 697 | } |
1456 | } | 698 | } |
1457 | 699 | ||
@@ -1470,6 +712,8 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq, | |||
1470 | 712 | ||
1471 | return 0; | 713 | return 0; |
1472 | 714 | ||
715 | err_irq: | ||
716 | wm8350_irq_exit(wm8350); | ||
1473 | err: | 717 | err: |
1474 | kfree(wm8350->reg_cache); | 718 | kfree(wm8350->reg_cache); |
1475 | return ret; | 719 | return ret; |
@@ -1493,7 +737,8 @@ void wm8350_device_exit(struct wm8350 *wm8350) | |||
1493 | platform_device_unregister(wm8350->gpio.pdev); | 737 | platform_device_unregister(wm8350->gpio.pdev); |
1494 | platform_device_unregister(wm8350->codec.pdev); | 738 | platform_device_unregister(wm8350->codec.pdev); |
1495 | 739 | ||
1496 | free_irq(wm8350->chip_irq, wm8350); | 740 | wm8350_irq_exit(wm8350); |
741 | |||
1497 | kfree(wm8350->reg_cache); | 742 | kfree(wm8350->reg_cache); |
1498 | } | 743 | } |
1499 | EXPORT_SYMBOL_GPL(wm8350_device_exit); | 744 | EXPORT_SYMBOL_GPL(wm8350_device_exit); |
diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c new file mode 100644 index 000000000000..c8df547c4747 --- /dev/null +++ b/drivers/mfd/wm8350-irq.c | |||
@@ -0,0 +1,529 @@ | |||
1 | /* | ||
2 | * wm8350-irq.c -- IRQ support for Wolfson WM8350 | ||
3 | * | ||
4 | * Copyright 2007, 2008, 2009 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Liam Girdwood, Mark Brown | ||
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/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/bug.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/workqueue.h> | ||
22 | |||
23 | #include <linux/mfd/wm8350/core.h> | ||
24 | #include <linux/mfd/wm8350/audio.h> | ||
25 | #include <linux/mfd/wm8350/comparator.h> | ||
26 | #include <linux/mfd/wm8350/gpio.h> | ||
27 | #include <linux/mfd/wm8350/pmic.h> | ||
28 | #include <linux/mfd/wm8350/rtc.h> | ||
29 | #include <linux/mfd/wm8350/supply.h> | ||
30 | #include <linux/mfd/wm8350/wdt.h> | ||
31 | |||
32 | #define WM8350_NUM_IRQ_REGS 7 | ||
33 | |||
34 | #define WM8350_INT_OFFSET_1 0 | ||
35 | #define WM8350_INT_OFFSET_2 1 | ||
36 | #define WM8350_POWER_UP_INT_OFFSET 2 | ||
37 | #define WM8350_UNDER_VOLTAGE_INT_OFFSET 3 | ||
38 | #define WM8350_OVER_CURRENT_INT_OFFSET 4 | ||
39 | #define WM8350_GPIO_INT_OFFSET 5 | ||
40 | #define WM8350_COMPARATOR_INT_OFFSET 6 | ||
41 | |||
42 | struct wm8350_irq_data { | ||
43 | int primary; | ||
44 | int reg; | ||
45 | int mask; | ||
46 | int primary_only; | ||
47 | }; | ||
48 | |||
49 | static struct wm8350_irq_data wm8350_irqs[] = { | ||
50 | [WM8350_IRQ_OC_LS] = { | ||
51 | .primary = WM8350_OC_INT, | ||
52 | .reg = WM8350_OVER_CURRENT_INT_OFFSET, | ||
53 | .mask = WM8350_OC_LS_EINT, | ||
54 | .primary_only = 1, | ||
55 | }, | ||
56 | [WM8350_IRQ_UV_DC1] = { | ||
57 | .primary = WM8350_UV_INT, | ||
58 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
59 | .mask = WM8350_UV_DC1_EINT, | ||
60 | }, | ||
61 | [WM8350_IRQ_UV_DC2] = { | ||
62 | .primary = WM8350_UV_INT, | ||
63 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
64 | .mask = WM8350_UV_DC2_EINT, | ||
65 | }, | ||
66 | [WM8350_IRQ_UV_DC3] = { | ||
67 | .primary = WM8350_UV_INT, | ||
68 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
69 | .mask = WM8350_UV_DC3_EINT, | ||
70 | }, | ||
71 | [WM8350_IRQ_UV_DC4] = { | ||
72 | .primary = WM8350_UV_INT, | ||
73 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
74 | .mask = WM8350_UV_DC4_EINT, | ||
75 | }, | ||
76 | [WM8350_IRQ_UV_DC5] = { | ||
77 | .primary = WM8350_UV_INT, | ||
78 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
79 | .mask = WM8350_UV_DC5_EINT, | ||
80 | }, | ||
81 | [WM8350_IRQ_UV_DC6] = { | ||
82 | .primary = WM8350_UV_INT, | ||
83 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
84 | .mask = WM8350_UV_DC6_EINT, | ||
85 | }, | ||
86 | [WM8350_IRQ_UV_LDO1] = { | ||
87 | .primary = WM8350_UV_INT, | ||
88 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
89 | .mask = WM8350_UV_LDO1_EINT, | ||
90 | }, | ||
91 | [WM8350_IRQ_UV_LDO2] = { | ||
92 | .primary = WM8350_UV_INT, | ||
93 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
94 | .mask = WM8350_UV_LDO2_EINT, | ||
95 | }, | ||
96 | [WM8350_IRQ_UV_LDO3] = { | ||
97 | .primary = WM8350_UV_INT, | ||
98 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
99 | .mask = WM8350_UV_LDO3_EINT, | ||
100 | }, | ||
101 | [WM8350_IRQ_UV_LDO4] = { | ||
102 | .primary = WM8350_UV_INT, | ||
103 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
104 | .mask = WM8350_UV_LDO4_EINT, | ||
105 | }, | ||
106 | [WM8350_IRQ_CHG_BAT_HOT] = { | ||
107 | .primary = WM8350_CHG_INT, | ||
108 | .reg = WM8350_INT_OFFSET_1, | ||
109 | .mask = WM8350_CHG_BAT_HOT_EINT, | ||
110 | }, | ||
111 | [WM8350_IRQ_CHG_BAT_COLD] = { | ||
112 | .primary = WM8350_CHG_INT, | ||
113 | .reg = WM8350_INT_OFFSET_1, | ||
114 | .mask = WM8350_CHG_BAT_COLD_EINT, | ||
115 | }, | ||
116 | [WM8350_IRQ_CHG_BAT_FAIL] = { | ||
117 | .primary = WM8350_CHG_INT, | ||
118 | .reg = WM8350_INT_OFFSET_1, | ||
119 | .mask = WM8350_CHG_BAT_FAIL_EINT, | ||
120 | }, | ||
121 | [WM8350_IRQ_CHG_TO] = { | ||
122 | .primary = WM8350_CHG_INT, | ||
123 | .reg = WM8350_INT_OFFSET_1, | ||
124 | .mask = WM8350_CHG_TO_EINT, | ||
125 | }, | ||
126 | [WM8350_IRQ_CHG_END] = { | ||
127 | .primary = WM8350_CHG_INT, | ||
128 | .reg = WM8350_INT_OFFSET_1, | ||
129 | .mask = WM8350_CHG_END_EINT, | ||
130 | }, | ||
131 | [WM8350_IRQ_CHG_START] = { | ||
132 | .primary = WM8350_CHG_INT, | ||
133 | .reg = WM8350_INT_OFFSET_1, | ||
134 | .mask = WM8350_CHG_START_EINT, | ||
135 | }, | ||
136 | [WM8350_IRQ_CHG_FAST_RDY] = { | ||
137 | .primary = WM8350_CHG_INT, | ||
138 | .reg = WM8350_INT_OFFSET_1, | ||
139 | .mask = WM8350_CHG_FAST_RDY_EINT, | ||
140 | }, | ||
141 | [WM8350_IRQ_CHG_VBATT_LT_3P9] = { | ||
142 | .primary = WM8350_CHG_INT, | ||
143 | .reg = WM8350_INT_OFFSET_1, | ||
144 | .mask = WM8350_CHG_VBATT_LT_3P9_EINT, | ||
145 | }, | ||
146 | [WM8350_IRQ_CHG_VBATT_LT_3P1] = { | ||
147 | .primary = WM8350_CHG_INT, | ||
148 | .reg = WM8350_INT_OFFSET_1, | ||
149 | .mask = WM8350_CHG_VBATT_LT_3P1_EINT, | ||
150 | }, | ||
151 | [WM8350_IRQ_CHG_VBATT_LT_2P85] = { | ||
152 | .primary = WM8350_CHG_INT, | ||
153 | .reg = WM8350_INT_OFFSET_1, | ||
154 | .mask = WM8350_CHG_VBATT_LT_2P85_EINT, | ||
155 | }, | ||
156 | [WM8350_IRQ_RTC_ALM] = { | ||
157 | .primary = WM8350_RTC_INT, | ||
158 | .reg = WM8350_INT_OFFSET_1, | ||
159 | .mask = WM8350_RTC_ALM_EINT, | ||
160 | }, | ||
161 | [WM8350_IRQ_RTC_SEC] = { | ||
162 | .primary = WM8350_RTC_INT, | ||
163 | .reg = WM8350_INT_OFFSET_1, | ||
164 | .mask = WM8350_RTC_SEC_EINT, | ||
165 | }, | ||
166 | [WM8350_IRQ_RTC_PER] = { | ||
167 | .primary = WM8350_RTC_INT, | ||
168 | .reg = WM8350_INT_OFFSET_1, | ||
169 | .mask = WM8350_RTC_PER_EINT, | ||
170 | }, | ||
171 | [WM8350_IRQ_CS1] = { | ||
172 | .primary = WM8350_CS_INT, | ||
173 | .reg = WM8350_INT_OFFSET_2, | ||
174 | .mask = WM8350_CS1_EINT, | ||
175 | }, | ||
176 | [WM8350_IRQ_CS2] = { | ||
177 | .primary = WM8350_CS_INT, | ||
178 | .reg = WM8350_INT_OFFSET_2, | ||
179 | .mask = WM8350_CS2_EINT, | ||
180 | }, | ||
181 | [WM8350_IRQ_SYS_HYST_COMP_FAIL] = { | ||
182 | .primary = WM8350_SYS_INT, | ||
183 | .reg = WM8350_INT_OFFSET_2, | ||
184 | .mask = WM8350_SYS_HYST_COMP_FAIL_EINT, | ||
185 | }, | ||
186 | [WM8350_IRQ_SYS_CHIP_GT115] = { | ||
187 | .primary = WM8350_SYS_INT, | ||
188 | .reg = WM8350_INT_OFFSET_2, | ||
189 | .mask = WM8350_SYS_CHIP_GT115_EINT, | ||
190 | }, | ||
191 | [WM8350_IRQ_SYS_CHIP_GT140] = { | ||
192 | .primary = WM8350_SYS_INT, | ||
193 | .reg = WM8350_INT_OFFSET_2, | ||
194 | .mask = WM8350_SYS_CHIP_GT140_EINT, | ||
195 | }, | ||
196 | [WM8350_IRQ_SYS_WDOG_TO] = { | ||
197 | .primary = WM8350_SYS_INT, | ||
198 | .reg = WM8350_INT_OFFSET_2, | ||
199 | .mask = WM8350_SYS_WDOG_TO_EINT, | ||
200 | }, | ||
201 | [WM8350_IRQ_AUXADC_DATARDY] = { | ||
202 | .primary = WM8350_AUXADC_INT, | ||
203 | .reg = WM8350_INT_OFFSET_2, | ||
204 | .mask = WM8350_AUXADC_DATARDY_EINT, | ||
205 | }, | ||
206 | [WM8350_IRQ_AUXADC_DCOMP4] = { | ||
207 | .primary = WM8350_AUXADC_INT, | ||
208 | .reg = WM8350_INT_OFFSET_2, | ||
209 | .mask = WM8350_AUXADC_DCOMP4_EINT, | ||
210 | }, | ||
211 | [WM8350_IRQ_AUXADC_DCOMP3] = { | ||
212 | .primary = WM8350_AUXADC_INT, | ||
213 | .reg = WM8350_INT_OFFSET_2, | ||
214 | .mask = WM8350_AUXADC_DCOMP3_EINT, | ||
215 | }, | ||
216 | [WM8350_IRQ_AUXADC_DCOMP2] = { | ||
217 | .primary = WM8350_AUXADC_INT, | ||
218 | .reg = WM8350_INT_OFFSET_2, | ||
219 | .mask = WM8350_AUXADC_DCOMP2_EINT, | ||
220 | }, | ||
221 | [WM8350_IRQ_AUXADC_DCOMP1] = { | ||
222 | .primary = WM8350_AUXADC_INT, | ||
223 | .reg = WM8350_INT_OFFSET_2, | ||
224 | .mask = WM8350_AUXADC_DCOMP1_EINT, | ||
225 | }, | ||
226 | [WM8350_IRQ_USB_LIMIT] = { | ||
227 | .primary = WM8350_USB_INT, | ||
228 | .reg = WM8350_INT_OFFSET_2, | ||
229 | .mask = WM8350_USB_LIMIT_EINT, | ||
230 | .primary_only = 1, | ||
231 | }, | ||
232 | [WM8350_IRQ_WKUP_OFF_STATE] = { | ||
233 | .primary = WM8350_WKUP_INT, | ||
234 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
235 | .mask = WM8350_WKUP_OFF_STATE_EINT, | ||
236 | }, | ||
237 | [WM8350_IRQ_WKUP_HIB_STATE] = { | ||
238 | .primary = WM8350_WKUP_INT, | ||
239 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
240 | .mask = WM8350_WKUP_HIB_STATE_EINT, | ||
241 | }, | ||
242 | [WM8350_IRQ_WKUP_CONV_FAULT] = { | ||
243 | .primary = WM8350_WKUP_INT, | ||
244 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
245 | .mask = WM8350_WKUP_CONV_FAULT_EINT, | ||
246 | }, | ||
247 | [WM8350_IRQ_WKUP_WDOG_RST] = { | ||
248 | .primary = WM8350_WKUP_INT, | ||
249 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
250 | .mask = WM8350_WKUP_WDOG_RST_EINT, | ||
251 | }, | ||
252 | [WM8350_IRQ_WKUP_GP_PWR_ON] = { | ||
253 | .primary = WM8350_WKUP_INT, | ||
254 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
255 | .mask = WM8350_WKUP_GP_PWR_ON_EINT, | ||
256 | }, | ||
257 | [WM8350_IRQ_WKUP_ONKEY] = { | ||
258 | .primary = WM8350_WKUP_INT, | ||
259 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
260 | .mask = WM8350_WKUP_ONKEY_EINT, | ||
261 | }, | ||
262 | [WM8350_IRQ_WKUP_GP_WAKEUP] = { | ||
263 | .primary = WM8350_WKUP_INT, | ||
264 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
265 | .mask = WM8350_WKUP_GP_WAKEUP_EINT, | ||
266 | }, | ||
267 | [WM8350_IRQ_CODEC_JCK_DET_L] = { | ||
268 | .primary = WM8350_CODEC_INT, | ||
269 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
270 | .mask = WM8350_CODEC_JCK_DET_L_EINT, | ||
271 | }, | ||
272 | [WM8350_IRQ_CODEC_JCK_DET_R] = { | ||
273 | .primary = WM8350_CODEC_INT, | ||
274 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
275 | .mask = WM8350_CODEC_JCK_DET_R_EINT, | ||
276 | }, | ||
277 | [WM8350_IRQ_CODEC_MICSCD] = { | ||
278 | .primary = WM8350_CODEC_INT, | ||
279 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
280 | .mask = WM8350_CODEC_MICSCD_EINT, | ||
281 | }, | ||
282 | [WM8350_IRQ_CODEC_MICD] = { | ||
283 | .primary = WM8350_CODEC_INT, | ||
284 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
285 | .mask = WM8350_CODEC_MICD_EINT, | ||
286 | }, | ||
287 | [WM8350_IRQ_EXT_USB_FB] = { | ||
288 | .primary = WM8350_EXT_INT, | ||
289 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
290 | .mask = WM8350_EXT_USB_FB_EINT, | ||
291 | }, | ||
292 | [WM8350_IRQ_EXT_WALL_FB] = { | ||
293 | .primary = WM8350_EXT_INT, | ||
294 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
295 | .mask = WM8350_EXT_WALL_FB_EINT, | ||
296 | }, | ||
297 | [WM8350_IRQ_EXT_BAT_FB] = { | ||
298 | .primary = WM8350_EXT_INT, | ||
299 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
300 | .mask = WM8350_EXT_BAT_FB_EINT, | ||
301 | }, | ||
302 | [WM8350_IRQ_GPIO(0)] = { | ||
303 | .primary = WM8350_GP_INT, | ||
304 | .reg = WM8350_GPIO_INT_OFFSET, | ||
305 | .mask = WM8350_GP0_EINT, | ||
306 | }, | ||
307 | [WM8350_IRQ_GPIO(1)] = { | ||
308 | .primary = WM8350_GP_INT, | ||
309 | .reg = WM8350_GPIO_INT_OFFSET, | ||
310 | .mask = WM8350_GP1_EINT, | ||
311 | }, | ||
312 | [WM8350_IRQ_GPIO(2)] = { | ||
313 | .primary = WM8350_GP_INT, | ||
314 | .reg = WM8350_GPIO_INT_OFFSET, | ||
315 | .mask = WM8350_GP2_EINT, | ||
316 | }, | ||
317 | [WM8350_IRQ_GPIO(3)] = { | ||
318 | .primary = WM8350_GP_INT, | ||
319 | .reg = WM8350_GPIO_INT_OFFSET, | ||
320 | .mask = WM8350_GP3_EINT, | ||
321 | }, | ||
322 | [WM8350_IRQ_GPIO(4)] = { | ||
323 | .primary = WM8350_GP_INT, | ||
324 | .reg = WM8350_GPIO_INT_OFFSET, | ||
325 | .mask = WM8350_GP4_EINT, | ||
326 | }, | ||
327 | [WM8350_IRQ_GPIO(5)] = { | ||
328 | .primary = WM8350_GP_INT, | ||
329 | .reg = WM8350_GPIO_INT_OFFSET, | ||
330 | .mask = WM8350_GP5_EINT, | ||
331 | }, | ||
332 | [WM8350_IRQ_GPIO(6)] = { | ||
333 | .primary = WM8350_GP_INT, | ||
334 | .reg = WM8350_GPIO_INT_OFFSET, | ||
335 | .mask = WM8350_GP6_EINT, | ||
336 | }, | ||
337 | [WM8350_IRQ_GPIO(7)] = { | ||
338 | .primary = WM8350_GP_INT, | ||
339 | .reg = WM8350_GPIO_INT_OFFSET, | ||
340 | .mask = WM8350_GP7_EINT, | ||
341 | }, | ||
342 | [WM8350_IRQ_GPIO(8)] = { | ||
343 | .primary = WM8350_GP_INT, | ||
344 | .reg = WM8350_GPIO_INT_OFFSET, | ||
345 | .mask = WM8350_GP8_EINT, | ||
346 | }, | ||
347 | [WM8350_IRQ_GPIO(9)] = { | ||
348 | .primary = WM8350_GP_INT, | ||
349 | .reg = WM8350_GPIO_INT_OFFSET, | ||
350 | .mask = WM8350_GP9_EINT, | ||
351 | }, | ||
352 | [WM8350_IRQ_GPIO(10)] = { | ||
353 | .primary = WM8350_GP_INT, | ||
354 | .reg = WM8350_GPIO_INT_OFFSET, | ||
355 | .mask = WM8350_GP10_EINT, | ||
356 | }, | ||
357 | [WM8350_IRQ_GPIO(11)] = { | ||
358 | .primary = WM8350_GP_INT, | ||
359 | .reg = WM8350_GPIO_INT_OFFSET, | ||
360 | .mask = WM8350_GP11_EINT, | ||
361 | }, | ||
362 | [WM8350_IRQ_GPIO(12)] = { | ||
363 | .primary = WM8350_GP_INT, | ||
364 | .reg = WM8350_GPIO_INT_OFFSET, | ||
365 | .mask = WM8350_GP12_EINT, | ||
366 | }, | ||
367 | }; | ||
368 | |||
369 | static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq) | ||
370 | { | ||
371 | mutex_lock(&wm8350->irq_mutex); | ||
372 | |||
373 | if (wm8350->irq[irq].handler) | ||
374 | wm8350->irq[irq].handler(irq, wm8350->irq[irq].data); | ||
375 | else { | ||
376 | dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n", | ||
377 | irq); | ||
378 | wm8350_mask_irq(wm8350, irq); | ||
379 | } | ||
380 | |||
381 | mutex_unlock(&wm8350->irq_mutex); | ||
382 | } | ||
383 | |||
384 | /* | ||
385 | * This is a threaded IRQ handler so can access I2C/SPI. Since all | ||
386 | * interrupts are clear on read the IRQ line will be reasserted and | ||
387 | * the physical IRQ will be handled again if another interrupt is | ||
388 | * asserted while we run - in the normal course of events this is a | ||
389 | * rare occurrence so we save I2C/SPI reads. | ||
390 | */ | ||
391 | static irqreturn_t wm8350_irq(int irq, void *irq_data) | ||
392 | { | ||
393 | struct wm8350 *wm8350 = irq_data; | ||
394 | u16 level_one; | ||
395 | u16 sub_reg[WM8350_NUM_IRQ_REGS]; | ||
396 | int read_done[WM8350_NUM_IRQ_REGS]; | ||
397 | struct wm8350_irq_data *data; | ||
398 | int i; | ||
399 | |||
400 | /* TODO: Use block reads to improve performance? */ | ||
401 | level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS) | ||
402 | & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK); | ||
403 | |||
404 | if (!level_one) | ||
405 | return IRQ_NONE; | ||
406 | |||
407 | memset(&read_done, 0, sizeof(read_done)); | ||
408 | |||
409 | for (i = 0; i < ARRAY_SIZE(wm8350_irqs); i++) { | ||
410 | data = &wm8350_irqs[i]; | ||
411 | |||
412 | if (!(level_one & data->primary)) | ||
413 | continue; | ||
414 | |||
415 | if (!read_done[data->reg]) { | ||
416 | sub_reg[data->reg] = | ||
417 | wm8350_reg_read(wm8350, WM8350_INT_STATUS_1 + | ||
418 | data->reg); | ||
419 | sub_reg[data->reg] &= | ||
420 | ~wm8350_reg_read(wm8350, | ||
421 | WM8350_INT_STATUS_1_MASK + | ||
422 | data->reg); | ||
423 | read_done[data->reg] = 1; | ||
424 | } | ||
425 | |||
426 | if (sub_reg[data->reg] & data->mask) | ||
427 | wm8350_irq_call_handler(wm8350, i); | ||
428 | } | ||
429 | |||
430 | return IRQ_HANDLED; | ||
431 | } | ||
432 | |||
433 | int wm8350_register_irq(struct wm8350 *wm8350, int irq, | ||
434 | irq_handler_t handler, unsigned long flags, | ||
435 | const char *name, void *data) | ||
436 | { | ||
437 | if (irq < 0 || irq > WM8350_NUM_IRQ || !handler) | ||
438 | return -EINVAL; | ||
439 | |||
440 | if (wm8350->irq[irq].handler) | ||
441 | return -EBUSY; | ||
442 | |||
443 | mutex_lock(&wm8350->irq_mutex); | ||
444 | wm8350->irq[irq].handler = handler; | ||
445 | wm8350->irq[irq].data = data; | ||
446 | mutex_unlock(&wm8350->irq_mutex); | ||
447 | |||
448 | wm8350_unmask_irq(wm8350, irq); | ||
449 | |||
450 | return 0; | ||
451 | } | ||
452 | EXPORT_SYMBOL_GPL(wm8350_register_irq); | ||
453 | |||
454 | int wm8350_free_irq(struct wm8350 *wm8350, int irq) | ||
455 | { | ||
456 | if (irq < 0 || irq > WM8350_NUM_IRQ) | ||
457 | return -EINVAL; | ||
458 | |||
459 | wm8350_mask_irq(wm8350, irq); | ||
460 | |||
461 | mutex_lock(&wm8350->irq_mutex); | ||
462 | wm8350->irq[irq].handler = NULL; | ||
463 | mutex_unlock(&wm8350->irq_mutex); | ||
464 | return 0; | ||
465 | } | ||
466 | EXPORT_SYMBOL_GPL(wm8350_free_irq); | ||
467 | |||
468 | int wm8350_mask_irq(struct wm8350 *wm8350, int irq) | ||
469 | { | ||
470 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK + | ||
471 | wm8350_irqs[irq].reg, | ||
472 | wm8350_irqs[irq].mask); | ||
473 | } | ||
474 | EXPORT_SYMBOL_GPL(wm8350_mask_irq); | ||
475 | |||
476 | int wm8350_unmask_irq(struct wm8350 *wm8350, int irq) | ||
477 | { | ||
478 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK + | ||
479 | wm8350_irqs[irq].reg, | ||
480 | wm8350_irqs[irq].mask); | ||
481 | } | ||
482 | EXPORT_SYMBOL_GPL(wm8350_unmask_irq); | ||
483 | |||
484 | int wm8350_irq_init(struct wm8350 *wm8350, int irq, | ||
485 | struct wm8350_platform_data *pdata) | ||
486 | { | ||
487 | int ret; | ||
488 | int flags = IRQF_ONESHOT; | ||
489 | |||
490 | if (!irq) { | ||
491 | dev_err(wm8350->dev, "No IRQ configured\n"); | ||
492 | return -EINVAL; | ||
493 | } | ||
494 | |||
495 | wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF); | ||
496 | wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF); | ||
497 | wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF); | ||
498 | wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF); | ||
499 | wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF); | ||
500 | wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF); | ||
501 | |||
502 | mutex_init(&wm8350->irq_mutex); | ||
503 | wm8350->chip_irq = irq; | ||
504 | |||
505 | if (pdata && pdata->irq_high) { | ||
506 | flags |= IRQF_TRIGGER_HIGH; | ||
507 | |||
508 | wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1, | ||
509 | WM8350_IRQ_POL); | ||
510 | } else { | ||
511 | flags |= IRQF_TRIGGER_LOW; | ||
512 | |||
513 | wm8350_clear_bits(wm8350, WM8350_SYSTEM_CONTROL_1, | ||
514 | WM8350_IRQ_POL); | ||
515 | } | ||
516 | |||
517 | ret = request_threaded_irq(irq, NULL, wm8350_irq, flags, | ||
518 | "wm8350", wm8350); | ||
519 | if (ret != 0) | ||
520 | dev_err(wm8350->dev, "Failed to request IRQ: %d\n", ret); | ||
521 | |||
522 | return ret; | ||
523 | } | ||
524 | |||
525 | int wm8350_irq_exit(struct wm8350 *wm8350) | ||
526 | { | ||
527 | free_irq(wm8350->chip_irq, wm8350); | ||
528 | return 0; | ||
529 | } | ||
diff --git a/drivers/mfd/wm8350-regmap.c b/drivers/mfd/wm8350-regmap.c index 7ccc1eab98ab..e965139e5cd5 100644 --- a/drivers/mfd/wm8350-regmap.c +++ b/drivers/mfd/wm8350-regmap.c | |||
@@ -3170,14 +3170,6 @@ const u16 wm8352_mode3_defaults[] = { | |||
3170 | }; | 3170 | }; |
3171 | #endif | 3171 | #endif |
3172 | 3172 | ||
3173 | /* The register defaults for the config mode used must be compiled in but | ||
3174 | * due to the impact on kernel size it is possible to disable | ||
3175 | */ | ||
3176 | #ifndef WM8350_HAVE_CONFIG_MODE | ||
3177 | #warning No WM8350 config modes supported - select at least one of the | ||
3178 | #warning MFD_WM8350_CONFIG_MODE_n options from the board driver. | ||
3179 | #endif | ||
3180 | |||
3181 | /* | 3173 | /* |
3182 | * Access masks. | 3174 | * Access masks. |
3183 | */ | 3175 | */ |