diff options
Diffstat (limited to 'drivers/mfd')
54 files changed, 5608 insertions, 1263 deletions
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 893fc1ba6ead..31ca55548ef9 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c | |||
@@ -1144,17 +1144,15 @@ static int pm860x_probe(struct i2c_client *client, | |||
1144 | return -ENOMEM; | 1144 | return -ENOMEM; |
1145 | ret = pm860x_dt_init(node, &client->dev, pdata); | 1145 | ret = pm860x_dt_init(node, &client->dev, pdata); |
1146 | if (ret) | 1146 | if (ret) |
1147 | goto err; | 1147 | return ret; |
1148 | } else if (!pdata) { | 1148 | } else if (!pdata) { |
1149 | pr_info("No platform data in %s!\n", __func__); | 1149 | pr_info("No platform data in %s!\n", __func__); |
1150 | return -EINVAL; | 1150 | return -EINVAL; |
1151 | } | 1151 | } |
1152 | 1152 | ||
1153 | chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); | 1153 | chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); |
1154 | if (chip == NULL) { | 1154 | if (chip == NULL) |
1155 | ret = -ENOMEM; | 1155 | return -ENOMEM; |
1156 | goto err; | ||
1157 | } | ||
1158 | 1156 | ||
1159 | chip->id = verify_addr(client); | 1157 | chip->id = verify_addr(client); |
1160 | chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); | 1158 | chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); |
@@ -1194,10 +1192,6 @@ static int pm860x_probe(struct i2c_client *client, | |||
1194 | 1192 | ||
1195 | pm860x_device_init(chip, pdata); | 1193 | pm860x_device_init(chip, pdata); |
1196 | return 0; | 1194 | return 0; |
1197 | err: | ||
1198 | if (node) | ||
1199 | devm_kfree(&client->dev, pdata); | ||
1200 | return ret; | ||
1201 | } | 1195 | } |
1202 | 1196 | ||
1203 | static int pm860x_remove(struct i2c_client *client) | 1197 | static int pm860x_remove(struct i2c_client *client) |
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ca86581d02ce..d9aed1593e5d 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -10,19 +10,240 @@ config MFD_CORE | |||
10 | select IRQ_DOMAIN | 10 | select IRQ_DOMAIN |
11 | default n | 11 | default n |
12 | 12 | ||
13 | config MFD_88PM860X | 13 | config MFD_CS5535 |
14 | bool "Support Marvell 88PM8606/88PM8607" | 14 | tristate "AMD CS5535 and CS5536 southbridge core functions" |
15 | select MFD_CORE | ||
16 | depends on PCI && X86 | ||
17 | ---help--- | ||
18 | This is the core driver for CS5535/CS5536 MFD functions. This is | ||
19 | necessary for using the board's GPIO and MFGPT functionality. | ||
20 | |||
21 | config MFD_AS3711 | ||
22 | bool "AMS AS3711" | ||
23 | select MFD_CORE | ||
24 | select REGMAP_I2C | ||
25 | select REGMAP_IRQ | ||
15 | depends on I2C=y && GENERIC_HARDIRQS | 26 | depends on I2C=y && GENERIC_HARDIRQS |
27 | help | ||
28 | Support for the AS3711 PMIC from AMS | ||
29 | |||
30 | config PMIC_ADP5520 | ||
31 | bool "Analog Devices ADP5520/01 MFD PMIC Core Support" | ||
32 | depends on I2C=y | ||
33 | help | ||
34 | Say yes here to add support for Analog Devices AD5520 and ADP5501, | ||
35 | Multifunction Power Management IC. This includes | ||
36 | the I2C driver and the core APIs _only_, you have to select | ||
37 | individual components like LCD backlight, LEDs, GPIOs and Kepad | ||
38 | under the corresponding menus. | ||
39 | |||
40 | config MFD_AAT2870_CORE | ||
41 | bool "AnalogicTech AAT2870" | ||
42 | select MFD_CORE | ||
43 | depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS | ||
44 | help | ||
45 | If you say yes here you get support for the AAT2870. | ||
46 | This driver provides common support for accessing the device, | ||
47 | additional drivers must be enabled in order to use the | ||
48 | functionality of the device. | ||
49 | |||
50 | config MFD_CROS_EC | ||
51 | tristate "ChromeOS Embedded Controller" | ||
52 | select MFD_CORE | ||
53 | help | ||
54 | If you say Y here you get support for the ChromeOS Embedded | ||
55 | Controller (EC) providing keyboard, battery and power services. | ||
56 | You also ned to enable the driver for the bus you are using. The | ||
57 | protocol for talking to the EC is defined by the bus driver. | ||
58 | |||
59 | config MFD_CROS_EC_I2C | ||
60 | tristate "ChromeOS Embedded Controller (I2C)" | ||
61 | depends on MFD_CROS_EC && I2C | ||
62 | |||
63 | help | ||
64 | If you say Y here, you get support for talking to the ChromeOS | ||
65 | EC through an I2C bus. This uses a simple byte-level protocol with | ||
66 | a checksum. Failing accesses will be retried three times to | ||
67 | improve reliability. | ||
68 | |||
69 | config MFD_CROS_EC_SPI | ||
70 | tristate "ChromeOS Embedded Controller (SPI)" | ||
71 | depends on MFD_CROS_EC && SPI | ||
72 | |||
73 | ---help--- | ||
74 | If you say Y here, you get support for talking to the ChromeOS EC | ||
75 | through a SPI bus, using a byte-level protocol. Since the EC's | ||
76 | response time cannot be guaranteed, we support ignoring | ||
77 | 'pre-amble' bytes before the response actually starts. | ||
78 | |||
79 | config MFD_ASIC3 | ||
80 | bool "Compaq ASIC3" | ||
81 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM | ||
82 | select MFD_CORE | ||
83 | ---help--- | ||
84 | This driver supports the ASIC3 multifunction chip found on many | ||
85 | PDAs (mainly iPAQ and HTC based ones) | ||
86 | |||
87 | config PMIC_DA903X | ||
88 | bool "Dialog Semiconductor DA9030/DA9034 PMIC Support" | ||
89 | depends on I2C=y | ||
90 | help | ||
91 | Say yes here to support for Dialog Semiconductor DA9030 (a.k.a | ||
92 | ARAVA) and DA9034 (a.k.a MICCO), these are Power Management IC | ||
93 | usually found on PXA processors-based platforms. This includes | ||
94 | the I2C driver and the core APIs _only_, you have to select | ||
95 | individual components like LCD backlight, voltage regulators, | ||
96 | LEDs and battery-charger under the corresponding menus. | ||
97 | |||
98 | config PMIC_DA9052 | ||
99 | bool | ||
100 | select MFD_CORE | ||
101 | |||
102 | config MFD_DA9052_SPI | ||
103 | bool "Dialog Semiconductor DA9052/53 PMIC variants with SPI" | ||
104 | select REGMAP_SPI | ||
105 | select REGMAP_IRQ | ||
106 | select PMIC_DA9052 | ||
107 | depends on SPI_MASTER=y && GENERIC_HARDIRQS | ||
108 | help | ||
109 | Support for the Dialog Semiconductor DA9052 PMIC | ||
110 | when controlled using SPI. This driver provides common support | ||
111 | for accessing the device, additional drivers must be enabled in | ||
112 | order to use the functionality of the device. | ||
113 | |||
114 | config MFD_DA9052_I2C | ||
115 | bool "Dialog Semiconductor DA9052/53 PMIC variants with I2C" | ||
16 | select REGMAP_I2C | 116 | select REGMAP_I2C |
117 | select REGMAP_IRQ | ||
118 | select PMIC_DA9052 | ||
119 | depends on I2C=y && GENERIC_HARDIRQS | ||
120 | help | ||
121 | Support for the Dialog Semiconductor DA9052 PMIC | ||
122 | when controlled using I2C. This driver provides common support | ||
123 | for accessing the device, additional drivers must be enabled in | ||
124 | order to use the functionality of the device. | ||
125 | |||
126 | config MFD_DA9055 | ||
127 | bool "Dialog Semiconductor DA9055 PMIC Support" | ||
128 | select REGMAP_I2C | ||
129 | select REGMAP_IRQ | ||
17 | select MFD_CORE | 130 | select MFD_CORE |
131 | depends on I2C=y && GENERIC_HARDIRQS | ||
18 | help | 132 | help |
19 | This supports for Marvell 88PM8606/88PM8607 Power Management IC. | 133 | Say yes here for support of Dialog Semiconductor DA9055. This is |
20 | This includes the I2C driver and the core APIs _only_, you have to | 134 | a Power Management IC. This driver provides common support for |
21 | select individual components like voltage regulators, RTC and | 135 | accessing the device as well as the I2C interface to the chip itself. |
22 | battery-charger under the corresponding menus. | 136 | Additional drivers must be enabled in order to use the functionality |
137 | of the device. | ||
138 | |||
139 | This driver can be built as a module. If built as a module it will be | ||
140 | called "da9055" | ||
141 | |||
142 | config MFD_MC13783 | ||
143 | tristate | ||
144 | |||
145 | config MFD_MC13XXX | ||
146 | tristate | ||
147 | depends on (SPI_MASTER || I2C) && GENERIC_HARDIRQS | ||
148 | select MFD_CORE | ||
149 | select MFD_MC13783 | ||
150 | help | ||
151 | Enable support for the Freescale MC13783 and MC13892 PMICs. | ||
152 | This driver provides common support for accessing the device, | ||
153 | additional drivers must be enabled in order to use the | ||
154 | functionality of the device. | ||
155 | |||
156 | config MFD_MC13XXX_SPI | ||
157 | tristate "Freescale MC13783 and MC13892 SPI interface" | ||
158 | depends on SPI_MASTER && GENERIC_HARDIRQS | ||
159 | select REGMAP_SPI | ||
160 | select MFD_MC13XXX | ||
161 | help | ||
162 | Select this if your MC13xxx is connected via an SPI bus. | ||
163 | |||
164 | config MFD_MC13XXX_I2C | ||
165 | tristate "Freescale MC13892 I2C interface" | ||
166 | depends on I2C && GENERIC_HARDIRQS | ||
167 | select REGMAP_I2C | ||
168 | select MFD_MC13XXX | ||
169 | help | ||
170 | Select this if your MC13xxx is connected via an I2C bus. | ||
171 | |||
172 | config HTC_EGPIO | ||
173 | bool "HTC EGPIO support" | ||
174 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM | ||
175 | help | ||
176 | This driver supports the CPLD egpio chip present on | ||
177 | several HTC phones. It provides basic support for input | ||
178 | pins, output pins, and irqs. | ||
179 | |||
180 | config HTC_PASIC3 | ||
181 | tristate "HTC PASIC3 LED/DS1WM chip support" | ||
182 | select MFD_CORE | ||
183 | depends on GENERIC_HARDIRQS | ||
184 | help | ||
185 | This core driver provides register access for the LED/DS1WM | ||
186 | chips labeled "AIC2" and "AIC3", found on HTC Blueangel and | ||
187 | HTC Magician devices, respectively. Actual functionality is | ||
188 | handled by the leds-pasic3 and ds1wm drivers. | ||
189 | |||
190 | config HTC_I2CPLD | ||
191 | bool "HTC I2C PLD chip support" | ||
192 | depends on I2C=y && GPIOLIB | ||
193 | help | ||
194 | If you say yes here you get support for the supposed CPLD | ||
195 | found on omap850 HTC devices like the HTC Wizard and HTC Herald. | ||
196 | This device provides input and output GPIOs through an I2C | ||
197 | interface to one or more sub-chips. | ||
198 | |||
199 | config LPC_ICH | ||
200 | tristate "Intel ICH LPC" | ||
201 | depends on PCI && GENERIC_HARDIRQS | ||
202 | select MFD_CORE | ||
203 | help | ||
204 | The LPC bridge function of the Intel ICH provides support for | ||
205 | many functional units. This driver provides needed support for | ||
206 | other drivers to control these functions, currently GPIO and | ||
207 | watchdog. | ||
208 | |||
209 | config LPC_SCH | ||
210 | tristate "Intel SCH LPC" | ||
211 | depends on PCI && GENERIC_HARDIRQS | ||
212 | select MFD_CORE | ||
213 | help | ||
214 | LPC bridge function of the Intel SCH provides support for | ||
215 | System Management Bus and General Purpose I/O. | ||
216 | |||
217 | config MFD_INTEL_MSIC | ||
218 | bool "Intel MSIC" | ||
219 | depends on INTEL_SCU_IPC | ||
220 | select MFD_CORE | ||
221 | help | ||
222 | Select this option to enable access to Intel MSIC (Avatele | ||
223 | Passage) chip. This chip embeds audio, battery, GPIO, etc. | ||
224 | devices used in Intel Medfield platforms. | ||
225 | |||
226 | config MFD_JANZ_CMODIO | ||
227 | tristate "Janz CMOD-IO PCI MODULbus Carrier Board" | ||
228 | select MFD_CORE | ||
229 | depends on PCI && GENERIC_HARDIRQS | ||
230 | help | ||
231 | This is the core driver for the Janz CMOD-IO PCI MODULbus | ||
232 | carrier board. This device is a PCI to MODULbus bridge which may | ||
233 | host many different types of MODULbus daughterboards, including | ||
234 | CAN and GPIO controllers. | ||
235 | |||
236 | config MFD_JZ4740_ADC | ||
237 | bool "Janz JZ4740 ADC core" | ||
238 | select MFD_CORE | ||
239 | select GENERIC_IRQ_CHIP | ||
240 | depends on MACH_JZ4740 | ||
241 | help | ||
242 | Say yes here if you want support for the ADC unit in the JZ4740 SoC. | ||
243 | This driver is necessary for jz4740-battery and jz4740-hwmon driver. | ||
23 | 244 | ||
24 | config MFD_88PM800 | 245 | config MFD_88PM800 |
25 | tristate "Support Marvell 88PM800" | 246 | tristate "Marvell 88PM800" |
26 | depends on I2C=y && GENERIC_HARDIRQS | 247 | depends on I2C=y && GENERIC_HARDIRQS |
27 | select REGMAP_I2C | 248 | select REGMAP_I2C |
28 | select REGMAP_IRQ | 249 | select REGMAP_IRQ |
@@ -34,7 +255,7 @@ config MFD_88PM800 | |||
34 | battery-charger under the corresponding menus. | 255 | battery-charger under the corresponding menus. |
35 | 256 | ||
36 | config MFD_88PM805 | 257 | config MFD_88PM805 |
37 | tristate "Support Marvell 88PM805" | 258 | tristate "Marvell 88PM805" |
38 | depends on I2C=y && GENERIC_HARDIRQS | 259 | depends on I2C=y && GENERIC_HARDIRQS |
39 | select REGMAP_I2C | 260 | select REGMAP_I2C |
40 | select REGMAP_IRQ | 261 | select REGMAP_IRQ |
@@ -45,8 +266,242 @@ config MFD_88PM805 | |||
45 | components like codec device, headset/Mic device under the | 266 | components like codec device, headset/Mic device under the |
46 | corresponding menus. | 267 | corresponding menus. |
47 | 268 | ||
269 | config MFD_88PM860X | ||
270 | bool "Marvell 88PM8606/88PM8607" | ||
271 | depends on I2C=y && GENERIC_HARDIRQS | ||
272 | select REGMAP_I2C | ||
273 | select MFD_CORE | ||
274 | help | ||
275 | This supports for Marvell 88PM8606/88PM8607 Power Management IC. | ||
276 | This includes the I2C driver and the core APIs _only_, you have to | ||
277 | select individual components like voltage regulators, RTC and | ||
278 | battery-charger under the corresponding menus. | ||
279 | |||
280 | config MFD_MAX77686 | ||
281 | bool "Maxim Semiconductor MAX77686 PMIC Support" | ||
282 | depends on I2C=y && GENERIC_HARDIRQS | ||
283 | select MFD_CORE | ||
284 | select REGMAP_I2C | ||
285 | select IRQ_DOMAIN | ||
286 | help | ||
287 | Say yes here to support for Maxim Semiconductor MAX77686. | ||
288 | This is a Power Management IC with RTC on chip. | ||
289 | This driver provides common support for accessing the device; | ||
290 | additional drivers must be enabled in order to use the functionality | ||
291 | of the device. | ||
292 | |||
293 | config MFD_MAX77693 | ||
294 | bool "Maxim Semiconductor MAX77693 PMIC Support" | ||
295 | depends on I2C=y && GENERIC_HARDIRQS | ||
296 | select MFD_CORE | ||
297 | select REGMAP_I2C | ||
298 | help | ||
299 | Say yes here to support for Maxim Semiconductor MAX77693. | ||
300 | This is a companion Power Management IC with Flash, Haptic, Charger, | ||
301 | and MUIC(Micro USB Interface Controller) controls on chip. | ||
302 | This driver provides common support for accessing the device; | ||
303 | additional drivers must be enabled in order to use the functionality | ||
304 | of the device. | ||
305 | |||
306 | config MFD_MAX8907 | ||
307 | tristate "Maxim Semiconductor MAX8907 PMIC Support" | ||
308 | select MFD_CORE | ||
309 | depends on I2C=y && GENERIC_HARDIRQS | ||
310 | select REGMAP_I2C | ||
311 | select REGMAP_IRQ | ||
312 | help | ||
313 | Say yes here to support for Maxim Semiconductor MAX8907. This is | ||
314 | a Power Management IC. This driver provides common support for | ||
315 | accessing the device; additional drivers must be enabled in order | ||
316 | to use the functionality of the device. | ||
317 | |||
318 | config MFD_MAX8925 | ||
319 | bool "Maxim Semiconductor MAX8925 PMIC Support" | ||
320 | depends on I2C=y && GENERIC_HARDIRQS | ||
321 | select MFD_CORE | ||
322 | help | ||
323 | Say yes here to support for Maxim Semiconductor MAX8925. This is | ||
324 | a Power Management IC. This driver provides common support for | ||
325 | accessing the device, additional drivers must be enabled in order | ||
326 | to use the functionality of the device. | ||
327 | |||
328 | config MFD_MAX8997 | ||
329 | bool "Maxim Semiconductor MAX8997/8966 PMIC Support" | ||
330 | depends on I2C=y && GENERIC_HARDIRQS | ||
331 | select MFD_CORE | ||
332 | select IRQ_DOMAIN | ||
333 | help | ||
334 | Say yes here to support for Maxim Semiconductor MAX8997/8966. | ||
335 | This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic, | ||
336 | MUIC controls on chip. | ||
337 | This driver provides common support for accessing the device; | ||
338 | additional drivers must be enabled in order to use the functionality | ||
339 | of the device. | ||
340 | |||
341 | config MFD_MAX8998 | ||
342 | bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" | ||
343 | depends on I2C=y && GENERIC_HARDIRQS | ||
344 | select MFD_CORE | ||
345 | help | ||
346 | Say yes here to support for Maxim Semiconductor MAX8998 and | ||
347 | National Semiconductor LP3974. This is a Power Management IC. | ||
348 | This driver provides common support for accessing the device, | ||
349 | additional drivers must be enabled in order to use the functionality | ||
350 | of the device. | ||
351 | |||
352 | config EZX_PCAP | ||
353 | bool "Motorola EZXPCAP Support" | ||
354 | depends on GENERIC_HARDIRQS && SPI_MASTER | ||
355 | help | ||
356 | This enables the PCAP ASIC present on EZX Phones. This is | ||
357 | needed for MMC, TouchScreen, Sound, USB, etc.. | ||
358 | |||
359 | config MFD_VIPERBOARD | ||
360 | tristate "Nano River Technologies Viperboard" | ||
361 | select MFD_CORE | ||
362 | depends on USB && GENERIC_HARDIRQS | ||
363 | default n | ||
364 | help | ||
365 | Say yes here if you want support for Nano River Technologies | ||
366 | Viperboard. | ||
367 | There are mfd cell drivers available for i2c master, adc and | ||
368 | both gpios found on the board. The spi part does not yet | ||
369 | have a driver. | ||
370 | You need to select the mfd cell drivers separately. | ||
371 | The drivers do not support all features the board exposes. | ||
372 | |||
373 | config MFD_RETU | ||
374 | tristate "Nokia Retu and Tahvo multi-function device" | ||
375 | select MFD_CORE | ||
376 | depends on I2C && GENERIC_HARDIRQS | ||
377 | select REGMAP_IRQ | ||
378 | help | ||
379 | Retu and Tahvo are a multi-function devices found on Nokia | ||
380 | Internet Tablets (770, N800 and N810). | ||
381 | |||
382 | config MFD_PCF50633 | ||
383 | tristate "NXP PCF50633" | ||
384 | depends on I2C | ||
385 | select REGMAP_I2C | ||
386 | help | ||
387 | Say yes here if you have NXP PCF50633 chip on your board. | ||
388 | This core driver provides register access and IRQ handling | ||
389 | facilities, and registers devices for the various functions | ||
390 | so that function-specific drivers can bind to them. | ||
391 | |||
392 | config PCF50633_ADC | ||
393 | tristate "NXP PCF50633 ADC" | ||
394 | depends on MFD_PCF50633 | ||
395 | help | ||
396 | Say yes here if you want to include support for ADC in the | ||
397 | NXP PCF50633 chip. | ||
398 | |||
399 | config PCF50633_GPIO | ||
400 | tristate "NXP PCF50633 GPIO" | ||
401 | depends on MFD_PCF50633 | ||
402 | help | ||
403 | Say yes here if you want to include support GPIO for pins on | ||
404 | the PCF50633 chip. | ||
405 | |||
406 | config UCB1400_CORE | ||
407 | tristate "Philips UCB1400 Core driver" | ||
408 | depends on AC97_BUS | ||
409 | depends on GPIOLIB | ||
410 | help | ||
411 | This enables support for the Philips UCB1400 core functions. | ||
412 | The UCB1400 is an AC97 audio codec. | ||
413 | |||
414 | To compile this driver as a module, choose M here: the | ||
415 | module will be called ucb1400_core. | ||
416 | |||
417 | config MFD_PM8XXX | ||
418 | tristate | ||
419 | |||
420 | config MFD_PM8921_CORE | ||
421 | tristate "Qualcomm PM8921 PMIC chip" | ||
422 | depends on SSBI && BROKEN | ||
423 | select MFD_CORE | ||
424 | select MFD_PM8XXX | ||
425 | help | ||
426 | If you say yes to this option, support will be included for the | ||
427 | built-in PM8921 PMIC chip. | ||
428 | |||
429 | This is required if your board has a PM8921 and uses its features, | ||
430 | such as: MPPs, GPIOs, regulators, interrupts, and PWM. | ||
431 | |||
432 | Say M here if you want to include support for PM8921 chip as a module. | ||
433 | This will build a module called "pm8921-core". | ||
434 | |||
435 | config MFD_PM8XXX_IRQ | ||
436 | bool "Qualcomm PM8xxx IRQ features" | ||
437 | depends on MFD_PM8XXX | ||
438 | default y if MFD_PM8XXX | ||
439 | help | ||
440 | This is the IRQ driver for Qualcomm PM 8xxx PMIC chips. | ||
441 | |||
442 | This is required to use certain other PM 8xxx features, such as GPIO | ||
443 | and MPP. | ||
444 | |||
445 | config MFD_RDC321X | ||
446 | tristate "RDC R-321x southbridge" | ||
447 | select MFD_CORE | ||
448 | depends on PCI && GENERIC_HARDIRQS | ||
449 | help | ||
450 | Say yes here if you want to have support for the RDC R-321x SoC | ||
451 | southbridge which provides access to GPIOs and Watchdog using the | ||
452 | southbridge PCI device configuration space. | ||
453 | |||
454 | config MFD_RTSX_PCI | ||
455 | tristate "Realtek PCI-E card reader" | ||
456 | depends on PCI && GENERIC_HARDIRQS | ||
457 | select MFD_CORE | ||
458 | help | ||
459 | This supports for Realtek PCI-Express card reader including rts5209, | ||
460 | rts5229, rtl8411, etc. Realtek card reader supports access to many | ||
461 | types of memory cards, such as Memory Stick, Memory Stick Pro, | ||
462 | Secure Digital and MultiMediaCard. | ||
463 | |||
464 | config MFD_RC5T583 | ||
465 | bool "Ricoh RC5T583 Power Management system device" | ||
466 | depends on I2C=y && GENERIC_HARDIRQS | ||
467 | select MFD_CORE | ||
468 | select REGMAP_I2C | ||
469 | help | ||
470 | Select this option to get support for the RICOH583 Power | ||
471 | Management system device. | ||
472 | This driver provides common support for accessing the device | ||
473 | through i2c interface. The device supports multiple sub-devices | ||
474 | like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey. | ||
475 | Additional drivers must be enabled in order to use the | ||
476 | different functionality of the device. | ||
477 | |||
478 | config MFD_SEC_CORE | ||
479 | bool "SAMSUNG Electronics PMIC Series Support" | ||
480 | depends on I2C=y && GENERIC_HARDIRQS | ||
481 | select MFD_CORE | ||
482 | select REGMAP_I2C | ||
483 | select REGMAP_IRQ | ||
484 | help | ||
485 | Support for the Samsung Electronics MFD series. | ||
486 | This driver provides common support for accessing the device, | ||
487 | additional drivers must be enabled in order to use the functionality | ||
488 | of the device | ||
489 | |||
490 | config MFD_SI476X_CORE | ||
491 | tristate "Silicon Laboratories 4761/64/68 AM/FM radio." | ||
492 | depends on I2C | ||
493 | select MFD_CORE | ||
494 | select REGMAP_I2C | ||
495 | help | ||
496 | This is the core driver for the SI476x series of AM/FM | ||
497 | radio. This MFD driver connects the radio-si476x V4L2 module | ||
498 | and the si476x audio codec. | ||
499 | |||
500 | To compile this driver as a module, choose M here: the | ||
501 | module will be called si476x-core. | ||
502 | |||
48 | config MFD_SM501 | 503 | config MFD_SM501 |
49 | tristate "Support for Silicon Motion SM501" | 504 | tristate "Silicon Motion SM501" |
50 | ---help--- | 505 | ---help--- |
51 | This is the core driver for the Silicon Motion SM501 multimedia | 506 | This is the core driver for the Silicon Motion SM501 multimedia |
52 | companion chip. This device is a multifunction device which may | 507 | companion chip. This device is a multifunction device which may |
@@ -63,46 +518,147 @@ config MFD_SM501_GPIO | |||
63 | lines on the SM501. The platform data is used to supply the | 518 | lines on the SM501. The platform data is used to supply the |
64 | base number for the first GPIO line to register. | 519 | base number for the first GPIO line to register. |
65 | 520 | ||
66 | config MFD_RTSX_PCI | 521 | config MFD_SMSC |
67 | tristate "Support for Realtek PCI-E card reader" | 522 | bool "SMSC ECE1099 series chips" |
68 | depends on PCI && GENERIC_HARDIRQS | 523 | depends on I2C=y && GENERIC_HARDIRQS |
524 | select MFD_CORE | ||
525 | select REGMAP_I2C | ||
526 | help | ||
527 | If you say yes here you get support for the | ||
528 | ece1099 chips from SMSC. | ||
529 | |||
530 | To compile this driver as a module, choose M here: the | ||
531 | module will be called smsc. | ||
532 | |||
533 | config ABX500_CORE | ||
534 | bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" | ||
535 | default y if ARCH_U300 || ARCH_U8500 | ||
536 | help | ||
537 | Say yes here if you have the ABX500 Mixed Signal IC family | ||
538 | chips. This core driver expose register access functions. | ||
539 | Functionality specific drivers using these functions can | ||
540 | remain unchanged when IC changes. Binding of the functions to | ||
541 | actual register access is done by the IC core driver. | ||
542 | |||
543 | config AB3100_CORE | ||
544 | bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" | ||
545 | depends on I2C=y && ABX500_CORE && GENERIC_HARDIRQS | ||
69 | select MFD_CORE | 546 | select MFD_CORE |
547 | default y if ARCH_U300 | ||
70 | help | 548 | help |
71 | This supports for Realtek PCI-Express card reader including rts5209, | 549 | Select this to enable the AB3100 Mixed Signal IC core |
72 | rts5229, rtl8411, etc. Realtek card reader supports access to many | 550 | functionality. This connects to a AB3100 on the I2C bus |
73 | types of memory cards, such as Memory Stick, Memory Stick Pro, | 551 | and expose a number of symbols needed for dependent devices |
74 | Secure Digital and MultiMediaCard. | 552 | to read and write registers and subscribe to events from |
553 | this multi-functional IC. This is needed to use other features | ||
554 | of the AB3100 such as battery-backed RTC, charging control, | ||
555 | LEDs, vibrator, system power and temperature, power management | ||
556 | and ALSA sound. | ||
75 | 557 | ||
76 | config MFD_ASIC3 | 558 | config AB3100_OTP |
77 | bool "Support for Compaq ASIC3" | 559 | tristate "ST-Ericsson AB3100 OTP functions" |
78 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM | 560 | depends on AB3100_CORE |
561 | default y if AB3100_CORE | ||
562 | help | ||
563 | Select this to enable the AB3100 Mixed Signal IC OTP (one-time | ||
564 | programmable memory) support. This exposes a sysfs file to read | ||
565 | out OTP values. | ||
566 | |||
567 | config AB8500_CORE | ||
568 | bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" | ||
569 | depends on GENERIC_HARDIRQS && ABX500_CORE && MFD_DB8500_PRCMU | ||
570 | select POWER_SUPPLY | ||
79 | select MFD_CORE | 571 | select MFD_CORE |
80 | ---help--- | 572 | select IRQ_DOMAIN |
81 | This driver supports the ASIC3 multifunction chip found on many | 573 | help |
82 | PDAs (mainly iPAQ and HTC based ones) | 574 | Select this option to enable access to AB8500 power management |
575 | chip. This connects to U8500 either on the SSP/SPI bus (deprecated | ||
576 | since hardware version v1.0) or the I2C bus via PRCMU. It also adds | ||
577 | the irq_chip parts for handling the Mixed Signal chip events. | ||
578 | This chip embeds various other multimedia funtionalities as well. | ||
83 | 579 | ||
84 | config MFD_DAVINCI_VOICECODEC | 580 | config AB8500_DEBUG |
85 | tristate | 581 | bool "Enable debug info via debugfs" |
582 | depends on AB8500_CORE && DEBUG_FS | ||
583 | default y if DEBUG_FS | ||
584 | help | ||
585 | Select this option if you want debug information using the debug | ||
586 | filesystem, debugfs. | ||
587 | |||
588 | config AB8500_GPADC | ||
589 | bool "ST-Ericsson AB8500 GPADC driver" | ||
590 | depends on AB8500_CORE && REGULATOR_AB8500 | ||
591 | default y | ||
592 | help | ||
593 | AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage | ||
594 | |||
595 | config MFD_DB8500_PRCMU | ||
596 | bool "ST-Ericsson DB8500 Power Reset Control Management Unit" | ||
597 | depends on UX500_SOC_DB8500 | ||
86 | select MFD_CORE | 598 | select MFD_CORE |
599 | help | ||
600 | Select this option to enable support for the DB8500 Power Reset | ||
601 | and Control Management Unit. This is basically an autonomous | ||
602 | system controller running an XP70 microprocessor, which is accessed | ||
603 | through a register map. | ||
87 | 604 | ||
88 | config MFD_DM355EVM_MSP | 605 | config MFD_STMPE |
89 | bool "DaVinci DM355 EVM microcontroller" | 606 | bool "STMicroelectronics STMPE" |
90 | depends on I2C=y && MACH_DAVINCI_DM355_EVM | 607 | depends on (I2C=y || SPI_MASTER=y) && GENERIC_HARDIRQS |
608 | select MFD_CORE | ||
91 | help | 609 | help |
92 | This driver supports the MSP430 microcontroller used on these | 610 | Support for the STMPE family of I/O Expanders from |
93 | boards. MSP430 firmware manages resets and power sequencing, | 611 | STMicroelectronics. |
94 | inputs from buttons and the IR remote, LEDs, an RTC, and more. | ||
95 | 612 | ||
96 | config MFD_TI_SSP | 613 | Currently supported devices are: |
97 | tristate "TI Sequencer Serial Port support" | 614 | |
98 | depends on ARCH_DAVINCI_TNETV107X && GENERIC_HARDIRQS | 615 | STMPE811: GPIO, Touchscreen |
616 | STMPE1601: GPIO, Keypad | ||
617 | STMPE1801: GPIO, Keypad | ||
618 | STMPE2401: GPIO, Keypad | ||
619 | STMPE2403: GPIO, Keypad | ||
620 | |||
621 | This driver provides common support for accessing the device, | ||
622 | additional drivers must be enabled in order to use the functionality | ||
623 | of the device. Currently available sub drivers are: | ||
624 | |||
625 | GPIO: stmpe-gpio | ||
626 | Keypad: stmpe-keypad | ||
627 | Touchscreen: stmpe-ts | ||
628 | |||
629 | menu "STMicroelectronics STMPE Interface Drivers" | ||
630 | depends on MFD_STMPE | ||
631 | |||
632 | config STMPE_I2C | ||
633 | bool "STMicroelectronics STMPE I2C Inteface" | ||
634 | depends on I2C=y | ||
635 | default y | ||
636 | help | ||
637 | This is used to enable I2C interface of STMPE | ||
638 | |||
639 | config STMPE_SPI | ||
640 | bool "STMicroelectronics STMPE SPI Inteface" | ||
641 | depends on SPI_MASTER | ||
642 | help | ||
643 | This is used to enable SPI interface of STMPE | ||
644 | endmenu | ||
645 | |||
646 | config MFD_STA2X11 | ||
647 | bool "STMicroelectronics STA2X11" | ||
648 | depends on STA2X11 && GENERIC_HARDIRQS | ||
99 | select MFD_CORE | 649 | select MFD_CORE |
100 | ---help--- | 650 | select REGMAP_MMIO |
101 | Say Y here if you want support for the Sequencer Serial Port | ||
102 | in a Texas Instruments TNETV107X SoC. | ||
103 | 651 | ||
104 | To compile this driver as a module, choose M here: the | 652 | config MFD_SYSCON |
105 | module will be called ti-ssp. | 653 | bool "System Controller Register R/W Based on Regmap" |
654 | select REGMAP_MMIO | ||
655 | help | ||
656 | Select this option to enable accessing system control registers | ||
657 | via regmap. | ||
658 | |||
659 | config MFD_DAVINCI_VOICECODEC | ||
660 | tristate | ||
661 | select MFD_CORE | ||
106 | 662 | ||
107 | config MFD_TI_AM335X_TSCADC | 663 | config MFD_TI_AM335X_TSCADC |
108 | tristate "TI ADC / Touch Screen chip support" | 664 | tristate "TI ADC / Touch Screen chip support" |
@@ -116,60 +672,56 @@ config MFD_TI_AM335X_TSCADC | |||
116 | To compile this driver as a module, choose M here: the | 672 | To compile this driver as a module, choose M here: the |
117 | module will be called ti_am335x_tscadc. | 673 | module will be called ti_am335x_tscadc. |
118 | 674 | ||
119 | config HTC_EGPIO | 675 | config MFD_DM355EVM_MSP |
120 | bool "HTC EGPIO support" | 676 | bool "TI DaVinci DM355 EVM microcontroller" |
121 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM | 677 | depends on I2C=y && MACH_DAVINCI_DM355_EVM |
122 | help | 678 | help |
123 | This driver supports the CPLD egpio chip present on | 679 | This driver supports the MSP430 microcontroller used on these |
124 | several HTC phones. It provides basic support for input | 680 | boards. MSP430 firmware manages resets and power sequencing, |
125 | pins, output pins, and irqs. | 681 | inputs from buttons and the IR remote, LEDs, an RTC, and more. |
126 | 682 | ||
127 | config HTC_PASIC3 | 683 | config MFD_LP8788 |
128 | tristate "HTC PASIC3 LED/DS1WM chip support" | 684 | bool "TI LP8788 Power Management Unit Driver" |
685 | depends on I2C=y && GENERIC_HARDIRQS | ||
129 | select MFD_CORE | 686 | select MFD_CORE |
130 | depends on GENERIC_HARDIRQS | 687 | select REGMAP_I2C |
131 | help | 688 | select IRQ_DOMAIN |
132 | This core driver provides register access for the LED/DS1WM | ||
133 | chips labeled "AIC2" and "AIC3", found on HTC Blueangel and | ||
134 | HTC Magician devices, respectively. Actual functionality is | ||
135 | handled by the leds-pasic3 and ds1wm drivers. | ||
136 | |||
137 | config HTC_I2CPLD | ||
138 | bool "HTC I2C PLD chip support" | ||
139 | depends on I2C=y && GPIOLIB | ||
140 | help | 689 | help |
141 | If you say yes here you get support for the supposed CPLD | 690 | TI LP8788 PMU supports regulators, battery charger, RTC, |
142 | found on omap850 HTC devices like the HTC Wizard and HTC Herald. | 691 | ADC, backlight driver and current sinks. |
143 | This device provides input and output GPIOs through an I2C | ||
144 | interface to one or more sub-chips. | ||
145 | 692 | ||
146 | config UCB1400_CORE | 693 | config MFD_OMAP_USB_HOST |
147 | tristate "Philips UCB1400 Core driver" | 694 | bool "TI OMAP USBHS core and TLL driver" |
148 | depends on AC97_BUS | 695 | depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 |
149 | depends on GPIOLIB | 696 | default y |
150 | help | 697 | help |
151 | This enables support for the Philips UCB1400 core functions. | 698 | This is the core driver for the OAMP EHCI and OHCI drivers. |
152 | The UCB1400 is an AC97 audio codec. | 699 | This MFD driver does the required setup functionalities for |
153 | 700 | OMAP USB Host drivers. | |
154 | To compile this driver as a module, choose M here: the | ||
155 | module will be called ucb1400_core. | ||
156 | 701 | ||
157 | config MFD_LM3533 | 702 | config MFD_PALMAS |
158 | tristate "LM3533 Lighting Power chip" | 703 | bool "TI Palmas series chips" |
159 | depends on I2C | ||
160 | select MFD_CORE | 704 | select MFD_CORE |
161 | select REGMAP_I2C | 705 | select REGMAP_I2C |
162 | depends on GENERIC_HARDIRQS | 706 | select REGMAP_IRQ |
707 | depends on I2C=y && GENERIC_HARDIRQS | ||
163 | help | 708 | help |
164 | Say yes here to enable support for National Semiconductor / TI | 709 | If you say yes here you get support for the Palmas |
165 | LM3533 Lighting Power chips. | 710 | series of PMIC chips from Texas Instruments. |
166 | 711 | ||
167 | This driver provides common support for accessing the device; | 712 | config MFD_TI_SSP |
168 | additional drivers must be enabled in order to use the LED, | 713 | tristate "TI Sequencer Serial Port support" |
169 | backlight or ambient-light-sensor functionality of the device. | 714 | depends on ARCH_DAVINCI_TNETV107X && GENERIC_HARDIRQS |
715 | select MFD_CORE | ||
716 | ---help--- | ||
717 | Say Y here if you want support for the Sequencer Serial Port | ||
718 | in a Texas Instruments TNETV107X SoC. | ||
719 | |||
720 | To compile this driver as a module, choose M here: the | ||
721 | module will be called ti-ssp. | ||
170 | 722 | ||
171 | config TPS6105X | 723 | config TPS6105X |
172 | tristate "TPS61050/61052 Boost Converters" | 724 | tristate "TI TPS61050/61052 Boost Converters" |
173 | depends on I2C | 725 | depends on I2C |
174 | select REGULATOR | 726 | select REGULATOR |
175 | select MFD_CORE | 727 | select MFD_CORE |
@@ -182,7 +734,7 @@ config TPS6105X | |||
182 | also contains a GPIO pin. | 734 | also contains a GPIO pin. |
183 | 735 | ||
184 | config TPS65010 | 736 | config TPS65010 |
185 | tristate "TPS6501x Power Management chips" | 737 | tristate "TI TPS6501x Power Management chips" |
186 | depends on I2C && GPIOLIB | 738 | depends on I2C && GPIOLIB |
187 | default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK | 739 | default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK |
188 | help | 740 | help |
@@ -195,7 +747,7 @@ config TPS65010 | |||
195 | will be called tps65010. | 747 | will be called tps65010. |
196 | 748 | ||
197 | config TPS6507X | 749 | config TPS6507X |
198 | tristate "TPS6507x Power Management / Touch Screen chips" | 750 | tristate "TI TPS6507x Power Management / Touch Screen chips" |
199 | select MFD_CORE | 751 | select MFD_CORE |
200 | depends on I2C && GENERIC_HARDIRQS | 752 | depends on I2C && GENERIC_HARDIRQS |
201 | help | 753 | help |
@@ -206,8 +758,24 @@ config TPS6507X | |||
206 | This driver can also be built as a module. If so, the module | 758 | This driver can also be built as a module. If so, the module |
207 | will be called tps6507x. | 759 | will be called tps6507x. |
208 | 760 | ||
761 | config TPS65911_COMPARATOR | ||
762 | tristate | ||
763 | |||
764 | config MFD_TPS65090 | ||
765 | bool "TI TPS65090 Power Management chips" | ||
766 | depends on I2C=y && GENERIC_HARDIRQS | ||
767 | select MFD_CORE | ||
768 | select REGMAP_I2C | ||
769 | select REGMAP_IRQ | ||
770 | help | ||
771 | If you say yes here you get support for the TPS65090 series of | ||
772 | Power Management chips. | ||
773 | This driver provides common support for accessing the device, | ||
774 | additional drivers must be enabled in order to use the | ||
775 | functionality of the device. | ||
776 | |||
209 | config MFD_TPS65217 | 777 | config MFD_TPS65217 |
210 | tristate "TPS65217 Power Management / White LED chips" | 778 | tristate "TI TPS65217 Power Management / White LED chips" |
211 | depends on I2C && GENERIC_HARDIRQS | 779 | depends on I2C && GENERIC_HARDIRQS |
212 | select MFD_CORE | 780 | select MFD_CORE |
213 | select REGMAP_I2C | 781 | select REGMAP_I2C |
@@ -222,7 +790,7 @@ config MFD_TPS65217 | |||
222 | will be called tps65217. | 790 | will be called tps65217. |
223 | 791 | ||
224 | config MFD_TPS6586X | 792 | config MFD_TPS6586X |
225 | bool "TPS6586x Power Management chips" | 793 | bool "TI TPS6586x Power Management chips" |
226 | depends on I2C=y && GENERIC_HARDIRQS | 794 | depends on I2C=y && GENERIC_HARDIRQS |
227 | select MFD_CORE | 795 | select MFD_CORE |
228 | select REGMAP_I2C | 796 | select REGMAP_I2C |
@@ -237,7 +805,7 @@ config MFD_TPS6586X | |||
237 | will be called tps6586x. | 805 | will be called tps6586x. |
238 | 806 | ||
239 | config MFD_TPS65910 | 807 | config MFD_TPS65910 |
240 | bool "TPS65910 Power Management chip" | 808 | bool "TI TPS65910 Power Management chip" |
241 | depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS | 809 | depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS |
242 | select MFD_CORE | 810 | select MFD_CORE |
243 | select REGMAP_I2C | 811 | select REGMAP_I2C |
@@ -248,11 +816,14 @@ config MFD_TPS65910 | |||
248 | Power Management chips. | 816 | Power Management chips. |
249 | 817 | ||
250 | config MFD_TPS65912 | 818 | config MFD_TPS65912 |
251 | bool | 819 | bool "TI TPS65912 Power Management chip" |
252 | depends on GPIOLIB | 820 | depends on GPIOLIB |
821 | help | ||
822 | If you say yes here you get support for the TPS65912 series of | ||
823 | PM chips. | ||
253 | 824 | ||
254 | config MFD_TPS65912_I2C | 825 | config MFD_TPS65912_I2C |
255 | bool "TPS65912 Power Management chip with I2C" | 826 | bool "TI TPS65912 Power Management chip with I2C" |
256 | select MFD_CORE | 827 | select MFD_CORE |
257 | select MFD_TPS65912 | 828 | select MFD_TPS65912 |
258 | depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS | 829 | depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS |
@@ -261,7 +832,7 @@ config MFD_TPS65912_I2C | |||
261 | PM chips with I2C interface. | 832 | PM chips with I2C interface. |
262 | 833 | ||
263 | config MFD_TPS65912_SPI | 834 | config MFD_TPS65912_SPI |
264 | bool "TPS65912 Power Management chip with SPI" | 835 | bool "TI TPS65912 Power Management chip with SPI" |
265 | select MFD_CORE | 836 | select MFD_CORE |
266 | select MFD_TPS65912 | 837 | select MFD_TPS65912 |
267 | depends on SPI_MASTER && GPIOLIB && GENERIC_HARDIRQS | 838 | depends on SPI_MASTER && GPIOLIB && GENERIC_HARDIRQS |
@@ -283,18 +854,8 @@ config MFD_TPS80031 | |||
283 | ADC, RTC, 2 PWM, System Voltage Regulator/Battery Charger with | 854 | ADC, RTC, 2 PWM, System Voltage Regulator/Battery Charger with |
284 | Power Path from USB, 32K clock generator. | 855 | Power Path from USB, 32K clock generator. |
285 | 856 | ||
286 | config MENELAUS | ||
287 | bool "Texas Instruments TWL92330/Menelaus PM chip" | ||
288 | depends on I2C=y && ARCH_OMAP2 | ||
289 | help | ||
290 | If you say yes here you get support for the Texas Instruments | ||
291 | TWL92330/Menelaus Power Management chip. This include voltage | ||
292 | regulators, Dual slot memory card transceivers, real-time clock | ||
293 | and other features that are often used in portable devices like | ||
294 | cell phones and PDAs. | ||
295 | |||
296 | config TWL4030_CORE | 857 | config TWL4030_CORE |
297 | bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" | 858 | bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 Support" |
298 | depends on I2C=y && GENERIC_HARDIRQS | 859 | depends on I2C=y && GENERIC_HARDIRQS |
299 | select IRQ_DOMAIN | 860 | select IRQ_DOMAIN |
300 | select REGMAP_I2C | 861 | select REGMAP_I2C |
@@ -310,7 +871,7 @@ config TWL4030_CORE | |||
310 | versions) and many other features. | 871 | versions) and many other features. |
311 | 872 | ||
312 | config TWL4030_MADC | 873 | config TWL4030_MADC |
313 | tristate "Texas Instruments TWL4030 MADC" | 874 | tristate "TI TWL4030 MADC" |
314 | depends on TWL4030_CORE | 875 | depends on TWL4030_CORE |
315 | help | 876 | help |
316 | This driver provides support for triton TWL4030-MADC. The | 877 | This driver provides support for triton TWL4030-MADC. The |
@@ -320,7 +881,7 @@ config TWL4030_MADC | |||
320 | named twl4030-madc | 881 | named twl4030-madc |
321 | 882 | ||
322 | config TWL4030_POWER | 883 | config TWL4030_POWER |
323 | bool "Support power resources on TWL4030 family chips" | 884 | bool "TI TWL4030 power resources" |
324 | depends on TWL4030_CORE && ARM | 885 | depends on TWL4030_CORE && ARM |
325 | help | 886 | help |
326 | Say yes here if you want to use the power resources on the | 887 | Say yes here if you want to use the power resources on the |
@@ -333,13 +894,13 @@ config TWL4030_POWER | |||
333 | or reset when a sleep, wakeup or warm reset event occurs. | 894 | or reset when a sleep, wakeup or warm reset event occurs. |
334 | 895 | ||
335 | config MFD_TWL4030_AUDIO | 896 | config MFD_TWL4030_AUDIO |
336 | bool | 897 | bool "TI TWL4030 Audio" |
337 | depends on TWL4030_CORE && GENERIC_HARDIRQS | 898 | depends on TWL4030_CORE && GENERIC_HARDIRQS |
338 | select MFD_CORE | 899 | select MFD_CORE |
339 | default n | 900 | default n |
340 | 901 | ||
341 | config TWL6040_CORE | 902 | config TWL6040_CORE |
342 | bool "Support for TWL6040 audio codec" | 903 | bool "TI TWL6040 audio codec" |
343 | depends on I2C=y && GENERIC_HARDIRQS | 904 | depends on I2C=y && GENERIC_HARDIRQS |
344 | select MFD_CORE | 905 | select MFD_CORE |
345 | select REGMAP_I2C | 906 | select REGMAP_I2C |
@@ -352,48 +913,53 @@ config TWL6040_CORE | |||
352 | additional drivers must be enabled in order to use the | 913 | additional drivers must be enabled in order to use the |
353 | functionality of the device (audio, vibra). | 914 | functionality of the device (audio, vibra). |
354 | 915 | ||
355 | config MFD_STMPE | 916 | config MENELAUS |
356 | bool "Support STMicroelectronics STMPE" | 917 | bool "TI TWL92330/Menelaus PM chip" |
357 | depends on (I2C=y || SPI_MASTER=y) && GENERIC_HARDIRQS | 918 | depends on I2C=y && ARCH_OMAP2 |
358 | select MFD_CORE | ||
359 | help | 919 | help |
360 | Support for the STMPE family of I/O Expanders from | 920 | If you say yes here you get support for the Texas Instruments |
361 | STMicroelectronics. | 921 | TWL92330/Menelaus Power Management chip. This include voltage |
362 | 922 | regulators, Dual slot memory card transceivers, real-time clock | |
363 | Currently supported devices are: | 923 | and other features that are often used in portable devices like |
364 | 924 | cell phones and PDAs. | |
365 | STMPE811: GPIO, Touchscreen | ||
366 | STMPE1601: GPIO, Keypad | ||
367 | STMPE2401: GPIO, Keypad | ||
368 | STMPE2403: GPIO, Keypad | ||
369 | 925 | ||
370 | This driver provides common support for accessing the device, | 926 | config MFD_WL1273_CORE |
371 | additional drivers must be enabled in order to use the functionality | 927 | tristate "TI WL1273 FM radio" |
372 | of the device. Currently available sub drivers are: | 928 | depends on I2C && GENERIC_HARDIRQS |
929 | select MFD_CORE | ||
930 | default n | ||
931 | help | ||
932 | This is the core driver for the TI WL1273 FM radio. This MFD | ||
933 | driver connects the radio-wl1273 V4L2 module and the wl1273 | ||
934 | audio codec. | ||
373 | 935 | ||
374 | GPIO: stmpe-gpio | 936 | config MFD_LM3533 |
375 | Keypad: stmpe-keypad | 937 | tristate "TI/National Semiconductor LM3533 Lighting Power chip" |
376 | Touchscreen: stmpe-ts | 938 | depends on I2C |
939 | select MFD_CORE | ||
940 | select REGMAP_I2C | ||
941 | depends on GENERIC_HARDIRQS | ||
942 | help | ||
943 | Say yes here to enable support for National Semiconductor / TI | ||
944 | LM3533 Lighting Power chips. | ||
377 | 945 | ||
378 | menu "STMPE Interface Drivers" | 946 | This driver provides common support for accessing the device; |
379 | depends on MFD_STMPE | 947 | additional drivers must be enabled in order to use the LED, |
948 | backlight or ambient-light-sensor functionality of the device. | ||
380 | 949 | ||
381 | config STMPE_I2C | 950 | config MFD_TIMBERDALE |
382 | bool "STMPE I2C Inteface" | 951 | tristate "Timberdale FPGA" |
383 | depends on I2C=y | 952 | select MFD_CORE |
384 | default y | 953 | depends on PCI && GPIOLIB |
385 | help | 954 | ---help--- |
386 | This is used to enable I2C interface of STMPE | 955 | This is the core driver for the timberdale FPGA. This device is a |
956 | multifunction device which exposes numerous platform devices. | ||
387 | 957 | ||
388 | config STMPE_SPI | 958 | The timberdale FPGA can be found on the Intel Atom development board |
389 | bool "STMPE SPI Inteface" | 959 | for in-vehicle infontainment, called Russellville. |
390 | depends on SPI_MASTER | ||
391 | help | ||
392 | This is used to enable SPI interface of STMPE | ||
393 | endmenu | ||
394 | 960 | ||
395 | config MFD_TC3589X | 961 | config MFD_TC3589X |
396 | bool "Support Toshiba TC35892 and variants" | 962 | bool "Toshiba TC35892 and variants" |
397 | depends on I2C=y && GENERIC_HARDIRQS | 963 | depends on I2C=y && GENERIC_HARDIRQS |
398 | select MFD_CORE | 964 | select MFD_CORE |
399 | help | 965 | help |
@@ -408,27 +974,15 @@ config MFD_TMIO | |||
408 | default n | 974 | default n |
409 | 975 | ||
410 | config MFD_T7L66XB | 976 | config MFD_T7L66XB |
411 | bool "Support Toshiba T7L66XB" | 977 | bool "Toshiba T7L66XB" |
412 | depends on ARM && HAVE_CLK && GENERIC_HARDIRQS | 978 | depends on ARM && HAVE_CLK && GENERIC_HARDIRQS |
413 | select MFD_CORE | 979 | select MFD_CORE |
414 | select MFD_TMIO | 980 | select MFD_TMIO |
415 | help | 981 | help |
416 | Support for Toshiba Mobile IO Controller T7L66XB | 982 | Support for Toshiba Mobile IO Controller T7L66XB |
417 | 983 | ||
418 | config MFD_SMSC | ||
419 | bool "Support for the SMSC ECE1099 series chips" | ||
420 | depends on I2C=y && GENERIC_HARDIRQS | ||
421 | select MFD_CORE | ||
422 | select REGMAP_I2C | ||
423 | help | ||
424 | If you say yes here you get support for the | ||
425 | ece1099 chips from SMSC. | ||
426 | |||
427 | To compile this driver as a module, choose M here: the | ||
428 | module will be called smsc. | ||
429 | |||
430 | config MFD_TC6387XB | 984 | config MFD_TC6387XB |
431 | bool "Support Toshiba TC6387XB" | 985 | bool "Toshiba TC6387XB" |
432 | depends on ARM && HAVE_CLK | 986 | depends on ARM && HAVE_CLK |
433 | select MFD_CORE | 987 | select MFD_CORE |
434 | select MFD_TMIO | 988 | select MFD_TMIO |
@@ -436,7 +990,7 @@ config MFD_TC6387XB | |||
436 | Support for Toshiba Mobile IO Controller TC6387XB | 990 | Support for Toshiba Mobile IO Controller TC6387XB |
437 | 991 | ||
438 | config MFD_TC6393XB | 992 | config MFD_TC6393XB |
439 | bool "Support Toshiba TC6393XB" | 993 | bool "Toshiba TC6393XB" |
440 | depends on ARM && HAVE_CLK | 994 | depends on ARM && HAVE_CLK |
441 | select GPIOLIB | 995 | select GPIOLIB |
442 | select MFD_CORE | 996 | select MFD_CORE |
@@ -444,165 +998,14 @@ config MFD_TC6393XB | |||
444 | help | 998 | help |
445 | Support for Toshiba Mobile IO Controller TC6393XB | 999 | Support for Toshiba Mobile IO Controller TC6393XB |
446 | 1000 | ||
447 | config PMIC_DA903X | 1001 | config MFD_VX855 |
448 | bool "Dialog Semiconductor DA9030/DA9034 PMIC Support" | 1002 | tristate "VIA VX855/VX875 integrated south bridge" |
449 | depends on I2C=y | 1003 | depends on PCI && GENERIC_HARDIRQS |
450 | help | ||
451 | Say yes here to support for Dialog Semiconductor DA9030 (a.k.a | ||
452 | ARAVA) and DA9034 (a.k.a MICCO), these are Power Management IC | ||
453 | usually found on PXA processors-based platforms. This includes | ||
454 | the I2C driver and the core APIs _only_, you have to select | ||
455 | individual components like LCD backlight, voltage regulators, | ||
456 | LEDs and battery-charger under the corresponding menus. | ||
457 | |||
458 | config PMIC_DA9052 | ||
459 | bool | ||
460 | select MFD_CORE | ||
461 | |||
462 | config MFD_DA9052_SPI | ||
463 | bool "Support Dialog Semiconductor DA9052/53 PMIC variants with SPI" | ||
464 | select REGMAP_SPI | ||
465 | select REGMAP_IRQ | ||
466 | select PMIC_DA9052 | ||
467 | depends on SPI_MASTER=y && GENERIC_HARDIRQS | ||
468 | help | ||
469 | Support for the Dialog Semiconductor DA9052 PMIC | ||
470 | when controlled using SPI. This driver provides common support | ||
471 | for accessing the device, additional drivers must be enabled in | ||
472 | order to use the functionality of the device. | ||
473 | |||
474 | config MFD_DA9052_I2C | ||
475 | bool "Support Dialog Semiconductor DA9052/53 PMIC variants with I2C" | ||
476 | select REGMAP_I2C | ||
477 | select REGMAP_IRQ | ||
478 | select PMIC_DA9052 | ||
479 | depends on I2C=y && GENERIC_HARDIRQS | ||
480 | help | ||
481 | Support for the Dialog Semiconductor DA9052 PMIC | ||
482 | when controlled using I2C. This driver provides common support | ||
483 | for accessing the device, additional drivers must be enabled in | ||
484 | order to use the functionality of the device. | ||
485 | |||
486 | config MFD_DA9055 | ||
487 | bool "Dialog Semiconductor DA9055 PMIC Support" | ||
488 | select REGMAP_I2C | ||
489 | select REGMAP_IRQ | ||
490 | select PMIC_DA9055 | ||
491 | select MFD_CORE | ||
492 | depends on I2C=y && GENERIC_HARDIRQS | ||
493 | help | ||
494 | Say yes here for support of Dialog Semiconductor DA9055. This is | ||
495 | a Power Management IC. This driver provides common support for | ||
496 | accessing the device as well as the I2C interface to the chip itself. | ||
497 | Additional drivers must be enabled in order to use the functionality | ||
498 | of the device. | ||
499 | |||
500 | This driver can be built as a module. If built as a module it will be | ||
501 | called "da9055" | ||
502 | |||
503 | config PMIC_ADP5520 | ||
504 | bool "Analog Devices ADP5520/01 MFD PMIC Core Support" | ||
505 | depends on I2C=y | ||
506 | help | ||
507 | Say yes here to add support for Analog Devices AD5520 and ADP5501, | ||
508 | Multifunction Power Management IC. This includes | ||
509 | the I2C driver and the core APIs _only_, you have to select | ||
510 | individual components like LCD backlight, LEDs, GPIOs and Kepad | ||
511 | under the corresponding menus. | ||
512 | |||
513 | config MFD_LP8788 | ||
514 | bool "Texas Instruments LP8788 Power Management Unit Driver" | ||
515 | depends on I2C=y && GENERIC_HARDIRQS | ||
516 | select MFD_CORE | ||
517 | select REGMAP_I2C | ||
518 | select IRQ_DOMAIN | ||
519 | help | ||
520 | TI LP8788 PMU supports regulators, battery charger, RTC, | ||
521 | ADC, backlight driver and current sinks. | ||
522 | |||
523 | config MFD_MAX77686 | ||
524 | bool "Maxim Semiconductor MAX77686 PMIC Support" | ||
525 | depends on I2C=y && GENERIC_HARDIRQS | ||
526 | select MFD_CORE | ||
527 | select REGMAP_I2C | ||
528 | select IRQ_DOMAIN | ||
529 | help | ||
530 | Say yes here to support for Maxim Semiconductor MAX77686. | ||
531 | This is a Power Management IC with RTC on chip. | ||
532 | This driver provides common support for accessing the device; | ||
533 | additional drivers must be enabled in order to use the functionality | ||
534 | of the device. | ||
535 | |||
536 | config MFD_MAX77693 | ||
537 | bool "Maxim Semiconductor MAX77693 PMIC Support" | ||
538 | depends on I2C=y && GENERIC_HARDIRQS | ||
539 | select MFD_CORE | ||
540 | select REGMAP_I2C | ||
541 | help | ||
542 | Say yes here to support for Maxim Semiconductor MAX77693. | ||
543 | This is a companion Power Management IC with Flash, Haptic, Charger, | ||
544 | and MUIC(Micro USB Interface Controller) controls on chip. | ||
545 | This driver provides common support for accessing the device; | ||
546 | additional drivers must be enabled in order to use the functionality | ||
547 | of the device. | ||
548 | |||
549 | config MFD_MAX8907 | ||
550 | tristate "Maxim Semiconductor MAX8907 PMIC Support" | ||
551 | select MFD_CORE | ||
552 | depends on I2C=y && GENERIC_HARDIRQS | ||
553 | select REGMAP_I2C | ||
554 | select REGMAP_IRQ | ||
555 | help | ||
556 | Say yes here to support for Maxim Semiconductor MAX8907. This is | ||
557 | a Power Management IC. This driver provides common support for | ||
558 | accessing the device; additional drivers must be enabled in order | ||
559 | to use the functionality of the device. | ||
560 | |||
561 | config MFD_MAX8925 | ||
562 | bool "Maxim Semiconductor MAX8925 PMIC Support" | ||
563 | depends on I2C=y && GENERIC_HARDIRQS | ||
564 | select MFD_CORE | ||
565 | help | ||
566 | Say yes here to support for Maxim Semiconductor MAX8925. This is | ||
567 | a Power Management IC. This driver provides common support for | ||
568 | accessing the device, additional drivers must be enabled in order | ||
569 | to use the functionality of the device. | ||
570 | |||
571 | config MFD_MAX8997 | ||
572 | bool "Maxim Semiconductor MAX8997/8966 PMIC Support" | ||
573 | depends on I2C=y && GENERIC_HARDIRQS | ||
574 | select MFD_CORE | ||
575 | select IRQ_DOMAIN | ||
576 | help | ||
577 | Say yes here to support for Maxim Semiconductor MAX8997/8966. | ||
578 | This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic, | ||
579 | MUIC controls on chip. | ||
580 | This driver provides common support for accessing the device; | ||
581 | additional drivers must be enabled in order to use the functionality | ||
582 | of the device. | ||
583 | |||
584 | config MFD_MAX8998 | ||
585 | bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" | ||
586 | depends on I2C=y && GENERIC_HARDIRQS | ||
587 | select MFD_CORE | ||
588 | help | ||
589 | Say yes here to support for Maxim Semiconductor MAX8998 and | ||
590 | National Semiconductor LP3974. This is a Power Management IC. | ||
591 | This driver provides common support for accessing the device, | ||
592 | additional drivers must be enabled in order to use the functionality | ||
593 | of the device. | ||
594 | |||
595 | config MFD_SEC_CORE | ||
596 | bool "SAMSUNG Electronics PMIC Series Support" | ||
597 | depends on I2C=y && GENERIC_HARDIRQS | ||
598 | select MFD_CORE | 1004 | select MFD_CORE |
599 | select REGMAP_I2C | ||
600 | select REGMAP_IRQ | ||
601 | help | 1005 | help |
602 | Support for the Samsung Electronics MFD series. | 1006 | Say yes here to enable support for various functions of the |
603 | This driver provides common support for accessing the device, | 1007 | VIA VX855/VX875 south bridge. You will need to enable the vx855_spi |
604 | additional drivers must be enabled in order to use the functionality | 1008 | and/or vx855_gpio drivers for this to do anything useful. |
605 | of the device | ||
606 | 1009 | ||
607 | config MFD_ARIZONA | 1010 | config MFD_ARIZONA |
608 | select REGMAP | 1011 | select REGMAP |
@@ -611,7 +1014,7 @@ config MFD_ARIZONA | |||
611 | bool | 1014 | bool |
612 | 1015 | ||
613 | config MFD_ARIZONA_I2C | 1016 | config MFD_ARIZONA_I2C |
614 | tristate "Support Wolfson Microelectronics Arizona platform with I2C" | 1017 | tristate "Wolfson Microelectronics Arizona platform with I2C" |
615 | select MFD_ARIZONA | 1018 | select MFD_ARIZONA |
616 | select MFD_CORE | 1019 | select MFD_CORE |
617 | select REGMAP_I2C | 1020 | select REGMAP_I2C |
@@ -621,7 +1024,7 @@ config MFD_ARIZONA_I2C | |||
621 | core functionality controlled via I2C. | 1024 | core functionality controlled via I2C. |
622 | 1025 | ||
623 | config MFD_ARIZONA_SPI | 1026 | config MFD_ARIZONA_SPI |
624 | tristate "Support Wolfson Microelectronics Arizona platform with SPI" | 1027 | tristate "Wolfson Microelectronics Arizona platform with SPI" |
625 | select MFD_ARIZONA | 1028 | select MFD_ARIZONA |
626 | select MFD_CORE | 1029 | select MFD_CORE |
627 | select REGMAP_SPI | 1030 | select REGMAP_SPI |
@@ -631,19 +1034,19 @@ config MFD_ARIZONA_SPI | |||
631 | core functionality controlled via I2C. | 1034 | core functionality controlled via I2C. |
632 | 1035 | ||
633 | config MFD_WM5102 | 1036 | config MFD_WM5102 |
634 | bool "Support Wolfson Microelectronics WM5102" | 1037 | bool "Wolfson Microelectronics WM5102" |
635 | depends on MFD_ARIZONA | 1038 | depends on MFD_ARIZONA |
636 | help | 1039 | help |
637 | Support for Wolfson Microelectronics WM5102 low power audio SoC | 1040 | Support for Wolfson Microelectronics WM5102 low power audio SoC |
638 | 1041 | ||
639 | config MFD_WM5110 | 1042 | config MFD_WM5110 |
640 | bool "Support Wolfson Microelectronics WM5110" | 1043 | bool "Wolfson Microelectronics WM5110" |
641 | depends on MFD_ARIZONA | 1044 | depends on MFD_ARIZONA |
642 | help | 1045 | help |
643 | Support for Wolfson Microelectronics WM5110 low power audio SoC | 1046 | Support for Wolfson Microelectronics WM5110 low power audio SoC |
644 | 1047 | ||
645 | config MFD_WM8400 | 1048 | config MFD_WM8400 |
646 | bool "Support Wolfson Microelectronics WM8400" | 1049 | bool "Wolfson Microelectronics WM8400" |
647 | select MFD_CORE | 1050 | select MFD_CORE |
648 | depends on I2C=y && GENERIC_HARDIRQS | 1051 | depends on I2C=y && GENERIC_HARDIRQS |
649 | select REGMAP_I2C | 1052 | select REGMAP_I2C |
@@ -658,7 +1061,7 @@ config MFD_WM831X | |||
658 | depends on GENERIC_HARDIRQS | 1061 | depends on GENERIC_HARDIRQS |
659 | 1062 | ||
660 | config MFD_WM831X_I2C | 1063 | config MFD_WM831X_I2C |
661 | bool "Support Wolfson Microelectronics WM831x/2x PMICs with I2C" | 1064 | bool "Wolfson Microelectronics WM831x/2x PMICs with I2C" |
662 | select MFD_CORE | 1065 | select MFD_CORE |
663 | select MFD_WM831X | 1066 | select MFD_WM831X |
664 | select REGMAP_I2C | 1067 | select REGMAP_I2C |
@@ -671,7 +1074,7 @@ config MFD_WM831X_I2C | |||
671 | order to use the functionality of the device. | 1074 | order to use the functionality of the device. |
672 | 1075 | ||
673 | config MFD_WM831X_SPI | 1076 | config MFD_WM831X_SPI |
674 | bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI" | 1077 | bool "Wolfson Microelectronics WM831x/2x PMICs with SPI" |
675 | select MFD_CORE | 1078 | select MFD_CORE |
676 | select MFD_WM831X | 1079 | select MFD_WM831X |
677 | select REGMAP_SPI | 1080 | select REGMAP_SPI |
@@ -687,56 +1090,8 @@ config MFD_WM8350 | |||
687 | bool | 1090 | bool |
688 | depends on GENERIC_HARDIRQS | 1091 | depends on GENERIC_HARDIRQS |
689 | 1092 | ||
690 | config MFD_WM8350_CONFIG_MODE_0 | ||
691 | bool | ||
692 | depends on MFD_WM8350 | ||
693 | |||
694 | config MFD_WM8350_CONFIG_MODE_1 | ||
695 | bool | ||
696 | depends on MFD_WM8350 | ||
697 | |||
698 | config MFD_WM8350_CONFIG_MODE_2 | ||
699 | bool | ||
700 | depends on MFD_WM8350 | ||
701 | |||
702 | config MFD_WM8350_CONFIG_MODE_3 | ||
703 | bool | ||
704 | depends on MFD_WM8350 | ||
705 | |||
706 | config MFD_WM8351_CONFIG_MODE_0 | ||
707 | bool | ||
708 | depends on MFD_WM8350 | ||
709 | |||
710 | config MFD_WM8351_CONFIG_MODE_1 | ||
711 | bool | ||
712 | depends on MFD_WM8350 | ||
713 | |||
714 | config MFD_WM8351_CONFIG_MODE_2 | ||
715 | bool | ||
716 | depends on MFD_WM8350 | ||
717 | |||
718 | config MFD_WM8351_CONFIG_MODE_3 | ||
719 | bool | ||
720 | depends on MFD_WM8350 | ||
721 | |||
722 | config MFD_WM8352_CONFIG_MODE_0 | ||
723 | bool | ||
724 | depends on MFD_WM8350 | ||
725 | |||
726 | config MFD_WM8352_CONFIG_MODE_1 | ||
727 | bool | ||
728 | depends on MFD_WM8350 | ||
729 | |||
730 | config MFD_WM8352_CONFIG_MODE_2 | ||
731 | bool | ||
732 | depends on MFD_WM8350 | ||
733 | |||
734 | config MFD_WM8352_CONFIG_MODE_3 | ||
735 | bool | ||
736 | depends on MFD_WM8350 | ||
737 | |||
738 | config MFD_WM8350_I2C | 1093 | config MFD_WM8350_I2C |
739 | bool "Support Wolfson Microelectronics WM8350 with I2C" | 1094 | bool "Wolfson Microelectronics WM8350 with I2C" |
740 | select MFD_WM8350 | 1095 | select MFD_WM8350 |
741 | depends on I2C=y && GENERIC_HARDIRQS | 1096 | depends on I2C=y && GENERIC_HARDIRQS |
742 | help | 1097 | help |
@@ -747,7 +1102,7 @@ config MFD_WM8350_I2C | |||
747 | selected to enable support for the functionality of the chip. | 1102 | selected to enable support for the functionality of the chip. |
748 | 1103 | ||
749 | config MFD_WM8994 | 1104 | config MFD_WM8994 |
750 | bool "Support Wolfson Microelectronics WM8994" | 1105 | bool "Wolfson Microelectronics WM8994" |
751 | select MFD_CORE | 1106 | select MFD_CORE |
752 | select REGMAP_I2C | 1107 | select REGMAP_I2C |
753 | select REGMAP_IRQ | 1108 | select REGMAP_IRQ |
@@ -760,365 +1115,6 @@ config MFD_WM8994 | |||
760 | core support for the WM8994, in order to use the actual | 1115 | core support for the WM8994, in order to use the actual |
761 | functionaltiy of the device other drivers must be enabled. | 1116 | functionaltiy of the device other drivers must be enabled. |
762 | 1117 | ||
763 | config MFD_PCF50633 | ||
764 | tristate "Support for NXP PCF50633" | ||
765 | depends on I2C | ||
766 | select REGMAP_I2C | ||
767 | help | ||
768 | Say yes here if you have NXP PCF50633 chip on your board. | ||
769 | This core driver provides register access and IRQ handling | ||
770 | facilities, and registers devices for the various functions | ||
771 | so that function-specific drivers can bind to them. | ||
772 | |||
773 | config PCF50633_ADC | ||
774 | tristate "Support for NXP PCF50633 ADC" | ||
775 | depends on MFD_PCF50633 | ||
776 | help | ||
777 | Say yes here if you want to include support for ADC in the | ||
778 | NXP PCF50633 chip. | ||
779 | |||
780 | config PCF50633_GPIO | ||
781 | tristate "Support for NXP PCF50633 GPIO" | ||
782 | depends on MFD_PCF50633 | ||
783 | help | ||
784 | Say yes here if you want to include support GPIO for pins on | ||
785 | the PCF50633 chip. | ||
786 | |||
787 | config MFD_MC13783 | ||
788 | tristate | ||
789 | |||
790 | config MFD_MC13XXX | ||
791 | tristate | ||
792 | depends on (SPI_MASTER || I2C) && GENERIC_HARDIRQS | ||
793 | select MFD_CORE | ||
794 | select MFD_MC13783 | ||
795 | help | ||
796 | Enable support for the Freescale MC13783 and MC13892 PMICs. | ||
797 | This driver provides common support for accessing the device, | ||
798 | additional drivers must be enabled in order to use the | ||
799 | functionality of the device. | ||
800 | |||
801 | config MFD_MC13XXX_SPI | ||
802 | tristate "Freescale MC13783 and MC13892 SPI interface" | ||
803 | depends on SPI_MASTER && GENERIC_HARDIRQS | ||
804 | select REGMAP_SPI | ||
805 | select MFD_MC13XXX | ||
806 | help | ||
807 | Select this if your MC13xxx is connected via an SPI bus. | ||
808 | |||
809 | config MFD_MC13XXX_I2C | ||
810 | tristate "Freescale MC13892 I2C interface" | ||
811 | depends on I2C && GENERIC_HARDIRQS | ||
812 | select REGMAP_I2C | ||
813 | select MFD_MC13XXX | ||
814 | help | ||
815 | Select this if your MC13xxx is connected via an I2C bus. | ||
816 | |||
817 | config ABX500_CORE | ||
818 | bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" | ||
819 | default y if ARCH_U300 || ARCH_U8500 | ||
820 | help | ||
821 | Say yes here if you have the ABX500 Mixed Signal IC family | ||
822 | chips. This core driver expose register access functions. | ||
823 | Functionality specific drivers using these functions can | ||
824 | remain unchanged when IC changes. Binding of the functions to | ||
825 | actual register access is done by the IC core driver. | ||
826 | |||
827 | config AB3100_CORE | ||
828 | bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" | ||
829 | depends on I2C=y && ABX500_CORE && GENERIC_HARDIRQS | ||
830 | select MFD_CORE | ||
831 | default y if ARCH_U300 | ||
832 | help | ||
833 | Select this to enable the AB3100 Mixed Signal IC core | ||
834 | functionality. This connects to a AB3100 on the I2C bus | ||
835 | and expose a number of symbols needed for dependent devices | ||
836 | to read and write registers and subscribe to events from | ||
837 | this multi-functional IC. This is needed to use other features | ||
838 | of the AB3100 such as battery-backed RTC, charging control, | ||
839 | LEDs, vibrator, system power and temperature, power management | ||
840 | and ALSA sound. | ||
841 | |||
842 | config AB3100_OTP | ||
843 | tristate "ST-Ericsson AB3100 OTP functions" | ||
844 | depends on AB3100_CORE | ||
845 | default y if AB3100_CORE | ||
846 | help | ||
847 | Select this to enable the AB3100 Mixed Signal IC OTP (one-time | ||
848 | programmable memory) support. This exposes a sysfs file to read | ||
849 | out OTP values. | ||
850 | |||
851 | config EZX_PCAP | ||
852 | bool "PCAP Support" | ||
853 | depends on GENERIC_HARDIRQS && SPI_MASTER | ||
854 | help | ||
855 | This enables the PCAP ASIC present on EZX Phones. This is | ||
856 | needed for MMC, TouchScreen, Sound, USB, etc.. | ||
857 | |||
858 | config AB8500_CORE | ||
859 | bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" | ||
860 | depends on GENERIC_HARDIRQS && ABX500_CORE && MFD_DB8500_PRCMU | ||
861 | select POWER_SUPPLY | ||
862 | select MFD_CORE | ||
863 | select IRQ_DOMAIN | ||
864 | help | ||
865 | Select this option to enable access to AB8500 power management | ||
866 | chip. This connects to U8500 either on the SSP/SPI bus (deprecated | ||
867 | since hardware version v1.0) or the I2C bus via PRCMU. It also adds | ||
868 | the irq_chip parts for handling the Mixed Signal chip events. | ||
869 | This chip embeds various other multimedia funtionalities as well. | ||
870 | |||
871 | config AB8500_DEBUG | ||
872 | bool "Enable debug info via debugfs" | ||
873 | depends on AB8500_CORE && DEBUG_FS | ||
874 | default y if DEBUG_FS | ||
875 | help | ||
876 | Select this option if you want debug information using the debug | ||
877 | filesystem, debugfs. | ||
878 | |||
879 | config AB8500_GPADC | ||
880 | bool "AB8500 GPADC driver" | ||
881 | depends on AB8500_CORE && REGULATOR_AB8500 | ||
882 | default y | ||
883 | help | ||
884 | AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage | ||
885 | |||
886 | config MFD_DB8500_PRCMU | ||
887 | bool "ST-Ericsson DB8500 Power Reset Control Management Unit" | ||
888 | depends on UX500_SOC_DB8500 | ||
889 | select MFD_CORE | ||
890 | help | ||
891 | Select this option to enable support for the DB8500 Power Reset | ||
892 | and Control Management Unit. This is basically an autonomous | ||
893 | system controller running an XP70 microprocessor, which is accessed | ||
894 | through a register map. | ||
895 | |||
896 | config MFD_CS5535 | ||
897 | tristate "Support for CS5535 and CS5536 southbridge core functions" | ||
898 | select MFD_CORE | ||
899 | depends on PCI && X86 | ||
900 | ---help--- | ||
901 | This is the core driver for CS5535/CS5536 MFD functions. This is | ||
902 | necessary for using the board's GPIO and MFGPT functionality. | ||
903 | |||
904 | config MFD_TIMBERDALE | ||
905 | tristate "Support for the Timberdale FPGA" | ||
906 | select MFD_CORE | ||
907 | depends on PCI && GPIOLIB | ||
908 | ---help--- | ||
909 | This is the core driver for the timberdale FPGA. This device is a | ||
910 | multifunction device which exposes numerous platform devices. | ||
911 | |||
912 | The timberdale FPGA can be found on the Intel Atom development board | ||
913 | for in-vehicle infontainment, called Russellville. | ||
914 | |||
915 | config LPC_SCH | ||
916 | tristate "Intel SCH LPC" | ||
917 | depends on PCI && GENERIC_HARDIRQS | ||
918 | select MFD_CORE | ||
919 | help | ||
920 | LPC bridge function of the Intel SCH provides support for | ||
921 | System Management Bus and General Purpose I/O. | ||
922 | |||
923 | config LPC_ICH | ||
924 | tristate "Intel ICH LPC" | ||
925 | depends on PCI && GENERIC_HARDIRQS | ||
926 | select MFD_CORE | ||
927 | help | ||
928 | The LPC bridge function of the Intel ICH provides support for | ||
929 | many functional units. This driver provides needed support for | ||
930 | other drivers to control these functions, currently GPIO and | ||
931 | watchdog. | ||
932 | |||
933 | config MFD_RDC321X | ||
934 | tristate "Support for RDC-R321x southbridge" | ||
935 | select MFD_CORE | ||
936 | depends on PCI && GENERIC_HARDIRQS | ||
937 | help | ||
938 | Say yes here if you want to have support for the RDC R-321x SoC | ||
939 | southbridge which provides access to GPIOs and Watchdog using the | ||
940 | southbridge PCI device configuration space. | ||
941 | |||
942 | config MFD_JANZ_CMODIO | ||
943 | tristate "Support for Janz CMOD-IO PCI MODULbus Carrier Board" | ||
944 | select MFD_CORE | ||
945 | depends on PCI && GENERIC_HARDIRQS | ||
946 | help | ||
947 | This is the core driver for the Janz CMOD-IO PCI MODULbus | ||
948 | carrier board. This device is a PCI to MODULbus bridge which may | ||
949 | host many different types of MODULbus daughterboards, including | ||
950 | CAN and GPIO controllers. | ||
951 | |||
952 | config MFD_JZ4740_ADC | ||
953 | bool "Support for the JZ4740 SoC ADC core" | ||
954 | select MFD_CORE | ||
955 | select GENERIC_IRQ_CHIP | ||
956 | depends on MACH_JZ4740 | ||
957 | help | ||
958 | Say yes here if you want support for the ADC unit in the JZ4740 SoC. | ||
959 | This driver is necessary for jz4740-battery and jz4740-hwmon driver. | ||
960 | |||
961 | config MFD_VX855 | ||
962 | tristate "Support for VIA VX855/VX875 integrated south bridge" | ||
963 | depends on PCI && GENERIC_HARDIRQS | ||
964 | select MFD_CORE | ||
965 | help | ||
966 | Say yes here to enable support for various functions of the | ||
967 | VIA VX855/VX875 south bridge. You will need to enable the vx855_spi | ||
968 | and/or vx855_gpio drivers for this to do anything useful. | ||
969 | |||
970 | config MFD_WL1273_CORE | ||
971 | tristate "Support for TI WL1273 FM radio." | ||
972 | depends on I2C && GENERIC_HARDIRQS | ||
973 | select MFD_CORE | ||
974 | default n | ||
975 | help | ||
976 | This is the core driver for the TI WL1273 FM radio. This MFD | ||
977 | driver connects the radio-wl1273 V4L2 module and the wl1273 | ||
978 | audio codec. | ||
979 | |||
980 | config MFD_OMAP_USB_HOST | ||
981 | bool "Support OMAP USBHS core and TLL driver" | ||
982 | depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 | ||
983 | default y | ||
984 | help | ||
985 | This is the core driver for the OAMP EHCI and OHCI drivers. | ||
986 | This MFD driver does the required setup functionalities for | ||
987 | OMAP USB Host drivers. | ||
988 | |||
989 | config MFD_PM8XXX | ||
990 | tristate | ||
991 | |||
992 | config MFD_PM8921_CORE | ||
993 | tristate "Qualcomm PM8921 PMIC chip" | ||
994 | depends on SSBI && BROKEN | ||
995 | select MFD_CORE | ||
996 | select MFD_PM8XXX | ||
997 | help | ||
998 | If you say yes to this option, support will be included for the | ||
999 | built-in PM8921 PMIC chip. | ||
1000 | |||
1001 | This is required if your board has a PM8921 and uses its features, | ||
1002 | such as: MPPs, GPIOs, regulators, interrupts, and PWM. | ||
1003 | |||
1004 | Say M here if you want to include support for PM8921 chip as a module. | ||
1005 | This will build a module called "pm8921-core". | ||
1006 | |||
1007 | config MFD_PM8XXX_IRQ | ||
1008 | bool "Support for Qualcomm PM8xxx IRQ features" | ||
1009 | depends on MFD_PM8XXX | ||
1010 | default y if MFD_PM8XXX | ||
1011 | help | ||
1012 | This is the IRQ driver for Qualcomm PM 8xxx PMIC chips. | ||
1013 | |||
1014 | This is required to use certain other PM 8xxx features, such as GPIO | ||
1015 | and MPP. | ||
1016 | |||
1017 | config TPS65911_COMPARATOR | ||
1018 | tristate | ||
1019 | |||
1020 | config MFD_TPS65090 | ||
1021 | bool "TPS65090 Power Management chips" | ||
1022 | depends on I2C=y && GENERIC_HARDIRQS | ||
1023 | select MFD_CORE | ||
1024 | select REGMAP_I2C | ||
1025 | select REGMAP_IRQ | ||
1026 | help | ||
1027 | If you say yes here you get support for the TPS65090 series of | ||
1028 | Power Management chips. | ||
1029 | This driver provides common support for accessing the device, | ||
1030 | additional drivers must be enabled in order to use the | ||
1031 | functionality of the device. | ||
1032 | |||
1033 | config MFD_AAT2870_CORE | ||
1034 | bool "Support for the AnalogicTech AAT2870" | ||
1035 | select MFD_CORE | ||
1036 | depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS | ||
1037 | help | ||
1038 | If you say yes here you get support for the AAT2870. | ||
1039 | This driver provides common support for accessing the device, | ||
1040 | additional drivers must be enabled in order to use the | ||
1041 | functionality of the device. | ||
1042 | |||
1043 | config MFD_INTEL_MSIC | ||
1044 | bool "Support for Intel MSIC" | ||
1045 | depends on INTEL_SCU_IPC | ||
1046 | select MFD_CORE | ||
1047 | help | ||
1048 | Select this option to enable access to Intel MSIC (Avatele | ||
1049 | Passage) chip. This chip embeds audio, battery, GPIO, etc. | ||
1050 | devices used in Intel Medfield platforms. | ||
1051 | |||
1052 | config MFD_RC5T583 | ||
1053 | bool "Ricoh RC5T583 Power Management system device" | ||
1054 | depends on I2C=y && GENERIC_HARDIRQS | ||
1055 | select MFD_CORE | ||
1056 | select REGMAP_I2C | ||
1057 | help | ||
1058 | Select this option to get support for the RICOH583 Power | ||
1059 | Management system device. | ||
1060 | This driver provides common support for accessing the device | ||
1061 | through i2c interface. The device supports multiple sub-devices | ||
1062 | like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey. | ||
1063 | Additional drivers must be enabled in order to use the | ||
1064 | different functionality of the device. | ||
1065 | |||
1066 | config MFD_STA2X11 | ||
1067 | bool "STA2X11 multi function device support" | ||
1068 | depends on STA2X11 && GENERIC_HARDIRQS | ||
1069 | select MFD_CORE | ||
1070 | select REGMAP_MMIO | ||
1071 | |||
1072 | config MFD_SYSCON | ||
1073 | bool "System Controller Register R/W Based on Regmap" | ||
1074 | depends on OF | ||
1075 | select REGMAP_MMIO | ||
1076 | help | ||
1077 | Select this option to enable accessing system control registers | ||
1078 | via regmap. | ||
1079 | |||
1080 | config MFD_PALMAS | ||
1081 | bool "Support for the TI Palmas series chips" | ||
1082 | select MFD_CORE | ||
1083 | select REGMAP_I2C | ||
1084 | select REGMAP_IRQ | ||
1085 | depends on I2C=y && GENERIC_HARDIRQS | ||
1086 | help | ||
1087 | If you say yes here you get support for the Palmas | ||
1088 | series of PMIC chips from Texas Instruments. | ||
1089 | |||
1090 | config MFD_VIPERBOARD | ||
1091 | tristate "Support for Nano River Technologies Viperboard" | ||
1092 | select MFD_CORE | ||
1093 | depends on USB && GENERIC_HARDIRQS | ||
1094 | default n | ||
1095 | help | ||
1096 | Say yes here if you want support for Nano River Technologies | ||
1097 | Viperboard. | ||
1098 | There are mfd cell drivers available for i2c master, adc and | ||
1099 | both gpios found on the board. The spi part does not yet | ||
1100 | have a driver. | ||
1101 | You need to select the mfd cell drivers separately. | ||
1102 | The drivers do not support all features the board exposes. | ||
1103 | |||
1104 | config MFD_RETU | ||
1105 | tristate "Support for Retu multi-function device" | ||
1106 | select MFD_CORE | ||
1107 | depends on I2C && GENERIC_HARDIRQS | ||
1108 | select REGMAP_IRQ | ||
1109 | help | ||
1110 | Retu is a multi-function device found on Nokia Internet Tablets | ||
1111 | (770, N800 and N810). | ||
1112 | |||
1113 | config MFD_AS3711 | ||
1114 | bool "Support for AS3711" | ||
1115 | select MFD_CORE | ||
1116 | select REGMAP_I2C | ||
1117 | select REGMAP_IRQ | ||
1118 | depends on I2C=y && GENERIC_HARDIRQS | ||
1119 | help | ||
1120 | Support for the AS3711 PMIC from AMS | ||
1121 | |||
1122 | endmenu | 1118 | endmenu |
1123 | endif | 1119 | endif |
1124 | 1120 | ||
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index b90409c23664..718e94a2a9a7 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -8,8 +8,11 @@ obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o | |||
8 | obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o | 8 | obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o |
9 | obj-$(CONFIG_MFD_SM501) += sm501.o | 9 | obj-$(CONFIG_MFD_SM501) += sm501.o |
10 | obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o | 10 | obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o |
11 | obj-$(CONFIG_MFD_CROS_EC) += cros_ec.o | ||
12 | obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o | ||
13 | obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o | ||
11 | 14 | ||
12 | rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o | 15 | rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o |
13 | obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o | 16 | obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o |
14 | 17 | ||
15 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o | 18 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o |
@@ -131,6 +134,10 @@ obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o | |||
131 | obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o | 134 | obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o |
132 | obj-$(CONFIG_MFD_VX855) += vx855.o | 135 | obj-$(CONFIG_MFD_VX855) += vx855.o |
133 | obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o | 136 | obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o |
137 | |||
138 | si476x-core-y := si476x-cmd.o si476x-prop.o si476x-i2c.o | ||
139 | obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o | ||
140 | |||
134 | obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o | 141 | obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o |
135 | obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o | 142 | obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o |
136 | obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o | 143 | obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o |
diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c index f1beb4971f87..dfdb0a2b6835 100644 --- a/drivers/mfd/aat2870-core.c +++ b/drivers/mfd/aat2870-core.c | |||
@@ -367,12 +367,12 @@ static int aat2870_i2c_probe(struct i2c_client *client, | |||
367 | int i, j; | 367 | int i, j; |
368 | int ret = 0; | 368 | int ret = 0; |
369 | 369 | ||
370 | aat2870 = kzalloc(sizeof(struct aat2870_data), GFP_KERNEL); | 370 | aat2870 = devm_kzalloc(&client->dev, sizeof(struct aat2870_data), |
371 | GFP_KERNEL); | ||
371 | if (!aat2870) { | 372 | if (!aat2870) { |
372 | dev_err(&client->dev, | 373 | dev_err(&client->dev, |
373 | "Failed to allocate memory for aat2870\n"); | 374 | "Failed to allocate memory for aat2870\n"); |
374 | ret = -ENOMEM; | 375 | return -ENOMEM; |
375 | goto out; | ||
376 | } | 376 | } |
377 | 377 | ||
378 | aat2870->dev = &client->dev; | 378 | aat2870->dev = &client->dev; |
@@ -400,12 +400,12 @@ static int aat2870_i2c_probe(struct i2c_client *client, | |||
400 | aat2870->init(aat2870); | 400 | aat2870->init(aat2870); |
401 | 401 | ||
402 | if (aat2870->en_pin >= 0) { | 402 | if (aat2870->en_pin >= 0) { |
403 | ret = gpio_request_one(aat2870->en_pin, GPIOF_OUT_INIT_HIGH, | 403 | ret = devm_gpio_request_one(&client->dev, aat2870->en_pin, |
404 | "aat2870-en"); | 404 | GPIOF_OUT_INIT_HIGH, "aat2870-en"); |
405 | if (ret < 0) { | 405 | if (ret < 0) { |
406 | dev_err(&client->dev, | 406 | dev_err(&client->dev, |
407 | "Failed to request GPIO %d\n", aat2870->en_pin); | 407 | "Failed to request GPIO %d\n", aat2870->en_pin); |
408 | goto out_kfree; | 408 | return ret; |
409 | } | 409 | } |
410 | } | 410 | } |
411 | 411 | ||
@@ -436,11 +436,6 @@ static int aat2870_i2c_probe(struct i2c_client *client, | |||
436 | 436 | ||
437 | out_disable: | 437 | out_disable: |
438 | aat2870_disable(aat2870); | 438 | aat2870_disable(aat2870); |
439 | if (aat2870->en_pin >= 0) | ||
440 | gpio_free(aat2870->en_pin); | ||
441 | out_kfree: | ||
442 | kfree(aat2870); | ||
443 | out: | ||
444 | return ret; | 439 | return ret; |
445 | } | 440 | } |
446 | 441 | ||
@@ -452,11 +447,8 @@ static int aat2870_i2c_remove(struct i2c_client *client) | |||
452 | 447 | ||
453 | mfd_remove_devices(aat2870->dev); | 448 | mfd_remove_devices(aat2870->dev); |
454 | aat2870_disable(aat2870); | 449 | aat2870_disable(aat2870); |
455 | if (aat2870->en_pin >= 0) | ||
456 | gpio_free(aat2870->en_pin); | ||
457 | if (aat2870->uninit) | 450 | if (aat2870->uninit) |
458 | aat2870->uninit(aat2870); | 451 | aat2870->uninit(aat2870); |
459 | kfree(aat2870); | ||
460 | 452 | ||
461 | return 0; | 453 | return 0; |
462 | } | 454 | } |
diff --git a/drivers/mfd/ab3100-otp.c b/drivers/mfd/ab3100-otp.c index 8440010eb2b8..d7ce016029fa 100644 --- a/drivers/mfd/ab3100-otp.c +++ b/drivers/mfd/ab3100-otp.c | |||
@@ -248,19 +248,7 @@ static struct platform_driver ab3100_otp_driver = { | |||
248 | .remove = __exit_p(ab3100_otp_remove), | 248 | .remove = __exit_p(ab3100_otp_remove), |
249 | }; | 249 | }; |
250 | 250 | ||
251 | static int __init ab3100_otp_init(void) | 251 | module_platform_driver_probe(ab3100_otp_driver, ab3100_otp_probe); |
252 | { | ||
253 | return platform_driver_probe(&ab3100_otp_driver, | ||
254 | ab3100_otp_probe); | ||
255 | } | ||
256 | |||
257 | static void __exit ab3100_otp_exit(void) | ||
258 | { | ||
259 | platform_driver_unregister(&ab3100_otp_driver); | ||
260 | } | ||
261 | |||
262 | module_init(ab3100_otp_init); | ||
263 | module_exit(ab3100_otp_exit); | ||
264 | 252 | ||
265 | MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); | 253 | MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); |
266 | MODULE_DESCRIPTION("AB3100 OTP Readout Driver"); | 254 | MODULE_DESCRIPTION("AB3100 OTP Readout Driver"); |
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index f276352cc9ef..8e8a016effe9 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c | |||
@@ -458,22 +458,23 @@ static void update_latch_offset(u8 *offset, int i) | |||
458 | static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, | 458 | static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, |
459 | int latch_offset, u8 latch_val) | 459 | int latch_offset, u8 latch_val) |
460 | { | 460 | { |
461 | int int_bit = __ffs(latch_val); | 461 | int int_bit, line, i; |
462 | int line, i; | ||
463 | 462 | ||
464 | do { | 463 | for (i = 0; i < ab8500->mask_size; i++) |
465 | int_bit = __ffs(latch_val); | 464 | if (ab8500->irq_reg_offset[i] == latch_offset) |
465 | break; | ||
466 | 466 | ||
467 | for (i = 0; i < ab8500->mask_size; i++) | 467 | if (i >= ab8500->mask_size) { |
468 | if (ab8500->irq_reg_offset[i] == latch_offset) | 468 | dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", |
469 | break; | 469 | latch_offset); |
470 | return -ENXIO; | ||
471 | } | ||
470 | 472 | ||
471 | if (i >= ab8500->mask_size) { | 473 | /* ignore masked out interrupts */ |
472 | dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", | 474 | latch_val &= ~ab8500->mask[i]; |
473 | latch_offset); | ||
474 | return -ENXIO; | ||
475 | } | ||
476 | 475 | ||
476 | while (latch_val) { | ||
477 | int_bit = __ffs(latch_val); | ||
477 | line = (i << 3) + int_bit; | 478 | line = (i << 3) + int_bit; |
478 | latch_val &= ~(1 << int_bit); | 479 | latch_val &= ~(1 << int_bit); |
479 | 480 | ||
@@ -491,7 +492,7 @@ static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, | |||
491 | line += 1; | 492 | line += 1; |
492 | 493 | ||
493 | handle_nested_irq(ab8500->irq_base + line); | 494 | handle_nested_irq(ab8500->irq_base + line); |
494 | } while (latch_val); | 495 | } |
495 | 496 | ||
496 | return 0; | 497 | return 0; |
497 | } | 498 | } |
@@ -1107,6 +1108,7 @@ static struct mfd_cell ab8500_devs[] = { | |||
1107 | }, | 1108 | }, |
1108 | { | 1109 | { |
1109 | .name = "ab8500-usb", | 1110 | .name = "ab8500-usb", |
1111 | .of_compatible = "stericsson,ab8500-usb", | ||
1110 | .num_resources = ARRAY_SIZE(ab8500_usb_resources), | 1112 | .num_resources = ARRAY_SIZE(ab8500_usb_resources), |
1111 | .resources = ab8500_usb_resources, | 1113 | .resources = ab8500_usb_resources, |
1112 | }, | 1114 | }, |
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 65f72284185d..5e65b28a5d09 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c | |||
@@ -332,7 +332,7 @@ if (ad_value < 0) { | |||
332 | 332 | ||
333 | return voltage; | 333 | return voltage; |
334 | } | 334 | } |
335 | EXPORT_SYMBOL(ab8500_gpadc_convert); | 335 | EXPORT_SYMBOL(ab8500_gpadc_sw_hw_convert); |
336 | 336 | ||
337 | /** | 337 | /** |
338 | * ab8500_gpadc_read_raw() - gpadc read | 338 | * ab8500_gpadc_read_raw() - gpadc read |
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c index 272479cdb107..fbca1ced49fa 100644 --- a/drivers/mfd/ab8500-sysctrl.c +++ b/drivers/mfd/ab8500-sysctrl.c | |||
@@ -242,7 +242,7 @@ static int __init ab8500_sysctrl_init(void) | |||
242 | { | 242 | { |
243 | return platform_driver_register(&ab8500_sysctrl_driver); | 243 | return platform_driver_register(&ab8500_sysctrl_driver); |
244 | } | 244 | } |
245 | subsys_initcall(ab8500_sysctrl_init); | 245 | arch_initcall(ab8500_sysctrl_init); |
246 | 246 | ||
247 | MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com"); | 247 | MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com"); |
248 | MODULE_DESCRIPTION("AB8500 system control driver"); | 248 | MODULE_DESCRIPTION("AB8500 system control driver"); |
diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c index 210dd038bb5a..0d2eba023439 100644 --- a/drivers/mfd/adp5520.c +++ b/drivers/mfd/adp5520.c | |||
@@ -36,6 +36,7 @@ struct adp5520_chip { | |||
36 | struct blocking_notifier_head notifier_list; | 36 | struct blocking_notifier_head notifier_list; |
37 | int irq; | 37 | int irq; |
38 | unsigned long id; | 38 | unsigned long id; |
39 | uint8_t mode; | ||
39 | }; | 40 | }; |
40 | 41 | ||
41 | static int __adp5520_read(struct i2c_client *client, | 42 | static int __adp5520_read(struct i2c_client *client, |
@@ -326,7 +327,10 @@ static int adp5520_suspend(struct device *dev) | |||
326 | struct i2c_client *client = to_i2c_client(dev); | 327 | struct i2c_client *client = to_i2c_client(dev); |
327 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); | 328 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); |
328 | 329 | ||
329 | adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); | 330 | adp5520_read(chip->dev, ADP5520_MODE_STATUS, &chip->mode); |
331 | /* All other bits are W1C */ | ||
332 | chip->mode &= ADP5520_BL_EN | ADP5520_DIM_EN | ADP5520_nSTNBY; | ||
333 | adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0); | ||
330 | return 0; | 334 | return 0; |
331 | } | 335 | } |
332 | 336 | ||
@@ -335,7 +339,7 @@ static int adp5520_resume(struct device *dev) | |||
335 | struct i2c_client *client = to_i2c_client(dev); | 339 | struct i2c_client *client = to_i2c_client(dev); |
336 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); | 340 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); |
337 | 341 | ||
338 | adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); | 342 | adp5520_write(chip->dev, ADP5520_MODE_STATUS, chip->mode); |
339 | return 0; | 343 | return 0; |
340 | } | 344 | } |
341 | #endif | 345 | #endif |
@@ -360,17 +364,7 @@ static struct i2c_driver adp5520_driver = { | |||
360 | .id_table = adp5520_id, | 364 | .id_table = adp5520_id, |
361 | }; | 365 | }; |
362 | 366 | ||
363 | static int __init adp5520_init(void) | 367 | module_i2c_driver(adp5520_driver); |
364 | { | ||
365 | return i2c_add_driver(&adp5520_driver); | ||
366 | } | ||
367 | module_init(adp5520_init); | ||
368 | |||
369 | static void __exit adp5520_exit(void) | ||
370 | { | ||
371 | i2c_del_driver(&adp5520_driver); | ||
372 | } | ||
373 | module_exit(adp5520_exit); | ||
374 | 368 | ||
375 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | 369 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); |
376 | MODULE_DESCRIPTION("ADP5520(01) PMIC-MFD Driver"); | 370 | MODULE_DESCRIPTION("ADP5520(01) PMIC-MFD Driver"); |
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index b562c7bf8a46..6ab03043fd60 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c | |||
@@ -39,11 +39,21 @@ int arizona_clk32k_enable(struct arizona *arizona) | |||
39 | 39 | ||
40 | arizona->clk32k_ref++; | 40 | arizona->clk32k_ref++; |
41 | 41 | ||
42 | if (arizona->clk32k_ref == 1) | 42 | if (arizona->clk32k_ref == 1) { |
43 | switch (arizona->pdata.clk32k_src) { | ||
44 | case ARIZONA_32KZ_MCLK1: | ||
45 | ret = pm_runtime_get_sync(arizona->dev); | ||
46 | if (ret != 0) | ||
47 | goto out; | ||
48 | break; | ||
49 | } | ||
50 | |||
43 | ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, | 51 | ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, |
44 | ARIZONA_CLK_32K_ENA, | 52 | ARIZONA_CLK_32K_ENA, |
45 | ARIZONA_CLK_32K_ENA); | 53 | ARIZONA_CLK_32K_ENA); |
54 | } | ||
46 | 55 | ||
56 | out: | ||
47 | if (ret != 0) | 57 | if (ret != 0) |
48 | arizona->clk32k_ref--; | 58 | arizona->clk32k_ref--; |
49 | 59 | ||
@@ -63,10 +73,17 @@ int arizona_clk32k_disable(struct arizona *arizona) | |||
63 | 73 | ||
64 | arizona->clk32k_ref--; | 74 | arizona->clk32k_ref--; |
65 | 75 | ||
66 | if (arizona->clk32k_ref == 0) | 76 | if (arizona->clk32k_ref == 0) { |
67 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, | 77 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, |
68 | ARIZONA_CLK_32K_ENA, 0); | 78 | ARIZONA_CLK_32K_ENA, 0); |
69 | 79 | ||
80 | switch (arizona->pdata.clk32k_src) { | ||
81 | case ARIZONA_32KZ_MCLK1: | ||
82 | pm_runtime_put_sync(arizona->dev); | ||
83 | break; | ||
84 | } | ||
85 | } | ||
86 | |||
70 | mutex_unlock(&arizona->clk_lock); | 87 | mutex_unlock(&arizona->clk_lock); |
71 | 88 | ||
72 | return ret; | 89 | return ret; |
@@ -179,42 +196,134 @@ static irqreturn_t arizona_overclocked(int irq, void *data) | |||
179 | return IRQ_HANDLED; | 196 | return IRQ_HANDLED; |
180 | } | 197 | } |
181 | 198 | ||
182 | static int arizona_wait_for_boot(struct arizona *arizona) | 199 | static int arizona_poll_reg(struct arizona *arizona, |
200 | int timeout, unsigned int reg, | ||
201 | unsigned int mask, unsigned int target) | ||
183 | { | 202 | { |
184 | unsigned int reg; | 203 | unsigned int val = 0; |
185 | int ret, i; | 204 | int ret, i; |
186 | 205 | ||
206 | for (i = 0; i < timeout; i++) { | ||
207 | ret = regmap_read(arizona->regmap, reg, &val); | ||
208 | if (ret != 0) { | ||
209 | dev_err(arizona->dev, "Failed to read reg %u: %d\n", | ||
210 | reg, ret); | ||
211 | continue; | ||
212 | } | ||
213 | |||
214 | if ((val & mask) == target) | ||
215 | return 0; | ||
216 | |||
217 | msleep(1); | ||
218 | } | ||
219 | |||
220 | dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val); | ||
221 | return -ETIMEDOUT; | ||
222 | } | ||
223 | |||
224 | static int arizona_wait_for_boot(struct arizona *arizona) | ||
225 | { | ||
226 | int ret; | ||
227 | |||
187 | /* | 228 | /* |
188 | * We can't use an interrupt as we need to runtime resume to do so, | 229 | * We can't use an interrupt as we need to runtime resume to do so, |
189 | * we won't race with the interrupt handler as it'll be blocked on | 230 | * we won't race with the interrupt handler as it'll be blocked on |
190 | * runtime resume. | 231 | * runtime resume. |
191 | */ | 232 | */ |
192 | for (i = 0; i < 5; i++) { | 233 | ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5, |
193 | msleep(1); | 234 | ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS); |
194 | 235 | ||
195 | ret = regmap_read(arizona->regmap, | 236 | if (!ret) |
196 | ARIZONA_INTERRUPT_RAW_STATUS_5, ®); | 237 | regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, |
197 | if (ret != 0) { | 238 | ARIZONA_BOOT_DONE_STS); |
198 | dev_err(arizona->dev, "Failed to read boot state: %d\n", | ||
199 | ret); | ||
200 | continue; | ||
201 | } | ||
202 | 239 | ||
203 | if (reg & ARIZONA_BOOT_DONE_STS) | 240 | pm_runtime_mark_last_busy(arizona->dev); |
204 | break; | 241 | |
242 | return ret; | ||
243 | } | ||
244 | |||
245 | static int arizona_apply_hardware_patch(struct arizona* arizona) | ||
246 | { | ||
247 | unsigned int fll, sysclk; | ||
248 | int ret, err; | ||
249 | |||
250 | regcache_cache_bypass(arizona->regmap, true); | ||
251 | |||
252 | /* Cache existing FLL and SYSCLK settings */ | ||
253 | ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &fll); | ||
254 | if (ret != 0) { | ||
255 | dev_err(arizona->dev, "Failed to cache FLL settings: %d\n", | ||
256 | ret); | ||
257 | return ret; | ||
258 | } | ||
259 | ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &sysclk); | ||
260 | if (ret != 0) { | ||
261 | dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n", | ||
262 | ret); | ||
263 | return ret; | ||
205 | } | 264 | } |
206 | 265 | ||
207 | if (reg & ARIZONA_BOOT_DONE_STS) { | 266 | /* Start up SYSCLK using the FLL in free running mode */ |
208 | regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, | 267 | ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, |
209 | ARIZONA_BOOT_DONE_STS); | 268 | ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN); |
210 | } else { | 269 | if (ret != 0) { |
211 | dev_err(arizona->dev, "Device boot timed out: %x\n", reg); | 270 | dev_err(arizona->dev, |
212 | return -ETIMEDOUT; | 271 | "Failed to start FLL in freerunning mode: %d\n", |
272 | ret); | ||
273 | return ret; | ||
274 | } | ||
275 | ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5, | ||
276 | ARIZONA_FLL1_CLOCK_OK_STS, | ||
277 | ARIZONA_FLL1_CLOCK_OK_STS); | ||
278 | if (ret != 0) { | ||
279 | ret = -ETIMEDOUT; | ||
280 | goto err_fll; | ||
213 | } | 281 | } |
214 | 282 | ||
215 | pm_runtime_mark_last_busy(arizona->dev); | 283 | ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); |
284 | if (ret != 0) { | ||
285 | dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret); | ||
286 | goto err_fll; | ||
287 | } | ||
216 | 288 | ||
217 | return 0; | 289 | /* Start the write sequencer and wait for it to finish */ |
290 | ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, | ||
291 | ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160); | ||
292 | if (ret != 0) { | ||
293 | dev_err(arizona->dev, "Failed to start write sequencer: %d\n", | ||
294 | ret); | ||
295 | goto err_sysclk; | ||
296 | } | ||
297 | ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1, | ||
298 | ARIZONA_WSEQ_BUSY, 0); | ||
299 | if (ret != 0) { | ||
300 | regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, | ||
301 | ARIZONA_WSEQ_ABORT); | ||
302 | ret = -ETIMEDOUT; | ||
303 | } | ||
304 | |||
305 | err_sysclk: | ||
306 | err = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, sysclk); | ||
307 | if (err != 0) { | ||
308 | dev_err(arizona->dev, | ||
309 | "Failed to re-apply old SYSCLK settings: %d\n", | ||
310 | err); | ||
311 | } | ||
312 | |||
313 | err_fll: | ||
314 | err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, fll); | ||
315 | if (err != 0) { | ||
316 | dev_err(arizona->dev, | ||
317 | "Failed to re-apply old FLL settings: %d\n", | ||
318 | err); | ||
319 | } | ||
320 | |||
321 | regcache_cache_bypass(arizona->regmap, false); | ||
322 | |||
323 | if (ret != 0) | ||
324 | return ret; | ||
325 | else | ||
326 | return err; | ||
218 | } | 327 | } |
219 | 328 | ||
220 | #ifdef CONFIG_PM_RUNTIME | 329 | #ifdef CONFIG_PM_RUNTIME |
@@ -233,20 +342,44 @@ static int arizona_runtime_resume(struct device *dev) | |||
233 | 342 | ||
234 | regcache_cache_only(arizona->regmap, false); | 343 | regcache_cache_only(arizona->regmap, false); |
235 | 344 | ||
236 | ret = arizona_wait_for_boot(arizona); | 345 | switch (arizona->type) { |
237 | if (ret != 0) { | 346 | case WM5102: |
238 | regulator_disable(arizona->dcvdd); | 347 | ret = wm5102_patch(arizona); |
239 | return ret; | 348 | if (ret != 0) { |
349 | dev_err(arizona->dev, "Failed to apply patch: %d\n", | ||
350 | ret); | ||
351 | goto err; | ||
352 | } | ||
353 | |||
354 | ret = arizona_apply_hardware_patch(arizona); | ||
355 | if (ret != 0) { | ||
356 | dev_err(arizona->dev, | ||
357 | "Failed to apply hardware patch: %d\n", | ||
358 | ret); | ||
359 | goto err; | ||
360 | } | ||
361 | break; | ||
362 | default: | ||
363 | ret = arizona_wait_for_boot(arizona); | ||
364 | if (ret != 0) { | ||
365 | goto err; | ||
366 | } | ||
367 | |||
368 | break; | ||
240 | } | 369 | } |
241 | 370 | ||
242 | ret = regcache_sync(arizona->regmap); | 371 | ret = regcache_sync(arizona->regmap); |
243 | if (ret != 0) { | 372 | if (ret != 0) { |
244 | dev_err(arizona->dev, "Failed to restore register cache\n"); | 373 | dev_err(arizona->dev, "Failed to restore register cache\n"); |
245 | regulator_disable(arizona->dcvdd); | 374 | goto err; |
246 | return ret; | ||
247 | } | 375 | } |
248 | 376 | ||
249 | return 0; | 377 | return 0; |
378 | |||
379 | err: | ||
380 | regcache_cache_only(arizona->regmap, true); | ||
381 | regulator_disable(arizona->dcvdd); | ||
382 | return ret; | ||
250 | } | 383 | } |
251 | 384 | ||
252 | static int arizona_runtime_suspend(struct device *dev) | 385 | static int arizona_runtime_suspend(struct device *dev) |
@@ -371,6 +504,17 @@ int arizona_dev_init(struct arizona *arizona) | |||
371 | goto err_early; | 504 | goto err_early; |
372 | } | 505 | } |
373 | 506 | ||
507 | if (arizona->pdata.reset) { | ||
508 | /* Start out with /RESET low to put the chip into reset */ | ||
509 | ret = gpio_request_one(arizona->pdata.reset, | ||
510 | GPIOF_DIR_OUT | GPIOF_INIT_LOW, | ||
511 | "arizona /RESET"); | ||
512 | if (ret != 0) { | ||
513 | dev_err(dev, "Failed to request /RESET: %d\n", ret); | ||
514 | goto err_early; | ||
515 | } | ||
516 | } | ||
517 | |||
374 | ret = regulator_bulk_enable(arizona->num_core_supplies, | 518 | ret = regulator_bulk_enable(arizona->num_core_supplies, |
375 | arizona->core_supplies); | 519 | arizona->core_supplies); |
376 | if (ret != 0) { | 520 | if (ret != 0) { |
@@ -386,16 +530,8 @@ int arizona_dev_init(struct arizona *arizona) | |||
386 | } | 530 | } |
387 | 531 | ||
388 | if (arizona->pdata.reset) { | 532 | if (arizona->pdata.reset) { |
389 | /* Start out with /RESET low to put the chip into reset */ | ||
390 | ret = gpio_request_one(arizona->pdata.reset, | ||
391 | GPIOF_DIR_OUT | GPIOF_INIT_LOW, | ||
392 | "arizona /RESET"); | ||
393 | if (ret != 0) { | ||
394 | dev_err(dev, "Failed to request /RESET: %d\n", ret); | ||
395 | goto err_dcvdd; | ||
396 | } | ||
397 | |||
398 | gpio_set_value_cansleep(arizona->pdata.reset, 1); | 533 | gpio_set_value_cansleep(arizona->pdata.reset, 1); |
534 | msleep(1); | ||
399 | } | 535 | } |
400 | 536 | ||
401 | regcache_cache_only(arizona->regmap, false); | 537 | regcache_cache_only(arizona->regmap, false); |
@@ -424,6 +560,7 @@ int arizona_dev_init(struct arizona *arizona) | |||
424 | arizona->type = WM5102; | 560 | arizona->type = WM5102; |
425 | } | 561 | } |
426 | apply_patch = wm5102_patch; | 562 | apply_patch = wm5102_patch; |
563 | arizona->rev &= 0x7; | ||
427 | break; | 564 | break; |
428 | #endif | 565 | #endif |
429 | #ifdef CONFIG_MFD_WM5110 | 566 | #ifdef CONFIG_MFD_WM5110 |
@@ -454,6 +591,8 @@ int arizona_dev_init(struct arizona *arizona) | |||
454 | goto err_reset; | 591 | goto err_reset; |
455 | } | 592 | } |
456 | 593 | ||
594 | msleep(1); | ||
595 | |||
457 | ret = regcache_sync(arizona->regmap); | 596 | ret = regcache_sync(arizona->regmap); |
458 | if (ret != 0) { | 597 | if (ret != 0) { |
459 | dev_err(dev, "Failed to sync device: %d\n", ret); | 598 | dev_err(dev, "Failed to sync device: %d\n", ret); |
@@ -461,10 +600,24 @@ int arizona_dev_init(struct arizona *arizona) | |||
461 | } | 600 | } |
462 | } | 601 | } |
463 | 602 | ||
464 | ret = arizona_wait_for_boot(arizona); | 603 | switch (arizona->type) { |
465 | if (ret != 0) { | 604 | case WM5102: |
466 | dev_err(arizona->dev, "Device failed initial boot: %d\n", ret); | 605 | ret = regmap_read(arizona->regmap, 0x19, &val); |
467 | goto err_reset; | 606 | if (ret != 0) |
607 | dev_err(dev, | ||
608 | "Failed to check write sequencer state: %d\n", | ||
609 | ret); | ||
610 | else if (val & 0x01) | ||
611 | break; | ||
612 | /* Fall through */ | ||
613 | default: | ||
614 | ret = arizona_wait_for_boot(arizona); | ||
615 | if (ret != 0) { | ||
616 | dev_err(arizona->dev, | ||
617 | "Device failed initial boot: %d\n", ret); | ||
618 | goto err_reset; | ||
619 | } | ||
620 | break; | ||
468 | } | 621 | } |
469 | 622 | ||
470 | if (apply_patch) { | 623 | if (apply_patch) { |
@@ -474,6 +627,20 @@ int arizona_dev_init(struct arizona *arizona) | |||
474 | ret); | 627 | ret); |
475 | goto err_reset; | 628 | goto err_reset; |
476 | } | 629 | } |
630 | |||
631 | switch (arizona->type) { | ||
632 | case WM5102: | ||
633 | ret = arizona_apply_hardware_patch(arizona); | ||
634 | if (ret != 0) { | ||
635 | dev_err(arizona->dev, | ||
636 | "Failed to apply hardware patch: %d\n", | ||
637 | ret); | ||
638 | goto err_reset; | ||
639 | } | ||
640 | break; | ||
641 | default: | ||
642 | break; | ||
643 | } | ||
477 | } | 644 | } |
478 | 645 | ||
479 | for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { | 646 | for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { |
@@ -498,6 +665,7 @@ int arizona_dev_init(struct arizona *arizona) | |||
498 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, | 665 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, |
499 | ARIZONA_CLK_32K_SRC_MASK, | 666 | ARIZONA_CLK_32K_SRC_MASK, |
500 | arizona->pdata.clk32k_src - 1); | 667 | arizona->pdata.clk32k_src - 1); |
668 | arizona_clk32k_enable(arizona); | ||
501 | break; | 669 | break; |
502 | case ARIZONA_32KZ_NONE: | 670 | case ARIZONA_32KZ_NONE: |
503 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, | 671 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, |
@@ -511,10 +679,16 @@ int arizona_dev_init(struct arizona *arizona) | |||
511 | } | 679 | } |
512 | 680 | ||
513 | for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { | 681 | for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { |
514 | if (!arizona->pdata.micbias[i].mV) | 682 | if (!arizona->pdata.micbias[i].mV && |
683 | !arizona->pdata.micbias[i].bypass) | ||
515 | continue; | 684 | continue; |
516 | 685 | ||
686 | /* Apply default for bypass mode */ | ||
687 | if (!arizona->pdata.micbias[i].mV) | ||
688 | arizona->pdata.micbias[i].mV = 2800; | ||
689 | |||
517 | val = (arizona->pdata.micbias[i].mV - 1500) / 100; | 690 | val = (arizona->pdata.micbias[i].mV - 1500) / 100; |
691 | |||
518 | val <<= ARIZONA_MICB1_LVL_SHIFT; | 692 | val <<= ARIZONA_MICB1_LVL_SHIFT; |
519 | 693 | ||
520 | if (arizona->pdata.micbias[i].ext_cap) | 694 | if (arizona->pdata.micbias[i].ext_cap) |
@@ -526,10 +700,14 @@ int arizona_dev_init(struct arizona *arizona) | |||
526 | if (arizona->pdata.micbias[i].fast_start) | 700 | if (arizona->pdata.micbias[i].fast_start) |
527 | val |= ARIZONA_MICB1_RATE; | 701 | val |= ARIZONA_MICB1_RATE; |
528 | 702 | ||
703 | if (arizona->pdata.micbias[i].bypass) | ||
704 | val |= ARIZONA_MICB1_BYPASS; | ||
705 | |||
529 | regmap_update_bits(arizona->regmap, | 706 | regmap_update_bits(arizona->regmap, |
530 | ARIZONA_MIC_BIAS_CTRL_1 + i, | 707 | ARIZONA_MIC_BIAS_CTRL_1 + i, |
531 | ARIZONA_MICB1_LVL_MASK | | 708 | ARIZONA_MICB1_LVL_MASK | |
532 | ARIZONA_MICB1_DISCH | | 709 | ARIZONA_MICB1_DISCH | |
710 | ARIZONA_MICB1_BYPASS | | ||
533 | ARIZONA_MICB1_RATE, val); | 711 | ARIZONA_MICB1_RATE, val); |
534 | } | 712 | } |
535 | 713 | ||
@@ -610,10 +788,9 @@ err_irq: | |||
610 | arizona_irq_exit(arizona); | 788 | arizona_irq_exit(arizona); |
611 | err_reset: | 789 | err_reset: |
612 | if (arizona->pdata.reset) { | 790 | if (arizona->pdata.reset) { |
613 | gpio_set_value_cansleep(arizona->pdata.reset, 1); | 791 | gpio_set_value_cansleep(arizona->pdata.reset, 0); |
614 | gpio_free(arizona->pdata.reset); | 792 | gpio_free(arizona->pdata.reset); |
615 | } | 793 | } |
616 | err_dcvdd: | ||
617 | regulator_disable(arizona->dcvdd); | 794 | regulator_disable(arizona->dcvdd); |
618 | err_enable: | 795 | err_enable: |
619 | regulator_bulk_disable(arizona->num_core_supplies, | 796 | regulator_bulk_disable(arizona->num_core_supplies, |
diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index 2bec5f0db3ee..64cd9b6dac92 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c | |||
@@ -94,6 +94,7 @@ static irqreturn_t arizona_ctrlif_err(int irq, void *data) | |||
94 | static irqreturn_t arizona_irq_thread(int irq, void *data) | 94 | static irqreturn_t arizona_irq_thread(int irq, void *data) |
95 | { | 95 | { |
96 | struct arizona *arizona = data; | 96 | struct arizona *arizona = data; |
97 | bool poll; | ||
97 | unsigned int val; | 98 | unsigned int val; |
98 | int ret; | 99 | int ret; |
99 | 100 | ||
@@ -103,20 +104,39 @@ static irqreturn_t arizona_irq_thread(int irq, void *data) | |||
103 | return IRQ_NONE; | 104 | return IRQ_NONE; |
104 | } | 105 | } |
105 | 106 | ||
106 | /* Always handle the AoD domain */ | 107 | do { |
107 | handle_nested_irq(irq_find_mapping(arizona->virq, 0)); | 108 | poll = false; |
109 | |||
110 | /* Always handle the AoD domain */ | ||
111 | handle_nested_irq(irq_find_mapping(arizona->virq, 0)); | ||
112 | |||
113 | /* | ||
114 | * Check if one of the main interrupts is asserted and only | ||
115 | * check that domain if it is. | ||
116 | */ | ||
117 | ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS, | ||
118 | &val); | ||
119 | if (ret == 0 && val & ARIZONA_IRQ1_STS) { | ||
120 | handle_nested_irq(irq_find_mapping(arizona->virq, 1)); | ||
121 | } else if (ret != 0) { | ||
122 | dev_err(arizona->dev, | ||
123 | "Failed to read main IRQ status: %d\n", ret); | ||
124 | } | ||
108 | 125 | ||
109 | /* | 126 | /* |
110 | * Check if one of the main interrupts is asserted and only | 127 | * Poll the IRQ pin status to see if we're really done |
111 | * check that domain if it is. | 128 | * if the interrupt controller can't do it for us. |
112 | */ | 129 | */ |
113 | ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS, &val); | 130 | if (!arizona->pdata.irq_gpio) { |
114 | if (ret == 0 && val & ARIZONA_IRQ1_STS) { | 131 | break; |
115 | handle_nested_irq(irq_find_mapping(arizona->virq, 1)); | 132 | } else if (arizona->pdata.irq_flags & IRQF_TRIGGER_RISING && |
116 | } else if (ret != 0) { | 133 | gpio_get_value_cansleep(arizona->pdata.irq_gpio)) { |
117 | dev_err(arizona->dev, "Failed to read main IRQ status: %d\n", | 134 | poll = true; |
118 | ret); | 135 | } else if (arizona->pdata.irq_flags & IRQF_TRIGGER_FALLING && |
119 | } | 136 | !gpio_get_value_cansleep(arizona->pdata.irq_gpio)) { |
137 | poll = true; | ||
138 | } | ||
139 | } while (poll); | ||
120 | 140 | ||
121 | pm_runtime_mark_last_busy(arizona->dev); | 141 | pm_runtime_mark_last_busy(arizona->dev); |
122 | pm_runtime_put_autosuspend(arizona->dev); | 142 | pm_runtime_put_autosuspend(arizona->dev); |
@@ -169,6 +189,7 @@ int arizona_irq_init(struct arizona *arizona) | |||
169 | int ret, i; | 189 | int ret, i; |
170 | const struct regmap_irq_chip *aod, *irq; | 190 | const struct regmap_irq_chip *aod, *irq; |
171 | bool ctrlif_error = true; | 191 | bool ctrlif_error = true; |
192 | struct irq_data *irq_data; | ||
172 | 193 | ||
173 | switch (arizona->type) { | 194 | switch (arizona->type) { |
174 | #ifdef CONFIG_MFD_WM5102 | 195 | #ifdef CONFIG_MFD_WM5102 |
@@ -192,7 +213,36 @@ int arizona_irq_init(struct arizona *arizona) | |||
192 | return -EINVAL; | 213 | return -EINVAL; |
193 | } | 214 | } |
194 | 215 | ||
195 | if (arizona->pdata.irq_active_high) { | 216 | /* Disable all wake sources by default */ |
217 | regmap_write(arizona->regmap, ARIZONA_WAKE_CONTROL, 0); | ||
218 | |||
219 | /* Read the flags from the interrupt controller if not specified */ | ||
220 | if (!arizona->pdata.irq_flags) { | ||
221 | irq_data = irq_get_irq_data(arizona->irq); | ||
222 | if (!irq_data) { | ||
223 | dev_err(arizona->dev, "Invalid IRQ: %d\n", | ||
224 | arizona->irq); | ||
225 | return -EINVAL; | ||
226 | } | ||
227 | |||
228 | arizona->pdata.irq_flags = irqd_get_trigger_type(irq_data); | ||
229 | switch (arizona->pdata.irq_flags) { | ||
230 | case IRQF_TRIGGER_LOW: | ||
231 | case IRQF_TRIGGER_HIGH: | ||
232 | case IRQF_TRIGGER_RISING: | ||
233 | case IRQF_TRIGGER_FALLING: | ||
234 | break; | ||
235 | |||
236 | case IRQ_TYPE_NONE: | ||
237 | default: | ||
238 | /* Device default */ | ||
239 | arizona->pdata.irq_flags = IRQF_TRIGGER_LOW; | ||
240 | break; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | if (arizona->pdata.irq_flags & (IRQF_TRIGGER_HIGH | | ||
245 | IRQF_TRIGGER_RISING)) { | ||
196 | ret = regmap_update_bits(arizona->regmap, ARIZONA_IRQ_CTRL_1, | 246 | ret = regmap_update_bits(arizona->regmap, ARIZONA_IRQ_CTRL_1, |
197 | ARIZONA_IRQ_POL, 0); | 247 | ARIZONA_IRQ_POL, 0); |
198 | if (ret != 0) { | 248 | if (ret != 0) { |
@@ -200,12 +250,10 @@ int arizona_irq_init(struct arizona *arizona) | |||
200 | ret); | 250 | ret); |
201 | goto err; | 251 | goto err; |
202 | } | 252 | } |
203 | |||
204 | flags |= IRQF_TRIGGER_HIGH; | ||
205 | } else { | ||
206 | flags |= IRQF_TRIGGER_LOW; | ||
207 | } | 253 | } |
208 | 254 | ||
255 | flags |= arizona->pdata.irq_flags; | ||
256 | |||
209 | /* Allocate a virtual IRQ domain to distribute to the regmap domains */ | 257 | /* Allocate a virtual IRQ domain to distribute to the regmap domains */ |
210 | arizona->virq = irq_domain_add_linear(NULL, 2, &arizona_domain_ops, | 258 | arizona->virq = irq_domain_add_linear(NULL, 2, &arizona_domain_ops, |
211 | arizona); | 259 | arizona); |
@@ -257,11 +305,31 @@ int arizona_irq_init(struct arizona *arizona) | |||
257 | } | 305 | } |
258 | } | 306 | } |
259 | 307 | ||
308 | /* Used to emulate edge trigger and to work around broken pinmux */ | ||
309 | if (arizona->pdata.irq_gpio) { | ||
310 | if (gpio_to_irq(arizona->pdata.irq_gpio) != arizona->irq) { | ||
311 | dev_warn(arizona->dev, "IRQ %d is not GPIO %d (%d)\n", | ||
312 | arizona->irq, arizona->pdata.irq_gpio, | ||
313 | gpio_to_irq(arizona->pdata.irq_gpio)); | ||
314 | arizona->irq = gpio_to_irq(arizona->pdata.irq_gpio); | ||
315 | } | ||
316 | |||
317 | ret = devm_gpio_request_one(arizona->dev, | ||
318 | arizona->pdata.irq_gpio, | ||
319 | GPIOF_IN, "arizona IRQ"); | ||
320 | if (ret != 0) { | ||
321 | dev_err(arizona->dev, | ||
322 | "Failed to request IRQ GPIO %d:: %d\n", | ||
323 | arizona->pdata.irq_gpio, ret); | ||
324 | arizona->pdata.irq_gpio = 0; | ||
325 | } | ||
326 | } | ||
327 | |||
260 | ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread, | 328 | ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread, |
261 | flags, "arizona", arizona); | 329 | flags, "arizona", arizona); |
262 | 330 | ||
263 | if (ret != 0) { | 331 | if (ret != 0) { |
264 | dev_err(arizona->dev, "Failed to request IRQ %d: %d\n", | 332 | dev_err(arizona->dev, "Failed to request primary IRQ %d: %d\n", |
265 | arizona->irq, ret); | 333 | arizona->irq, ret); |
266 | goto err_main_irq; | 334 | goto err_main_irq; |
267 | } | 335 | } |
diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c index 1b9fdd698b03..b57e642d2b4a 100644 --- a/drivers/mfd/arizona-spi.c +++ b/drivers/mfd/arizona-spi.c | |||
@@ -67,7 +67,7 @@ static int arizona_spi_probe(struct spi_device *spi) | |||
67 | 67 | ||
68 | static int arizona_spi_remove(struct spi_device *spi) | 68 | static int arizona_spi_remove(struct spi_device *spi) |
69 | { | 69 | { |
70 | struct arizona *arizona = dev_get_drvdata(&spi->dev); | 70 | struct arizona *arizona = spi_get_drvdata(spi); |
71 | arizona_dev_exit(arizona); | 71 | arizona_dev_exit(arizona); |
72 | return 0; | 72 | return 0; |
73 | } | 73 | } |
diff --git a/drivers/mfd/as3711.c b/drivers/mfd/as3711.c index e994c9691124..01e414162702 100644 --- a/drivers/mfd/as3711.c +++ b/drivers/mfd/as3711.c | |||
@@ -112,16 +112,34 @@ static const struct regmap_config as3711_regmap_config = { | |||
112 | .cache_type = REGCACHE_RBTREE, | 112 | .cache_type = REGCACHE_RBTREE, |
113 | }; | 113 | }; |
114 | 114 | ||
115 | #ifdef CONFIG_OF | ||
116 | static struct of_device_id as3711_of_match[] = { | ||
117 | {.compatible = "ams,as3711",}, | ||
118 | {} | ||
119 | }; | ||
120 | MODULE_DEVICE_TABLE(of, as3711_of_match); | ||
121 | #endif | ||
122 | |||
115 | static int as3711_i2c_probe(struct i2c_client *client, | 123 | static int as3711_i2c_probe(struct i2c_client *client, |
116 | const struct i2c_device_id *id) | 124 | const struct i2c_device_id *id) |
117 | { | 125 | { |
118 | struct as3711 *as3711; | 126 | struct as3711 *as3711; |
119 | struct as3711_platform_data *pdata = client->dev.platform_data; | 127 | struct as3711_platform_data *pdata; |
120 | unsigned int id1, id2; | 128 | unsigned int id1, id2; |
121 | int ret; | 129 | int ret; |
122 | 130 | ||
123 | if (!pdata) | 131 | if (!client->dev.of_node) { |
124 | dev_dbg(&client->dev, "Platform data not found\n"); | 132 | pdata = client->dev.platform_data; |
133 | if (!pdata) | ||
134 | dev_dbg(&client->dev, "Platform data not found\n"); | ||
135 | } else { | ||
136 | pdata = devm_kzalloc(&client->dev, | ||
137 | sizeof(*pdata), GFP_KERNEL); | ||
138 | if (!pdata) { | ||
139 | dev_err(&client->dev, "Failed to allocate pdata\n"); | ||
140 | return -ENOMEM; | ||
141 | } | ||
142 | } | ||
125 | 143 | ||
126 | as3711 = devm_kzalloc(&client->dev, sizeof(struct as3711), GFP_KERNEL); | 144 | as3711 = devm_kzalloc(&client->dev, sizeof(struct as3711), GFP_KERNEL); |
127 | if (!as3711) { | 145 | if (!as3711) { |
@@ -193,7 +211,8 @@ static struct i2c_driver as3711_i2c_driver = { | |||
193 | .driver = { | 211 | .driver = { |
194 | .name = "as3711", | 212 | .name = "as3711", |
195 | .owner = THIS_MODULE, | 213 | .owner = THIS_MODULE, |
196 | }, | 214 | .of_match_table = of_match_ptr(as3711_of_match), |
215 | }, | ||
197 | .probe = as3711_i2c_probe, | 216 | .probe = as3711_i2c_probe, |
198 | .remove = as3711_i2c_remove, | 217 | .remove = as3711_i2c_remove, |
199 | .id_table = as3711_i2c_id, | 218 | .id_table = as3711_i2c_id, |
diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c new file mode 100644 index 000000000000..10cd14e35eb0 --- /dev/null +++ b/drivers/mfd/cros_ec.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * ChromeOS EC multi-function device | ||
3 | * | ||
4 | * Copyright (C) 2012 Google, Inc | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * The ChromeOS EC multi function device is used to mux all the requests | ||
16 | * to the EC device for its multiple features: keyboard controller, | ||
17 | * battery charging and regulator control, firmware update. | ||
18 | */ | ||
19 | |||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/mfd/core.h> | ||
24 | #include <linux/mfd/cros_ec.h> | ||
25 | #include <linux/mfd/cros_ec_commands.h> | ||
26 | |||
27 | int cros_ec_prepare_tx(struct cros_ec_device *ec_dev, | ||
28 | struct cros_ec_msg *msg) | ||
29 | { | ||
30 | uint8_t *out; | ||
31 | int csum, i; | ||
32 | |||
33 | BUG_ON(msg->out_len > EC_HOST_PARAM_SIZE); | ||
34 | out = ec_dev->dout; | ||
35 | out[0] = EC_CMD_VERSION0 + msg->version; | ||
36 | out[1] = msg->cmd; | ||
37 | out[2] = msg->out_len; | ||
38 | csum = out[0] + out[1] + out[2]; | ||
39 | for (i = 0; i < msg->out_len; i++) | ||
40 | csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->out_buf[i]; | ||
41 | out[EC_MSG_TX_HEADER_BYTES + msg->out_len] = (uint8_t)(csum & 0xff); | ||
42 | |||
43 | return EC_MSG_TX_PROTO_BYTES + msg->out_len; | ||
44 | } | ||
45 | EXPORT_SYMBOL(cros_ec_prepare_tx); | ||
46 | |||
47 | static int cros_ec_command_sendrecv(struct cros_ec_device *ec_dev, | ||
48 | uint16_t cmd, void *out_buf, int out_len, | ||
49 | void *in_buf, int in_len) | ||
50 | { | ||
51 | struct cros_ec_msg msg; | ||
52 | |||
53 | msg.version = cmd >> 8; | ||
54 | msg.cmd = cmd & 0xff; | ||
55 | msg.out_buf = out_buf; | ||
56 | msg.out_len = out_len; | ||
57 | msg.in_buf = in_buf; | ||
58 | msg.in_len = in_len; | ||
59 | |||
60 | return ec_dev->command_xfer(ec_dev, &msg); | ||
61 | } | ||
62 | |||
63 | static int cros_ec_command_recv(struct cros_ec_device *ec_dev, | ||
64 | uint16_t cmd, void *buf, int buf_len) | ||
65 | { | ||
66 | return cros_ec_command_sendrecv(ec_dev, cmd, NULL, 0, buf, buf_len); | ||
67 | } | ||
68 | |||
69 | static int cros_ec_command_send(struct cros_ec_device *ec_dev, | ||
70 | uint16_t cmd, void *buf, int buf_len) | ||
71 | { | ||
72 | return cros_ec_command_sendrecv(ec_dev, cmd, buf, buf_len, NULL, 0); | ||
73 | } | ||
74 | |||
75 | static irqreturn_t ec_irq_thread(int irq, void *data) | ||
76 | { | ||
77 | struct cros_ec_device *ec_dev = data; | ||
78 | |||
79 | if (device_may_wakeup(ec_dev->dev)) | ||
80 | pm_wakeup_event(ec_dev->dev, 0); | ||
81 | |||
82 | blocking_notifier_call_chain(&ec_dev->event_notifier, 1, ec_dev); | ||
83 | |||
84 | return IRQ_HANDLED; | ||
85 | } | ||
86 | |||
87 | static struct mfd_cell cros_devs[] = { | ||
88 | { | ||
89 | .name = "cros-ec-keyb", | ||
90 | .id = 1, | ||
91 | .of_compatible = "google,cros-ec-keyb", | ||
92 | }, | ||
93 | }; | ||
94 | |||
95 | int cros_ec_register(struct cros_ec_device *ec_dev) | ||
96 | { | ||
97 | struct device *dev = ec_dev->dev; | ||
98 | int err = 0; | ||
99 | |||
100 | BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->event_notifier); | ||
101 | |||
102 | ec_dev->command_send = cros_ec_command_send; | ||
103 | ec_dev->command_recv = cros_ec_command_recv; | ||
104 | ec_dev->command_sendrecv = cros_ec_command_sendrecv; | ||
105 | |||
106 | if (ec_dev->din_size) { | ||
107 | ec_dev->din = kmalloc(ec_dev->din_size, GFP_KERNEL); | ||
108 | if (!ec_dev->din) { | ||
109 | err = -ENOMEM; | ||
110 | goto fail_din; | ||
111 | } | ||
112 | } | ||
113 | if (ec_dev->dout_size) { | ||
114 | ec_dev->dout = kmalloc(ec_dev->dout_size, GFP_KERNEL); | ||
115 | if (!ec_dev->dout) { | ||
116 | err = -ENOMEM; | ||
117 | goto fail_dout; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | if (!ec_dev->irq) { | ||
122 | dev_dbg(dev, "no valid IRQ: %d\n", ec_dev->irq); | ||
123 | goto fail_irq; | ||
124 | } | ||
125 | |||
126 | err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread, | ||
127 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
128 | "chromeos-ec", ec_dev); | ||
129 | if (err) { | ||
130 | dev_err(dev, "request irq %d: error %d\n", ec_dev->irq, err); | ||
131 | goto fail_irq; | ||
132 | } | ||
133 | |||
134 | err = mfd_add_devices(dev, 0, cros_devs, | ||
135 | ARRAY_SIZE(cros_devs), | ||
136 | NULL, ec_dev->irq, NULL); | ||
137 | if (err) { | ||
138 | dev_err(dev, "failed to add mfd devices\n"); | ||
139 | goto fail_mfd; | ||
140 | } | ||
141 | |||
142 | dev_info(dev, "Chrome EC (%s)\n", ec_dev->name); | ||
143 | |||
144 | return 0; | ||
145 | |||
146 | fail_mfd: | ||
147 | free_irq(ec_dev->irq, ec_dev); | ||
148 | fail_irq: | ||
149 | kfree(ec_dev->dout); | ||
150 | fail_dout: | ||
151 | kfree(ec_dev->din); | ||
152 | fail_din: | ||
153 | return err; | ||
154 | } | ||
155 | EXPORT_SYMBOL(cros_ec_register); | ||
156 | |||
157 | int cros_ec_remove(struct cros_ec_device *ec_dev) | ||
158 | { | ||
159 | mfd_remove_devices(ec_dev->dev); | ||
160 | free_irq(ec_dev->irq, ec_dev); | ||
161 | kfree(ec_dev->dout); | ||
162 | kfree(ec_dev->din); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | EXPORT_SYMBOL(cros_ec_remove); | ||
167 | |||
168 | #ifdef CONFIG_PM_SLEEP | ||
169 | int cros_ec_suspend(struct cros_ec_device *ec_dev) | ||
170 | { | ||
171 | struct device *dev = ec_dev->dev; | ||
172 | |||
173 | if (device_may_wakeup(dev)) | ||
174 | ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq); | ||
175 | |||
176 | disable_irq(ec_dev->irq); | ||
177 | ec_dev->was_wake_device = ec_dev->wake_enabled; | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | EXPORT_SYMBOL(cros_ec_suspend); | ||
182 | |||
183 | int cros_ec_resume(struct cros_ec_device *ec_dev) | ||
184 | { | ||
185 | enable_irq(ec_dev->irq); | ||
186 | |||
187 | if (ec_dev->wake_enabled) { | ||
188 | disable_irq_wake(ec_dev->irq); | ||
189 | ec_dev->wake_enabled = 0; | ||
190 | } | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | EXPORT_SYMBOL(cros_ec_resume); | ||
195 | |||
196 | #endif | ||
diff --git a/drivers/mfd/cros_ec_i2c.c b/drivers/mfd/cros_ec_i2c.c new file mode 100644 index 000000000000..123044608b63 --- /dev/null +++ b/drivers/mfd/cros_ec_i2c.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /* | ||
2 | * ChromeOS EC multi-function device (I2C) | ||
3 | * | ||
4 | * Copyright (C) 2012 Google, Inc | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/mfd/cros_ec.h> | ||
21 | #include <linux/mfd/cros_ec_commands.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/slab.h> | ||
24 | |||
25 | static inline struct cros_ec_device *to_ec_dev(struct device *dev) | ||
26 | { | ||
27 | struct i2c_client *client = to_i2c_client(dev); | ||
28 | |||
29 | return i2c_get_clientdata(client); | ||
30 | } | ||
31 | |||
32 | static int cros_ec_command_xfer(struct cros_ec_device *ec_dev, | ||
33 | struct cros_ec_msg *msg) | ||
34 | { | ||
35 | struct i2c_client *client = ec_dev->priv; | ||
36 | int ret = -ENOMEM; | ||
37 | int i; | ||
38 | int packet_len; | ||
39 | u8 *out_buf = NULL; | ||
40 | u8 *in_buf = NULL; | ||
41 | u8 sum; | ||
42 | struct i2c_msg i2c_msg[2]; | ||
43 | |||
44 | i2c_msg[0].addr = client->addr; | ||
45 | i2c_msg[0].flags = 0; | ||
46 | i2c_msg[1].addr = client->addr; | ||
47 | i2c_msg[1].flags = I2C_M_RD; | ||
48 | |||
49 | /* | ||
50 | * allocate larger packet (one byte for checksum, one byte for | ||
51 | * length, and one for result code) | ||
52 | */ | ||
53 | packet_len = msg->in_len + 3; | ||
54 | in_buf = kzalloc(packet_len, GFP_KERNEL); | ||
55 | if (!in_buf) | ||
56 | goto done; | ||
57 | i2c_msg[1].len = packet_len; | ||
58 | i2c_msg[1].buf = (char *)in_buf; | ||
59 | |||
60 | /* | ||
61 | * allocate larger packet (one byte for checksum, one for | ||
62 | * command code, one for length, and one for command version) | ||
63 | */ | ||
64 | packet_len = msg->out_len + 4; | ||
65 | out_buf = kzalloc(packet_len, GFP_KERNEL); | ||
66 | if (!out_buf) | ||
67 | goto done; | ||
68 | i2c_msg[0].len = packet_len; | ||
69 | i2c_msg[0].buf = (char *)out_buf; | ||
70 | |||
71 | out_buf[0] = EC_CMD_VERSION0 + msg->version; | ||
72 | out_buf[1] = msg->cmd; | ||
73 | out_buf[2] = msg->out_len; | ||
74 | |||
75 | /* copy message payload and compute checksum */ | ||
76 | sum = out_buf[0] + out_buf[1] + out_buf[2]; | ||
77 | for (i = 0; i < msg->out_len; i++) { | ||
78 | out_buf[3 + i] = msg->out_buf[i]; | ||
79 | sum += out_buf[3 + i]; | ||
80 | } | ||
81 | out_buf[3 + msg->out_len] = sum; | ||
82 | |||
83 | /* send command to EC and read answer */ | ||
84 | ret = i2c_transfer(client->adapter, i2c_msg, 2); | ||
85 | if (ret < 0) { | ||
86 | dev_err(ec_dev->dev, "i2c transfer failed: %d\n", ret); | ||
87 | goto done; | ||
88 | } else if (ret != 2) { | ||
89 | dev_err(ec_dev->dev, "failed to get response: %d\n", ret); | ||
90 | ret = -EIO; | ||
91 | goto done; | ||
92 | } | ||
93 | |||
94 | /* check response error code */ | ||
95 | if (i2c_msg[1].buf[0]) { | ||
96 | dev_warn(ec_dev->dev, "command 0x%02x returned an error %d\n", | ||
97 | msg->cmd, i2c_msg[1].buf[0]); | ||
98 | ret = -EINVAL; | ||
99 | goto done; | ||
100 | } | ||
101 | |||
102 | /* copy response packet payload and compute checksum */ | ||
103 | sum = in_buf[0] + in_buf[1]; | ||
104 | for (i = 0; i < msg->in_len; i++) { | ||
105 | msg->in_buf[i] = in_buf[2 + i]; | ||
106 | sum += in_buf[2 + i]; | ||
107 | } | ||
108 | dev_dbg(ec_dev->dev, "packet: %*ph, sum = %02x\n", | ||
109 | i2c_msg[1].len, in_buf, sum); | ||
110 | if (sum != in_buf[2 + msg->in_len]) { | ||
111 | dev_err(ec_dev->dev, "bad packet checksum\n"); | ||
112 | ret = -EBADMSG; | ||
113 | goto done; | ||
114 | } | ||
115 | |||
116 | ret = 0; | ||
117 | done: | ||
118 | kfree(in_buf); | ||
119 | kfree(out_buf); | ||
120 | return ret; | ||
121 | } | ||
122 | |||
123 | static int cros_ec_probe_i2c(struct i2c_client *client, | ||
124 | const struct i2c_device_id *dev_id) | ||
125 | { | ||
126 | struct device *dev = &client->dev; | ||
127 | struct cros_ec_device *ec_dev = NULL; | ||
128 | int err; | ||
129 | |||
130 | ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL); | ||
131 | if (!ec_dev) | ||
132 | return -ENOMEM; | ||
133 | |||
134 | i2c_set_clientdata(client, ec_dev); | ||
135 | ec_dev->name = "I2C"; | ||
136 | ec_dev->dev = dev; | ||
137 | ec_dev->priv = client; | ||
138 | ec_dev->irq = client->irq; | ||
139 | ec_dev->command_xfer = cros_ec_command_xfer; | ||
140 | ec_dev->ec_name = client->name; | ||
141 | ec_dev->phys_name = client->adapter->name; | ||
142 | ec_dev->parent = &client->dev; | ||
143 | |||
144 | err = cros_ec_register(ec_dev); | ||
145 | if (err) { | ||
146 | dev_err(dev, "cannot register EC\n"); | ||
147 | return err; | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int cros_ec_remove_i2c(struct i2c_client *client) | ||
154 | { | ||
155 | struct cros_ec_device *ec_dev = i2c_get_clientdata(client); | ||
156 | |||
157 | cros_ec_remove(ec_dev); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | #ifdef CONFIG_PM_SLEEP | ||
163 | static int cros_ec_i2c_suspend(struct device *dev) | ||
164 | { | ||
165 | struct cros_ec_device *ec_dev = to_ec_dev(dev); | ||
166 | |||
167 | return cros_ec_suspend(ec_dev); | ||
168 | } | ||
169 | |||
170 | static int cros_ec_i2c_resume(struct device *dev) | ||
171 | { | ||
172 | struct cros_ec_device *ec_dev = to_ec_dev(dev); | ||
173 | |||
174 | return cros_ec_resume(ec_dev); | ||
175 | } | ||
176 | #endif | ||
177 | |||
178 | static SIMPLE_DEV_PM_OPS(cros_ec_i2c_pm_ops, cros_ec_i2c_suspend, | ||
179 | cros_ec_i2c_resume); | ||
180 | |||
181 | static const struct i2c_device_id cros_ec_i2c_id[] = { | ||
182 | { "cros-ec-i2c", 0 }, | ||
183 | { } | ||
184 | }; | ||
185 | MODULE_DEVICE_TABLE(i2c, cros_ec_i2c_id); | ||
186 | |||
187 | static struct i2c_driver cros_ec_driver = { | ||
188 | .driver = { | ||
189 | .name = "cros-ec-i2c", | ||
190 | .owner = THIS_MODULE, | ||
191 | .pm = &cros_ec_i2c_pm_ops, | ||
192 | }, | ||
193 | .probe = cros_ec_probe_i2c, | ||
194 | .remove = cros_ec_remove_i2c, | ||
195 | .id_table = cros_ec_i2c_id, | ||
196 | }; | ||
197 | |||
198 | module_i2c_driver(cros_ec_driver); | ||
199 | |||
200 | MODULE_LICENSE("GPL"); | ||
201 | MODULE_DESCRIPTION("ChromeOS EC multi function device"); | ||
diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c new file mode 100644 index 000000000000..19193cf1e7a1 --- /dev/null +++ b/drivers/mfd/cros_ec_spi.c | |||
@@ -0,0 +1,375 @@ | |||
1 | /* | ||
2 | * ChromeOS EC multi-function device (SPI) | ||
3 | * | ||
4 | * Copyright (C) 2012 Google, Inc | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/delay.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/mfd/cros_ec.h> | ||
20 | #include <linux/mfd/cros_ec_commands.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/spi/spi.h> | ||
24 | |||
25 | |||
26 | /* The header byte, which follows the preamble */ | ||
27 | #define EC_MSG_HEADER 0xec | ||
28 | |||
29 | /* | ||
30 | * Number of EC preamble bytes we read at a time. Since it takes | ||
31 | * about 400-500us for the EC to respond there is not a lot of | ||
32 | * point in tuning this. If the EC could respond faster then | ||
33 | * we could increase this so that might expect the preamble and | ||
34 | * message to occur in a single transaction. However, the maximum | ||
35 | * SPI transfer size is 256 bytes, so at 5MHz we need a response | ||
36 | * time of perhaps <320us (200 bytes / 1600 bits). | ||
37 | */ | ||
38 | #define EC_MSG_PREAMBLE_COUNT 32 | ||
39 | |||
40 | /* | ||
41 | * We must get a response from the EC in 5ms. This is a very long | ||
42 | * time, but the flash write command can take 2-3ms. The EC command | ||
43 | * processing is currently not very fast (about 500us). We could | ||
44 | * look at speeding this up and making the flash write command a | ||
45 | * 'slow' command, requiring a GET_STATUS wait loop, like flash | ||
46 | * erase. | ||
47 | */ | ||
48 | #define EC_MSG_DEADLINE_MS 5 | ||
49 | |||
50 | /* | ||
51 | * Time between raising the SPI chip select (for the end of a | ||
52 | * transaction) and dropping it again (for the next transaction). | ||
53 | * If we go too fast, the EC will miss the transaction. It seems | ||
54 | * that 50us is enough with the 16MHz STM32 EC. | ||
55 | */ | ||
56 | #define EC_SPI_RECOVERY_TIME_NS (50 * 1000) | ||
57 | |||
58 | /** | ||
59 | * struct cros_ec_spi - information about a SPI-connected EC | ||
60 | * | ||
61 | * @spi: SPI device we are connected to | ||
62 | * @last_transfer_ns: time that we last finished a transfer, or 0 if there | ||
63 | * if no record | ||
64 | */ | ||
65 | struct cros_ec_spi { | ||
66 | struct spi_device *spi; | ||
67 | s64 last_transfer_ns; | ||
68 | }; | ||
69 | |||
70 | static void debug_packet(struct device *dev, const char *name, u8 *ptr, | ||
71 | int len) | ||
72 | { | ||
73 | #ifdef DEBUG | ||
74 | int i; | ||
75 | |||
76 | dev_dbg(dev, "%s: ", name); | ||
77 | for (i = 0; i < len; i++) | ||
78 | dev_cont(dev, " %02x", ptr[i]); | ||
79 | #endif | ||
80 | } | ||
81 | |||
82 | /** | ||
83 | * cros_ec_spi_receive_response - Receive a response from the EC. | ||
84 | * | ||
85 | * This function has two phases: reading the preamble bytes (since if we read | ||
86 | * data from the EC before it is ready to send, we just get preamble) and | ||
87 | * reading the actual message. | ||
88 | * | ||
89 | * The received data is placed into ec_dev->din. | ||
90 | * | ||
91 | * @ec_dev: ChromeOS EC device | ||
92 | * @need_len: Number of message bytes we need to read | ||
93 | */ | ||
94 | static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, | ||
95 | int need_len) | ||
96 | { | ||
97 | struct cros_ec_spi *ec_spi = ec_dev->priv; | ||
98 | struct spi_transfer trans; | ||
99 | struct spi_message msg; | ||
100 | u8 *ptr, *end; | ||
101 | int ret; | ||
102 | unsigned long deadline; | ||
103 | int todo; | ||
104 | |||
105 | /* Receive data until we see the header byte */ | ||
106 | deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS); | ||
107 | do { | ||
108 | memset(&trans, '\0', sizeof(trans)); | ||
109 | trans.cs_change = 1; | ||
110 | trans.rx_buf = ptr = ec_dev->din; | ||
111 | trans.len = EC_MSG_PREAMBLE_COUNT; | ||
112 | |||
113 | spi_message_init(&msg); | ||
114 | spi_message_add_tail(&trans, &msg); | ||
115 | ret = spi_sync(ec_spi->spi, &msg); | ||
116 | if (ret < 0) { | ||
117 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
118 | return ret; | ||
119 | } | ||
120 | |||
121 | for (end = ptr + EC_MSG_PREAMBLE_COUNT; ptr != end; ptr++) { | ||
122 | if (*ptr == EC_MSG_HEADER) { | ||
123 | dev_dbg(ec_dev->dev, "msg found at %ld\n", | ||
124 | ptr - ec_dev->din); | ||
125 | break; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | if (time_after(jiffies, deadline)) { | ||
130 | dev_warn(ec_dev->dev, "EC failed to respond in time\n"); | ||
131 | return -ETIMEDOUT; | ||
132 | } | ||
133 | } while (ptr == end); | ||
134 | |||
135 | /* | ||
136 | * ptr now points to the header byte. Copy any valid data to the | ||
137 | * start of our buffer | ||
138 | */ | ||
139 | todo = end - ++ptr; | ||
140 | BUG_ON(todo < 0 || todo > ec_dev->din_size); | ||
141 | todo = min(todo, need_len); | ||
142 | memmove(ec_dev->din, ptr, todo); | ||
143 | ptr = ec_dev->din + todo; | ||
144 | dev_dbg(ec_dev->dev, "need %d, got %d bytes from preamble\n", | ||
145 | need_len, todo); | ||
146 | need_len -= todo; | ||
147 | |||
148 | /* Receive data until we have it all */ | ||
149 | while (need_len > 0) { | ||
150 | /* | ||
151 | * We can't support transfers larger than the SPI FIFO size | ||
152 | * unless we have DMA. We don't have DMA on the ISP SPI ports | ||
153 | * for Exynos. We need a way of asking SPI driver for | ||
154 | * maximum-supported transfer size. | ||
155 | */ | ||
156 | todo = min(need_len, 256); | ||
157 | dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%ld\n", | ||
158 | todo, need_len, ptr - ec_dev->din); | ||
159 | |||
160 | memset(&trans, '\0', sizeof(trans)); | ||
161 | trans.cs_change = 1; | ||
162 | trans.rx_buf = ptr; | ||
163 | trans.len = todo; | ||
164 | spi_message_init(&msg); | ||
165 | spi_message_add_tail(&trans, &msg); | ||
166 | |||
167 | /* send command to EC and read answer */ | ||
168 | BUG_ON((u8 *)trans.rx_buf - ec_dev->din + todo > | ||
169 | ec_dev->din_size); | ||
170 | ret = spi_sync(ec_spi->spi, &msg); | ||
171 | if (ret < 0) { | ||
172 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | debug_packet(ec_dev->dev, "interim", ptr, todo); | ||
177 | ptr += todo; | ||
178 | need_len -= todo; | ||
179 | } | ||
180 | |||
181 | dev_dbg(ec_dev->dev, "loop done, ptr=%ld\n", ptr - ec_dev->din); | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * cros_ec_command_spi_xfer - Transfer a message over SPI and receive the reply | ||
188 | * | ||
189 | * @ec_dev: ChromeOS EC device | ||
190 | * @ec_msg: Message to transfer | ||
191 | */ | ||
192 | static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, | ||
193 | struct cros_ec_msg *ec_msg) | ||
194 | { | ||
195 | struct cros_ec_spi *ec_spi = ec_dev->priv; | ||
196 | struct spi_transfer trans; | ||
197 | struct spi_message msg; | ||
198 | int i, len; | ||
199 | u8 *ptr; | ||
200 | int sum; | ||
201 | int ret = 0, final_ret; | ||
202 | struct timespec ts; | ||
203 | |||
204 | len = cros_ec_prepare_tx(ec_dev, ec_msg); | ||
205 | dev_dbg(ec_dev->dev, "prepared, len=%d\n", len); | ||
206 | |||
207 | /* If it's too soon to do another transaction, wait */ | ||
208 | if (ec_spi->last_transfer_ns) { | ||
209 | struct timespec ts; | ||
210 | unsigned long delay; /* The delay completed so far */ | ||
211 | |||
212 | ktime_get_ts(&ts); | ||
213 | delay = timespec_to_ns(&ts) - ec_spi->last_transfer_ns; | ||
214 | if (delay < EC_SPI_RECOVERY_TIME_NS) | ||
215 | ndelay(delay); | ||
216 | } | ||
217 | |||
218 | /* Transmit phase - send our message */ | ||
219 | debug_packet(ec_dev->dev, "out", ec_dev->dout, len); | ||
220 | memset(&trans, '\0', sizeof(trans)); | ||
221 | trans.tx_buf = ec_dev->dout; | ||
222 | trans.len = len; | ||
223 | trans.cs_change = 1; | ||
224 | spi_message_init(&msg); | ||
225 | spi_message_add_tail(&trans, &msg); | ||
226 | ret = spi_sync(ec_spi->spi, &msg); | ||
227 | |||
228 | /* Get the response */ | ||
229 | if (!ret) { | ||
230 | ret = cros_ec_spi_receive_response(ec_dev, | ||
231 | ec_msg->in_len + EC_MSG_TX_PROTO_BYTES); | ||
232 | } else { | ||
233 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
234 | } | ||
235 | |||
236 | /* turn off CS */ | ||
237 | spi_message_init(&msg); | ||
238 | final_ret = spi_sync(ec_spi->spi, &msg); | ||
239 | ktime_get_ts(&ts); | ||
240 | ec_spi->last_transfer_ns = timespec_to_ns(&ts); | ||
241 | if (!ret) | ||
242 | ret = final_ret; | ||
243 | if (ret < 0) { | ||
244 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
245 | return ret; | ||
246 | } | ||
247 | |||
248 | /* check response error code */ | ||
249 | ptr = ec_dev->din; | ||
250 | if (ptr[0]) { | ||
251 | dev_warn(ec_dev->dev, "command 0x%02x returned an error %d\n", | ||
252 | ec_msg->cmd, ptr[0]); | ||
253 | debug_packet(ec_dev->dev, "in_err", ptr, len); | ||
254 | return -EINVAL; | ||
255 | } | ||
256 | len = ptr[1]; | ||
257 | sum = ptr[0] + ptr[1]; | ||
258 | if (len > ec_msg->in_len) { | ||
259 | dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)", | ||
260 | len, ec_msg->in_len); | ||
261 | return -ENOSPC; | ||
262 | } | ||
263 | |||
264 | /* copy response packet payload and compute checksum */ | ||
265 | for (i = 0; i < len; i++) { | ||
266 | sum += ptr[i + 2]; | ||
267 | if (ec_msg->in_len) | ||
268 | ec_msg->in_buf[i] = ptr[i + 2]; | ||
269 | } | ||
270 | sum &= 0xff; | ||
271 | |||
272 | debug_packet(ec_dev->dev, "in", ptr, len + 3); | ||
273 | |||
274 | if (sum != ptr[len + 2]) { | ||
275 | dev_err(ec_dev->dev, | ||
276 | "bad packet checksum, expected %02x, got %02x\n", | ||
277 | sum, ptr[len + 2]); | ||
278 | return -EBADMSG; | ||
279 | } | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static int cros_ec_probe_spi(struct spi_device *spi) | ||
285 | { | ||
286 | struct device *dev = &spi->dev; | ||
287 | struct cros_ec_device *ec_dev; | ||
288 | struct cros_ec_spi *ec_spi; | ||
289 | int err; | ||
290 | |||
291 | spi->bits_per_word = 8; | ||
292 | spi->mode = SPI_MODE_0; | ||
293 | err = spi_setup(spi); | ||
294 | if (err < 0) | ||
295 | return err; | ||
296 | |||
297 | ec_spi = devm_kzalloc(dev, sizeof(*ec_spi), GFP_KERNEL); | ||
298 | if (ec_spi == NULL) | ||
299 | return -ENOMEM; | ||
300 | ec_spi->spi = spi; | ||
301 | ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL); | ||
302 | if (!ec_dev) | ||
303 | return -ENOMEM; | ||
304 | |||
305 | spi_set_drvdata(spi, ec_dev); | ||
306 | ec_dev->name = "SPI"; | ||
307 | ec_dev->dev = dev; | ||
308 | ec_dev->priv = ec_spi; | ||
309 | ec_dev->irq = spi->irq; | ||
310 | ec_dev->command_xfer = cros_ec_command_spi_xfer; | ||
311 | ec_dev->ec_name = ec_spi->spi->modalias; | ||
312 | ec_dev->phys_name = dev_name(&ec_spi->spi->dev); | ||
313 | ec_dev->parent = &ec_spi->spi->dev; | ||
314 | ec_dev->din_size = EC_MSG_BYTES + EC_MSG_PREAMBLE_COUNT; | ||
315 | ec_dev->dout_size = EC_MSG_BYTES; | ||
316 | |||
317 | err = cros_ec_register(ec_dev); | ||
318 | if (err) { | ||
319 | dev_err(dev, "cannot register EC\n"); | ||
320 | return err; | ||
321 | } | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static int cros_ec_remove_spi(struct spi_device *spi) | ||
327 | { | ||
328 | struct cros_ec_device *ec_dev; | ||
329 | |||
330 | ec_dev = spi_get_drvdata(spi); | ||
331 | cros_ec_remove(ec_dev); | ||
332 | |||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | #ifdef CONFIG_PM_SLEEP | ||
337 | static int cros_ec_spi_suspend(struct device *dev) | ||
338 | { | ||
339 | struct cros_ec_device *ec_dev = dev_get_drvdata(dev); | ||
340 | |||
341 | return cros_ec_suspend(ec_dev); | ||
342 | } | ||
343 | |||
344 | static int cros_ec_spi_resume(struct device *dev) | ||
345 | { | ||
346 | struct cros_ec_device *ec_dev = dev_get_drvdata(dev); | ||
347 | |||
348 | return cros_ec_resume(ec_dev); | ||
349 | } | ||
350 | #endif | ||
351 | |||
352 | static SIMPLE_DEV_PM_OPS(cros_ec_spi_pm_ops, cros_ec_spi_suspend, | ||
353 | cros_ec_spi_resume); | ||
354 | |||
355 | static const struct spi_device_id cros_ec_spi_id[] = { | ||
356 | { "cros-ec-spi", 0 }, | ||
357 | { } | ||
358 | }; | ||
359 | MODULE_DEVICE_TABLE(spi, cros_ec_spi_id); | ||
360 | |||
361 | static struct spi_driver cros_ec_driver_spi = { | ||
362 | .driver = { | ||
363 | .name = "cros-ec-spi", | ||
364 | .owner = THIS_MODULE, | ||
365 | .pm = &cros_ec_spi_pm_ops, | ||
366 | }, | ||
367 | .probe = cros_ec_probe_spi, | ||
368 | .remove = cros_ec_remove_spi, | ||
369 | .id_table = cros_ec_spi_id, | ||
370 | }; | ||
371 | |||
372 | module_spi_driver(cros_ec_driver_spi); | ||
373 | |||
374 | MODULE_LICENSE("GPL"); | ||
375 | MODULE_DESCRIPTION("ChromeOS EC multi function device (SPI)"); | ||
diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index 05176cd2862b..f1a316e0d6a6 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c | |||
@@ -499,7 +499,8 @@ static int da903x_probe(struct i2c_client *client, | |||
499 | unsigned int tmp; | 499 | unsigned int tmp; |
500 | int ret; | 500 | int ret; |
501 | 501 | ||
502 | chip = kzalloc(sizeof(struct da903x_chip), GFP_KERNEL); | 502 | chip = devm_kzalloc(&client->dev, sizeof(struct da903x_chip), |
503 | GFP_KERNEL); | ||
503 | if (chip == NULL) | 504 | if (chip == NULL) |
504 | return -ENOMEM; | 505 | return -ENOMEM; |
505 | 506 | ||
@@ -515,33 +516,27 @@ static int da903x_probe(struct i2c_client *client, | |||
515 | 516 | ||
516 | ret = chip->ops->init_chip(chip); | 517 | ret = chip->ops->init_chip(chip); |
517 | if (ret) | 518 | if (ret) |
518 | goto out_free_chip; | 519 | return ret; |
519 | 520 | ||
520 | /* mask and clear all IRQs */ | 521 | /* mask and clear all IRQs */ |
521 | chip->events_mask = 0xffffffff; | 522 | chip->events_mask = 0xffffffff; |
522 | chip->ops->mask_events(chip, chip->events_mask); | 523 | chip->ops->mask_events(chip, chip->events_mask); |
523 | chip->ops->read_events(chip, &tmp); | 524 | chip->ops->read_events(chip, &tmp); |
524 | 525 | ||
525 | ret = request_irq(client->irq, da903x_irq_handler, | 526 | ret = devm_request_irq(&client->dev, client->irq, da903x_irq_handler, |
526 | IRQF_TRIGGER_FALLING, | 527 | IRQF_TRIGGER_FALLING, |
527 | "da903x", chip); | 528 | "da903x", chip); |
528 | if (ret) { | 529 | if (ret) { |
529 | dev_err(&client->dev, "failed to request irq %d\n", | 530 | dev_err(&client->dev, "failed to request irq %d\n", |
530 | client->irq); | 531 | client->irq); |
531 | goto out_free_chip; | 532 | return ret; |
532 | } | 533 | } |
533 | 534 | ||
534 | ret = da903x_add_subdevs(chip, pdata); | 535 | ret = da903x_add_subdevs(chip, pdata); |
535 | if (ret) | 536 | if (ret) |
536 | goto out_free_irq; | 537 | return ret; |
537 | 538 | ||
538 | return 0; | 539 | return 0; |
539 | |||
540 | out_free_irq: | ||
541 | free_irq(client->irq, chip); | ||
542 | out_free_chip: | ||
543 | kfree(chip); | ||
544 | return ret; | ||
545 | } | 540 | } |
546 | 541 | ||
547 | static int da903x_remove(struct i2c_client *client) | 542 | static int da903x_remove(struct i2c_client *client) |
@@ -549,8 +544,6 @@ static int da903x_remove(struct i2c_client *client) | |||
549 | struct da903x_chip *chip = i2c_get_clientdata(client); | 544 | struct da903x_chip *chip = i2c_get_clientdata(client); |
550 | 545 | ||
551 | da903x_remove_subdevs(chip); | 546 | da903x_remove_subdevs(chip); |
552 | free_irq(client->irq, chip); | ||
553 | kfree(chip); | ||
554 | return 0; | 547 | return 0; |
555 | } | 548 | } |
556 | 549 | ||
diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c index 61d63b93576c..0680bcbc53de 100644 --- a/drivers/mfd/da9052-spi.c +++ b/drivers/mfd/da9052-spi.c | |||
@@ -38,7 +38,7 @@ static int da9052_spi_probe(struct spi_device *spi) | |||
38 | da9052->dev = &spi->dev; | 38 | da9052->dev = &spi->dev; |
39 | da9052->chip_irq = spi->irq; | 39 | da9052->chip_irq = spi->irq; |
40 | 40 | ||
41 | dev_set_drvdata(&spi->dev, da9052); | 41 | spi_set_drvdata(spi, da9052); |
42 | 42 | ||
43 | da9052_regmap_config.read_flag_mask = 1; | 43 | da9052_regmap_config.read_flag_mask = 1; |
44 | da9052_regmap_config.write_flag_mask = 0; | 44 | da9052_regmap_config.write_flag_mask = 0; |
@@ -60,7 +60,7 @@ static int da9052_spi_probe(struct spi_device *spi) | |||
60 | 60 | ||
61 | static int da9052_spi_remove(struct spi_device *spi) | 61 | static int da9052_spi_remove(struct spi_device *spi) |
62 | { | 62 | { |
63 | struct da9052 *da9052 = dev_get_drvdata(&spi->dev); | 63 | struct da9052 *da9052 = spi_get_drvdata(spi); |
64 | 64 | ||
65 | da9052_device_exit(da9052); | 65 | da9052_device_exit(da9052); |
66 | return 0; | 66 | return 0; |
diff --git a/drivers/mfd/da9055-core.c b/drivers/mfd/da9055-core.c index f56a1a9f7777..49cb23d37469 100644 --- a/drivers/mfd/da9055-core.c +++ b/drivers/mfd/da9055-core.c | |||
@@ -391,7 +391,7 @@ int da9055_device_init(struct da9055 *da9055) | |||
391 | da9055->irq_base = pdata->irq_base; | 391 | da9055->irq_base = pdata->irq_base; |
392 | 392 | ||
393 | ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq, | 393 | ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq, |
394 | IRQF_TRIGGER_HIGH | IRQF_ONESHOT, | 394 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
395 | da9055->irq_base, &da9055_regmap_irq_chip, | 395 | da9055->irq_base, &da9055_regmap_irq_chip, |
396 | &da9055->irq_data); | 396 | &da9055->irq_data); |
397 | if (ret < 0) | 397 | if (ret < 0) |
diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c index c0bcc872af4e..c60ab0c3c4db 100644 --- a/drivers/mfd/davinci_voicecodec.c +++ b/drivers/mfd/davinci_voicecodec.c | |||
@@ -177,17 +177,7 @@ static struct platform_driver davinci_vc_driver = { | |||
177 | .remove = davinci_vc_remove, | 177 | .remove = davinci_vc_remove, |
178 | }; | 178 | }; |
179 | 179 | ||
180 | static int __init davinci_vc_init(void) | 180 | module_platform_driver_probe(davinci_vc_driver, davinci_vc_probe); |
181 | { | ||
182 | return platform_driver_probe(&davinci_vc_driver, davinci_vc_probe); | ||
183 | } | ||
184 | module_init(davinci_vc_init); | ||
185 | |||
186 | static void __exit davinci_vc_exit(void) | ||
187 | { | ||
188 | platform_driver_unregister(&davinci_vc_driver); | ||
189 | } | ||
190 | module_exit(davinci_vc_exit); | ||
191 | 181 | ||
192 | MODULE_AUTHOR("Miguel Aguilar"); | 182 | MODULE_AUTHOR("Miguel Aguilar"); |
193 | MODULE_DESCRIPTION("Texas Instruments DaVinci Voice Codec Core Interface"); | 183 | MODULE_DESCRIPTION("Texas Instruments DaVinci Voice Codec Core Interface"); |
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 21434beb420a..319b8abe742b 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/jiffies.h> | 24 | #include <linux/jiffies.h> |
25 | #include <linux/bitops.h> | 25 | #include <linux/bitops.h> |
26 | #include <linux/fs.h> | 26 | #include <linux/fs.h> |
27 | #include <linux/of.h> | ||
27 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
28 | #include <linux/uaccess.h> | 29 | #include <linux/uaccess.h> |
29 | #include <linux/mfd/core.h> | 30 | #include <linux/mfd/core.h> |
@@ -2704,6 +2705,7 @@ static void dbx500_fw_version_init(struct platform_device *pdev, | |||
2704 | { | 2705 | { |
2705 | struct resource *res; | 2706 | struct resource *res; |
2706 | void __iomem *tcpm_base; | 2707 | void __iomem *tcpm_base; |
2708 | u32 version; | ||
2707 | 2709 | ||
2708 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | 2710 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
2709 | "prcmu-tcpm"); | 2711 | "prcmu-tcpm"); |
@@ -2713,26 +2715,27 @@ static void dbx500_fw_version_init(struct platform_device *pdev, | |||
2713 | return; | 2715 | return; |
2714 | } | 2716 | } |
2715 | tcpm_base = ioremap(res->start, resource_size(res)); | 2717 | tcpm_base = ioremap(res->start, resource_size(res)); |
2716 | if (tcpm_base != NULL) { | 2718 | if (!tcpm_base) { |
2717 | u32 version; | 2719 | dev_err(&pdev->dev, "no prcmu tcpm mem region provided\n"); |
2718 | 2720 | return; | |
2719 | version = readl(tcpm_base + version_offset); | ||
2720 | fw_info.version.project = (version & 0xFF); | ||
2721 | fw_info.version.api_version = (version >> 8) & 0xFF; | ||
2722 | fw_info.version.func_version = (version >> 16) & 0xFF; | ||
2723 | fw_info.version.errata = (version >> 24) & 0xFF; | ||
2724 | strncpy(fw_info.version.project_name, | ||
2725 | fw_project_name(fw_info.version.project), | ||
2726 | PRCMU_FW_PROJECT_NAME_LEN); | ||
2727 | fw_info.valid = true; | ||
2728 | pr_info("PRCMU firmware: %s(%d), version %d.%d.%d\n", | ||
2729 | fw_info.version.project_name, | ||
2730 | fw_info.version.project, | ||
2731 | fw_info.version.api_version, | ||
2732 | fw_info.version.func_version, | ||
2733 | fw_info.version.errata); | ||
2734 | iounmap(tcpm_base); | ||
2735 | } | 2721 | } |
2722 | |||
2723 | version = readl(tcpm_base + version_offset); | ||
2724 | fw_info.version.project = (version & 0xFF); | ||
2725 | fw_info.version.api_version = (version >> 8) & 0xFF; | ||
2726 | fw_info.version.func_version = (version >> 16) & 0xFF; | ||
2727 | fw_info.version.errata = (version >> 24) & 0xFF; | ||
2728 | strncpy(fw_info.version.project_name, | ||
2729 | fw_project_name(fw_info.version.project), | ||
2730 | PRCMU_FW_PROJECT_NAME_LEN); | ||
2731 | fw_info.valid = true; | ||
2732 | pr_info("PRCMU firmware: %s(%d), version %d.%d.%d\n", | ||
2733 | fw_info.version.project_name, | ||
2734 | fw_info.version.project, | ||
2735 | fw_info.version.api_version, | ||
2736 | fw_info.version.func_version, | ||
2737 | fw_info.version.errata); | ||
2738 | iounmap(tcpm_base); | ||
2736 | } | 2739 | } |
2737 | 2740 | ||
2738 | void __init db8500_prcmu_early_init(u32 phy_base, u32 size) | 2741 | void __init db8500_prcmu_early_init(u32 phy_base, u32 size) |
@@ -3065,6 +3068,15 @@ static struct db8500_thsens_platform_data db8500_thsens_data = { | |||
3065 | .num_trips = 4, | 3068 | .num_trips = 4, |
3066 | }; | 3069 | }; |
3067 | 3070 | ||
3071 | static struct mfd_cell common_prcmu_devs[] = { | ||
3072 | { | ||
3073 | .name = "ux500_wdt", | ||
3074 | .platform_data = &db8500_wdt_pdata, | ||
3075 | .pdata_size = sizeof(db8500_wdt_pdata), | ||
3076 | .id = -1, | ||
3077 | }, | ||
3078 | }; | ||
3079 | |||
3068 | static struct mfd_cell db8500_prcmu_devs[] = { | 3080 | static struct mfd_cell db8500_prcmu_devs[] = { |
3069 | { | 3081 | { |
3070 | .name = "db8500-prcmu-regulators", | 3082 | .name = "db8500-prcmu-regulators", |
@@ -3079,12 +3091,6 @@ static struct mfd_cell db8500_prcmu_devs[] = { | |||
3079 | .pdata_size = sizeof(db8500_cpufreq_table), | 3091 | .pdata_size = sizeof(db8500_cpufreq_table), |
3080 | }, | 3092 | }, |
3081 | { | 3093 | { |
3082 | .name = "ux500_wdt", | ||
3083 | .platform_data = &db8500_wdt_pdata, | ||
3084 | .pdata_size = sizeof(db8500_wdt_pdata), | ||
3085 | .id = -1, | ||
3086 | }, | ||
3087 | { | ||
3088 | .name = "db8500-thermal", | 3094 | .name = "db8500-thermal", |
3089 | .num_resources = ARRAY_SIZE(db8500_thsens_resources), | 3095 | .num_resources = ARRAY_SIZE(db8500_thsens_resources), |
3090 | .resources = db8500_thsens_resources, | 3096 | .resources = db8500_thsens_resources, |
@@ -3173,13 +3179,25 @@ static int db8500_prcmu_probe(struct platform_device *pdev) | |||
3173 | 3179 | ||
3174 | db8500_prcmu_update_cpufreq(); | 3180 | db8500_prcmu_update_cpufreq(); |
3175 | 3181 | ||
3176 | err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs, | 3182 | err = mfd_add_devices(&pdev->dev, 0, common_prcmu_devs, |
3177 | ARRAY_SIZE(db8500_prcmu_devs), NULL, 0, db8500_irq_domain); | 3183 | ARRAY_SIZE(common_prcmu_devs), NULL, 0, db8500_irq_domain); |
3178 | if (err) { | 3184 | if (err) { |
3179 | pr_err("prcmu: Failed to add subdevices\n"); | 3185 | pr_err("prcmu: Failed to add subdevices\n"); |
3180 | return err; | 3186 | return err; |
3181 | } | 3187 | } |
3182 | 3188 | ||
3189 | /* TODO: Remove restriction when clk definitions are available. */ | ||
3190 | if (!of_machine_is_compatible("st-ericsson,u8540")) { | ||
3191 | err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs, | ||
3192 | ARRAY_SIZE(db8500_prcmu_devs), NULL, 0, | ||
3193 | db8500_irq_domain); | ||
3194 | if (err) { | ||
3195 | mfd_remove_devices(&pdev->dev); | ||
3196 | pr_err("prcmu: Failed to add subdevices\n"); | ||
3197 | goto no_irq_return; | ||
3198 | } | ||
3199 | } | ||
3200 | |||
3183 | err = db8500_prcmu_register_ab8500(&pdev->dev, pdata->ab_platdata, | 3201 | err = db8500_prcmu_register_ab8500(&pdev->dev, pdata->ab_platdata, |
3184 | pdata->ab_irq); | 3202 | pdata->ab_irq); |
3185 | if (err) { | 3203 | if (err) { |
diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index b7a61f0f27a4..5502106ad515 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c | |||
@@ -393,7 +393,7 @@ static int pcap_add_subdev(struct pcap_chip *pcap, | |||
393 | 393 | ||
394 | static int ezx_pcap_remove(struct spi_device *spi) | 394 | static int ezx_pcap_remove(struct spi_device *spi) |
395 | { | 395 | { |
396 | struct pcap_chip *pcap = dev_get_drvdata(&spi->dev); | 396 | struct pcap_chip *pcap = spi_get_drvdata(spi); |
397 | struct pcap_platform_data *pdata = spi->dev.platform_data; | 397 | struct pcap_platform_data *pdata = spi->dev.platform_data; |
398 | int i, adc_irq; | 398 | int i, adc_irq; |
399 | 399 | ||
@@ -403,7 +403,7 @@ static int ezx_pcap_remove(struct spi_device *spi) | |||
403 | /* cleanup ADC */ | 403 | /* cleanup ADC */ |
404 | adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? | 404 | adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? |
405 | PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE); | 405 | PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE); |
406 | free_irq(adc_irq, pcap); | 406 | devm_free_irq(&spi->dev, adc_irq, pcap); |
407 | mutex_lock(&pcap->adc_mutex); | 407 | mutex_lock(&pcap->adc_mutex); |
408 | for (i = 0; i < PCAP_ADC_MAXQ; i++) | 408 | for (i = 0; i < PCAP_ADC_MAXQ; i++) |
409 | kfree(pcap->adc_queue[i]); | 409 | kfree(pcap->adc_queue[i]); |
@@ -415,8 +415,6 @@ static int ezx_pcap_remove(struct spi_device *spi) | |||
415 | 415 | ||
416 | destroy_workqueue(pcap->workqueue); | 416 | destroy_workqueue(pcap->workqueue); |
417 | 417 | ||
418 | kfree(pcap); | ||
419 | |||
420 | return 0; | 418 | return 0; |
421 | } | 419 | } |
422 | 420 | ||
@@ -431,7 +429,7 @@ static int ezx_pcap_probe(struct spi_device *spi) | |||
431 | if (!pdata) | 429 | if (!pdata) |
432 | goto ret; | 430 | goto ret; |
433 | 431 | ||
434 | pcap = kzalloc(sizeof(*pcap), GFP_KERNEL); | 432 | pcap = devm_kzalloc(&spi->dev, sizeof(*pcap), GFP_KERNEL); |
435 | if (!pcap) { | 433 | if (!pcap) { |
436 | ret = -ENOMEM; | 434 | ret = -ENOMEM; |
437 | goto ret; | 435 | goto ret; |
@@ -441,14 +439,14 @@ static int ezx_pcap_probe(struct spi_device *spi) | |||
441 | mutex_init(&pcap->adc_mutex); | 439 | mutex_init(&pcap->adc_mutex); |
442 | INIT_WORK(&pcap->isr_work, pcap_isr_work); | 440 | INIT_WORK(&pcap->isr_work, pcap_isr_work); |
443 | INIT_WORK(&pcap->msr_work, pcap_msr_work); | 441 | INIT_WORK(&pcap->msr_work, pcap_msr_work); |
444 | dev_set_drvdata(&spi->dev, pcap); | 442 | spi_set_drvdata(spi, pcap); |
445 | 443 | ||
446 | /* setup spi */ | 444 | /* setup spi */ |
447 | spi->bits_per_word = 32; | 445 | spi->bits_per_word = 32; |
448 | spi->mode = SPI_MODE_0 | (pdata->config & PCAP_CS_AH ? SPI_CS_HIGH : 0); | 446 | spi->mode = SPI_MODE_0 | (pdata->config & PCAP_CS_AH ? SPI_CS_HIGH : 0); |
449 | ret = spi_setup(spi); | 447 | ret = spi_setup(spi); |
450 | if (ret) | 448 | if (ret) |
451 | goto free_pcap; | 449 | goto ret; |
452 | 450 | ||
453 | pcap->spi = spi; | 451 | pcap->spi = spi; |
454 | 452 | ||
@@ -458,7 +456,7 @@ static int ezx_pcap_probe(struct spi_device *spi) | |||
458 | if (!pcap->workqueue) { | 456 | if (!pcap->workqueue) { |
459 | ret = -ENOMEM; | 457 | ret = -ENOMEM; |
460 | dev_err(&spi->dev, "can't create pcap thread\n"); | 458 | dev_err(&spi->dev, "can't create pcap thread\n"); |
461 | goto free_pcap; | 459 | goto ret; |
462 | } | 460 | } |
463 | 461 | ||
464 | /* redirect interrupts to AP, except adcdone2 */ | 462 | /* redirect interrupts to AP, except adcdone2 */ |
@@ -491,7 +489,8 @@ static int ezx_pcap_probe(struct spi_device *spi) | |||
491 | adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? | 489 | adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? |
492 | PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE); | 490 | PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE); |
493 | 491 | ||
494 | ret = request_irq(adc_irq, pcap_adc_irq, 0, "ADC", pcap); | 492 | ret = devm_request_irq(&spi->dev, adc_irq, pcap_adc_irq, 0, "ADC", |
493 | pcap); | ||
495 | if (ret) | 494 | if (ret) |
496 | goto free_irqchip; | 495 | goto free_irqchip; |
497 | 496 | ||
@@ -511,14 +510,12 @@ static int ezx_pcap_probe(struct spi_device *spi) | |||
511 | remove_subdevs: | 510 | remove_subdevs: |
512 | device_for_each_child(&spi->dev, NULL, pcap_remove_subdev); | 511 | device_for_each_child(&spi->dev, NULL, pcap_remove_subdev); |
513 | /* free_adc: */ | 512 | /* free_adc: */ |
514 | free_irq(adc_irq, pcap); | 513 | devm_free_irq(&spi->dev, adc_irq, pcap); |
515 | free_irqchip: | 514 | free_irqchip: |
516 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) | 515 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) |
517 | irq_set_chip_and_handler(i, NULL, NULL); | 516 | irq_set_chip_and_handler(i, NULL, NULL); |
518 | /* destroy_workqueue: */ | 517 | /* destroy_workqueue: */ |
519 | destroy_workqueue(pcap->workqueue); | 518 | destroy_workqueue(pcap->workqueue); |
520 | free_pcap: | ||
521 | kfree(pcap); | ||
522 | ret: | 519 | ret: |
523 | return ret; | 520 | return ret; |
524 | } | 521 | } |
diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index 9e5453d21a68..0285fceb99a6 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c | |||
@@ -208,18 +208,7 @@ static struct platform_driver pasic3_driver = { | |||
208 | .remove = pasic3_remove, | 208 | .remove = pasic3_remove, |
209 | }; | 209 | }; |
210 | 210 | ||
211 | static int __init pasic3_base_init(void) | 211 | module_platform_driver_probe(pasic3_driver, pasic3_probe); |
212 | { | ||
213 | return platform_driver_probe(&pasic3_driver, pasic3_probe); | ||
214 | } | ||
215 | |||
216 | static void __exit pasic3_base_exit(void) | ||
217 | { | ||
218 | platform_driver_unregister(&pasic3_driver); | ||
219 | } | ||
220 | |||
221 | module_init(pasic3_base_init); | ||
222 | module_exit(pasic3_base_exit); | ||
223 | 212 | ||
224 | MODULE_AUTHOR("Philipp Zabel <philipp.zabel@gmail.com>"); | 213 | MODULE_AUTHOR("Philipp Zabel <philipp.zabel@gmail.com>"); |
225 | MODULE_DESCRIPTION("Core driver for HTC PASIC3"); | 214 | MODULE_DESCRIPTION("Core driver for HTC PASIC3"); |
diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c index 1804331bd52c..5be3b5e13855 100644 --- a/drivers/mfd/intel_msic.c +++ b/drivers/mfd/intel_msic.c | |||
@@ -323,7 +323,8 @@ static int intel_msic_init_devices(struct intel_msic *msic) | |||
323 | if (pdata->ocd) { | 323 | if (pdata->ocd) { |
324 | unsigned gpio = pdata->ocd->gpio; | 324 | unsigned gpio = pdata->ocd->gpio; |
325 | 325 | ||
326 | ret = gpio_request_one(gpio, GPIOF_IN, "ocd_gpio"); | 326 | ret = devm_gpio_request_one(&pdev->dev, gpio, |
327 | GPIOF_IN, "ocd_gpio"); | ||
327 | if (ret) { | 328 | if (ret) { |
328 | dev_err(&pdev->dev, "failed to register OCD GPIO\n"); | 329 | dev_err(&pdev->dev, "failed to register OCD GPIO\n"); |
329 | return ret; | 330 | return ret; |
@@ -332,7 +333,6 @@ static int intel_msic_init_devices(struct intel_msic *msic) | |||
332 | ret = gpio_to_irq(gpio); | 333 | ret = gpio_to_irq(gpio); |
333 | if (ret < 0) { | 334 | if (ret < 0) { |
334 | dev_err(&pdev->dev, "no IRQ number for OCD GPIO\n"); | 335 | dev_err(&pdev->dev, "no IRQ number for OCD GPIO\n"); |
335 | gpio_free(gpio); | ||
336 | return ret; | 336 | return ret; |
337 | } | 337 | } |
338 | 338 | ||
@@ -359,8 +359,6 @@ static int intel_msic_init_devices(struct intel_msic *msic) | |||
359 | 359 | ||
360 | fail: | 360 | fail: |
361 | mfd_remove_devices(&pdev->dev); | 361 | mfd_remove_devices(&pdev->dev); |
362 | if (pdata->ocd) | ||
363 | gpio_free(pdata->ocd->gpio); | ||
364 | 362 | ||
365 | return ret; | 363 | return ret; |
366 | } | 364 | } |
@@ -368,12 +366,8 @@ fail: | |||
368 | static void intel_msic_remove_devices(struct intel_msic *msic) | 366 | static void intel_msic_remove_devices(struct intel_msic *msic) |
369 | { | 367 | { |
370 | struct platform_device *pdev = msic->pdev; | 368 | struct platform_device *pdev = msic->pdev; |
371 | struct intel_msic_platform_data *pdata = pdev->dev.platform_data; | ||
372 | 369 | ||
373 | mfd_remove_devices(&pdev->dev); | 370 | mfd_remove_devices(&pdev->dev); |
374 | |||
375 | if (pdata->ocd) | ||
376 | gpio_free(pdata->ocd->gpio); | ||
377 | } | 371 | } |
378 | 372 | ||
379 | static int intel_msic_probe(struct platform_device *pdev) | 373 | static int intel_msic_probe(struct platform_device *pdev) |
diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c index ceebf2c1ea97..4b7e6dac1de8 100644 --- a/drivers/mfd/lm3533-core.c +++ b/drivers/mfd/lm3533-core.c | |||
@@ -496,8 +496,8 @@ static int lm3533_device_init(struct lm3533 *lm3533) | |||
496 | dev_set_drvdata(lm3533->dev, lm3533); | 496 | dev_set_drvdata(lm3533->dev, lm3533); |
497 | 497 | ||
498 | if (gpio_is_valid(lm3533->gpio_hwen)) { | 498 | if (gpio_is_valid(lm3533->gpio_hwen)) { |
499 | ret = gpio_request_one(lm3533->gpio_hwen, GPIOF_OUT_INIT_LOW, | 499 | ret = devm_gpio_request_one(lm3533->dev, lm3533->gpio_hwen, |
500 | "lm3533-hwen"); | 500 | GPIOF_OUT_INIT_LOW, "lm3533-hwen"); |
501 | if (ret < 0) { | 501 | if (ret < 0) { |
502 | dev_err(lm3533->dev, | 502 | dev_err(lm3533->dev, |
503 | "failed to request HWEN GPIO %d\n", | 503 | "failed to request HWEN GPIO %d\n", |
@@ -528,8 +528,6 @@ err_unregister: | |||
528 | mfd_remove_devices(lm3533->dev); | 528 | mfd_remove_devices(lm3533->dev); |
529 | err_disable: | 529 | err_disable: |
530 | lm3533_disable(lm3533); | 530 | lm3533_disable(lm3533); |
531 | if (gpio_is_valid(lm3533->gpio_hwen)) | ||
532 | gpio_free(lm3533->gpio_hwen); | ||
533 | 531 | ||
534 | return ret; | 532 | return ret; |
535 | } | 533 | } |
@@ -542,8 +540,6 @@ static void lm3533_device_exit(struct lm3533 *lm3533) | |||
542 | 540 | ||
543 | mfd_remove_devices(lm3533->dev); | 541 | mfd_remove_devices(lm3533->dev); |
544 | lm3533_disable(lm3533); | 542 | lm3533_disable(lm3533); |
545 | if (gpio_is_valid(lm3533->gpio_hwen)) | ||
546 | gpio_free(lm3533->gpio_hwen); | ||
547 | } | 543 | } |
548 | 544 | ||
549 | static bool lm3533_readable_register(struct device *dev, unsigned int reg) | 545 | static bool lm3533_readable_register(struct device *dev, unsigned int reg) |
diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index 4d73963cd8f0..1cbb17609c8b 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c | |||
@@ -46,7 +46,7 @@ static struct regmap_config max77686_regmap_config = { | |||
46 | 46 | ||
47 | #ifdef CONFIG_OF | 47 | #ifdef CONFIG_OF |
48 | static struct of_device_id max77686_pmic_dt_match[] = { | 48 | static struct of_device_id max77686_pmic_dt_match[] = { |
49 | {.compatible = "maxim,max77686", .data = 0}, | 49 | {.compatible = "maxim,max77686", .data = NULL}, |
50 | {}, | 50 | {}, |
51 | }; | 51 | }; |
52 | 52 | ||
diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c index 3032bae20b62..77189daadf1e 100644 --- a/drivers/mfd/mc13xxx-spi.c +++ b/drivers/mfd/mc13xxx-spi.c | |||
@@ -131,7 +131,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi) | |||
131 | if (!mc13xxx) | 131 | if (!mc13xxx) |
132 | return -ENOMEM; | 132 | return -ENOMEM; |
133 | 133 | ||
134 | dev_set_drvdata(&spi->dev, mc13xxx); | 134 | spi_set_drvdata(spi, mc13xxx); |
135 | spi->mode = SPI_MODE_0 | SPI_CS_HIGH; | 135 | spi->mode = SPI_MODE_0 | SPI_CS_HIGH; |
136 | 136 | ||
137 | mc13xxx->dev = &spi->dev; | 137 | mc13xxx->dev = &spi->dev; |
@@ -144,7 +144,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi) | |||
144 | ret = PTR_ERR(mc13xxx->regmap); | 144 | ret = PTR_ERR(mc13xxx->regmap); |
145 | dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n", | 145 | dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n", |
146 | ret); | 146 | ret); |
147 | dev_set_drvdata(&spi->dev, NULL); | 147 | spi_set_drvdata(spi, NULL); |
148 | return ret; | 148 | return ret; |
149 | } | 149 | } |
150 | 150 | ||
@@ -164,7 +164,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi) | |||
164 | 164 | ||
165 | static int mc13xxx_spi_remove(struct spi_device *spi) | 165 | static int mc13xxx_spi_remove(struct spi_device *spi) |
166 | { | 166 | { |
167 | struct mc13xxx *mc13xxx = dev_get_drvdata(&spi->dev); | 167 | struct mc13xxx *mc13xxx = spi_get_drvdata(spi); |
168 | 168 | ||
169 | mc13xxx_common_cleanup(mc13xxx); | 169 | mc13xxx_common_cleanup(mc13xxx); |
170 | 170 | ||
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 4febc5c7fdee..759fae3ca7fb 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c | |||
@@ -1,8 +1,9 @@ | |||
1 | /** | 1 | /** |
2 | * omap-usb-host.c - The USBHS core driver for OMAP EHCI & OHCI | 2 | * omap-usb-host.c - The USBHS core driver for OMAP EHCI & OHCI |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com | 4 | * Copyright (C) 2011-2013 Texas Instruments Incorporated - http://www.ti.com |
5 | * Author: Keshava Munegowda <keshava_mgowda@ti.com> | 5 | * Author: Keshava Munegowda <keshava_mgowda@ti.com> |
6 | * Author: Roger Quadros <rogerq@ti.com> | ||
6 | * | 7 | * |
7 | * This program is free software: you can redistribute it and/or modify | 8 | * 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 of | 9 | * it under the terms of the GNU General Public License version 2 of |
@@ -27,6 +28,9 @@ | |||
27 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
28 | #include <linux/platform_data/usb-omap.h> | 29 | #include <linux/platform_data/usb-omap.h> |
29 | #include <linux/pm_runtime.h> | 30 | #include <linux/pm_runtime.h> |
31 | #include <linux/of.h> | ||
32 | #include <linux/of_platform.h> | ||
33 | #include <linux/err.h> | ||
30 | 34 | ||
31 | #include "omap-usb.h" | 35 | #include "omap-usb.h" |
32 | 36 | ||
@@ -137,6 +141,49 @@ static inline u8 usbhs_readb(void __iomem *base, u8 reg) | |||
137 | 141 | ||
138 | /*-------------------------------------------------------------------------*/ | 142 | /*-------------------------------------------------------------------------*/ |
139 | 143 | ||
144 | /** | ||
145 | * Map 'enum usbhs_omap_port_mode' found in <linux/platform_data/usb-omap.h> | ||
146 | * to the device tree binding portN-mode found in | ||
147 | * 'Documentation/devicetree/bindings/mfd/omap-usb-host.txt' | ||
148 | */ | ||
149 | static const char * const port_modes[] = { | ||
150 | [OMAP_USBHS_PORT_MODE_UNUSED] = "", | ||
151 | [OMAP_EHCI_PORT_MODE_PHY] = "ehci-phy", | ||
152 | [OMAP_EHCI_PORT_MODE_TLL] = "ehci-tll", | ||
153 | [OMAP_EHCI_PORT_MODE_HSIC] = "ehci-hsic", | ||
154 | [OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0] = "ohci-phy-6pin-datse0", | ||
155 | [OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM] = "ohci-phy-6pin-dpdm", | ||
156 | [OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0] = "ohci-phy-3pin-datse0", | ||
157 | [OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM] = "ohci-phy-4pin-dpdm", | ||
158 | [OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0] = "ohci-tll-6pin-datse0", | ||
159 | [OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM] = "ohci-tll-6pin-dpdm", | ||
160 | [OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0] = "ohci-tll-3pin-datse0", | ||
161 | [OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM] = "ohci-tll-4pin-dpdm", | ||
162 | [OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0] = "ohci-tll-2pin-datse0", | ||
163 | [OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM] = "ohci-tll-2pin-dpdm", | ||
164 | }; | ||
165 | |||
166 | /** | ||
167 | * omap_usbhs_get_dt_port_mode - Get the 'enum usbhs_omap_port_mode' | ||
168 | * from the port mode string. | ||
169 | * @mode: The port mode string, usually obtained from device tree. | ||
170 | * | ||
171 | * The function returns the 'enum usbhs_omap_port_mode' that matches the | ||
172 | * provided port mode string as per the port_modes table. | ||
173 | * If no match is found it returns -ENODEV | ||
174 | */ | ||
175 | static const int omap_usbhs_get_dt_port_mode(const char *mode) | ||
176 | { | ||
177 | int i; | ||
178 | |||
179 | for (i = 0; i < ARRAY_SIZE(port_modes); i++) { | ||
180 | if (!strcmp(mode, port_modes[i])) | ||
181 | return i; | ||
182 | } | ||
183 | |||
184 | return -ENODEV; | ||
185 | } | ||
186 | |||
140 | static struct platform_device *omap_usbhs_alloc_child(const char *name, | 187 | static struct platform_device *omap_usbhs_alloc_child(const char *name, |
141 | struct resource *res, int num_resources, void *pdata, | 188 | struct resource *res, int num_resources, void *pdata, |
142 | size_t pdata_size, struct device *dev) | 189 | size_t pdata_size, struct device *dev) |
@@ -278,7 +325,7 @@ static int usbhs_runtime_resume(struct device *dev) | |||
278 | 325 | ||
279 | dev_dbg(dev, "usbhs_runtime_resume\n"); | 326 | dev_dbg(dev, "usbhs_runtime_resume\n"); |
280 | 327 | ||
281 | omap_tll_enable(); | 328 | omap_tll_enable(pdata); |
282 | 329 | ||
283 | if (!IS_ERR(omap->ehci_logic_fck)) | 330 | if (!IS_ERR(omap->ehci_logic_fck)) |
284 | clk_enable(omap->ehci_logic_fck); | 331 | clk_enable(omap->ehci_logic_fck); |
@@ -353,7 +400,7 @@ static int usbhs_runtime_suspend(struct device *dev) | |||
353 | if (!IS_ERR(omap->ehci_logic_fck)) | 400 | if (!IS_ERR(omap->ehci_logic_fck)) |
354 | clk_disable(omap->ehci_logic_fck); | 401 | clk_disable(omap->ehci_logic_fck); |
355 | 402 | ||
356 | omap_tll_disable(); | 403 | omap_tll_disable(pdata); |
357 | 404 | ||
358 | return 0; | 405 | return 0; |
359 | } | 406 | } |
@@ -430,24 +477,10 @@ static unsigned omap_usbhs_rev2_hostconfig(struct usbhs_hcd_omap *omap, | |||
430 | static void omap_usbhs_init(struct device *dev) | 477 | static void omap_usbhs_init(struct device *dev) |
431 | { | 478 | { |
432 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | 479 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); |
433 | struct usbhs_omap_platform_data *pdata = omap->pdata; | ||
434 | unsigned reg; | 480 | unsigned reg; |
435 | 481 | ||
436 | dev_dbg(dev, "starting TI HSUSB Controller\n"); | 482 | dev_dbg(dev, "starting TI HSUSB Controller\n"); |
437 | 483 | ||
438 | if (pdata->phy_reset) { | ||
439 | if (gpio_is_valid(pdata->reset_gpio_port[0])) | ||
440 | gpio_request_one(pdata->reset_gpio_port[0], | ||
441 | GPIOF_OUT_INIT_LOW, "USB1 PHY reset"); | ||
442 | |||
443 | if (gpio_is_valid(pdata->reset_gpio_port[1])) | ||
444 | gpio_request_one(pdata->reset_gpio_port[1], | ||
445 | GPIOF_OUT_INIT_LOW, "USB2 PHY reset"); | ||
446 | |||
447 | /* Hold the PHY in RESET for enough time till DIR is high */ | ||
448 | udelay(10); | ||
449 | } | ||
450 | |||
451 | pm_runtime_get_sync(dev); | 484 | pm_runtime_get_sync(dev); |
452 | 485 | ||
453 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); | 486 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); |
@@ -476,36 +509,59 @@ static void omap_usbhs_init(struct device *dev) | |||
476 | dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); | 509 | dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); |
477 | 510 | ||
478 | pm_runtime_put_sync(dev); | 511 | pm_runtime_put_sync(dev); |
479 | if (pdata->phy_reset) { | 512 | } |
480 | /* Hold the PHY in RESET for enough time till | 513 | |
481 | * PHY is settled and ready | 514 | static int usbhs_omap_get_dt_pdata(struct device *dev, |
482 | */ | 515 | struct usbhs_omap_platform_data *pdata) |
483 | udelay(10); | 516 | { |
517 | int ret, i; | ||
518 | struct device_node *node = dev->of_node; | ||
484 | 519 | ||
485 | if (gpio_is_valid(pdata->reset_gpio_port[0])) | 520 | ret = of_property_read_u32(node, "num-ports", &pdata->nports); |
486 | gpio_set_value_cansleep | 521 | if (ret) |
487 | (pdata->reset_gpio_port[0], 1); | 522 | pdata->nports = 0; |
488 | 523 | ||
489 | if (gpio_is_valid(pdata->reset_gpio_port[1])) | 524 | if (pdata->nports > OMAP3_HS_USB_PORTS) { |
490 | gpio_set_value_cansleep | 525 | dev_warn(dev, "Too many num_ports <%d> in device tree. Max %d\n", |
491 | (pdata->reset_gpio_port[1], 1); | 526 | pdata->nports, OMAP3_HS_USB_PORTS); |
527 | return -ENODEV; | ||
492 | } | 528 | } |
493 | } | ||
494 | 529 | ||
495 | static void omap_usbhs_deinit(struct device *dev) | 530 | /* get port modes */ |
496 | { | 531 | for (i = 0; i < OMAP3_HS_USB_PORTS; i++) { |
497 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | 532 | char prop[11]; |
498 | struct usbhs_omap_platform_data *pdata = omap->pdata; | 533 | const char *mode; |
499 | 534 | ||
500 | if (pdata->phy_reset) { | 535 | pdata->port_mode[i] = OMAP_USBHS_PORT_MODE_UNUSED; |
501 | if (gpio_is_valid(pdata->reset_gpio_port[0])) | 536 | |
502 | gpio_free(pdata->reset_gpio_port[0]); | 537 | snprintf(prop, sizeof(prop), "port%d-mode", i + 1); |
538 | ret = of_property_read_string(node, prop, &mode); | ||
539 | if (ret < 0) | ||
540 | continue; | ||
541 | |||
542 | ret = omap_usbhs_get_dt_port_mode(mode); | ||
543 | if (ret < 0) { | ||
544 | dev_warn(dev, "Invalid port%d-mode \"%s\" in device tree\n", | ||
545 | i, mode); | ||
546 | return -ENODEV; | ||
547 | } | ||
503 | 548 | ||
504 | if (gpio_is_valid(pdata->reset_gpio_port[1])) | 549 | dev_dbg(dev, "port%d-mode: %s -> %d\n", i, mode, ret); |
505 | gpio_free(pdata->reset_gpio_port[1]); | 550 | pdata->port_mode[i] = ret; |
506 | } | 551 | } |
552 | |||
553 | /* get flags */ | ||
554 | pdata->single_ulpi_bypass = of_property_read_bool(node, | ||
555 | "single-ulpi-bypass"); | ||
556 | |||
557 | return 0; | ||
507 | } | 558 | } |
508 | 559 | ||
560 | static struct of_device_id usbhs_child_match_table[] = { | ||
561 | { .compatible = "ti,omap-ehci", }, | ||
562 | { .compatible = "ti,omap-ohci", }, | ||
563 | { } | ||
564 | }; | ||
509 | 565 | ||
510 | /** | 566 | /** |
511 | * usbhs_omap_probe - initialize TI-based HCDs | 567 | * usbhs_omap_probe - initialize TI-based HCDs |
@@ -522,26 +578,46 @@ static int usbhs_omap_probe(struct platform_device *pdev) | |||
522 | int i; | 578 | int i; |
523 | bool need_logic_fck; | 579 | bool need_logic_fck; |
524 | 580 | ||
581 | if (dev->of_node) { | ||
582 | /* For DT boot we populate platform data from OF node */ | ||
583 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | ||
584 | if (!pdata) | ||
585 | return -ENOMEM; | ||
586 | |||
587 | ret = usbhs_omap_get_dt_pdata(dev, pdata); | ||
588 | if (ret) | ||
589 | return ret; | ||
590 | |||
591 | dev->platform_data = pdata; | ||
592 | } | ||
593 | |||
525 | if (!pdata) { | 594 | if (!pdata) { |
526 | dev_err(dev, "Missing platform data\n"); | 595 | dev_err(dev, "Missing platform data\n"); |
527 | return -ENODEV; | 596 | return -ENODEV; |
528 | } | 597 | } |
529 | 598 | ||
599 | if (pdata->nports > OMAP3_HS_USB_PORTS) { | ||
600 | dev_info(dev, "Too many num_ports <%d> in platform_data. Max %d\n", | ||
601 | pdata->nports, OMAP3_HS_USB_PORTS); | ||
602 | return -ENODEV; | ||
603 | } | ||
604 | |||
530 | omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL); | 605 | omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL); |
531 | if (!omap) { | 606 | if (!omap) { |
532 | dev_err(dev, "Memory allocation failed\n"); | 607 | dev_err(dev, "Memory allocation failed\n"); |
533 | return -ENOMEM; | 608 | return -ENOMEM; |
534 | } | 609 | } |
535 | 610 | ||
536 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh"); | 611 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
537 | omap->uhh_base = devm_request_and_ioremap(dev, res); | 612 | omap->uhh_base = devm_ioremap_resource(dev, res); |
538 | if (!omap->uhh_base) { | 613 | if (IS_ERR(omap->uhh_base)) |
539 | dev_err(dev, "Resource request/ioremap failed\n"); | 614 | return PTR_ERR(omap->uhh_base); |
540 | return -EADDRNOTAVAIL; | ||
541 | } | ||
542 | 615 | ||
543 | omap->pdata = pdata; | 616 | omap->pdata = pdata; |
544 | 617 | ||
618 | /* Initialize the TLL subsystem */ | ||
619 | omap_tll_init(pdata); | ||
620 | |||
545 | pm_runtime_enable(dev); | 621 | pm_runtime_enable(dev); |
546 | 622 | ||
547 | platform_set_drvdata(pdev, omap); | 623 | platform_set_drvdata(pdev, omap); |
@@ -575,6 +651,7 @@ static int usbhs_omap_probe(struct platform_device *pdev) | |||
575 | omap->usbhs_rev, omap->nports); | 651 | omap->usbhs_rev, omap->nports); |
576 | break; | 652 | break; |
577 | } | 653 | } |
654 | pdata->nports = omap->nports; | ||
578 | } | 655 | } |
579 | 656 | ||
580 | i = sizeof(struct clk *) * omap->nports; | 657 | i = sizeof(struct clk *) * omap->nports; |
@@ -700,17 +777,28 @@ static int usbhs_omap_probe(struct platform_device *pdev) | |||
700 | } | 777 | } |
701 | 778 | ||
702 | omap_usbhs_init(dev); | 779 | omap_usbhs_init(dev); |
703 | ret = omap_usbhs_alloc_children(pdev); | 780 | |
704 | if (ret) { | 781 | if (dev->of_node) { |
705 | dev_err(dev, "omap_usbhs_alloc_children failed\n"); | 782 | ret = of_platform_populate(dev->of_node, |
706 | goto err_alloc; | 783 | usbhs_child_match_table, NULL, dev); |
784 | |||
785 | if (ret) { | ||
786 | dev_err(dev, "Failed to create DT children: %d\n", ret); | ||
787 | goto err_alloc; | ||
788 | } | ||
789 | |||
790 | } else { | ||
791 | ret = omap_usbhs_alloc_children(pdev); | ||
792 | if (ret) { | ||
793 | dev_err(dev, "omap_usbhs_alloc_children failed: %d\n", | ||
794 | ret); | ||
795 | goto err_alloc; | ||
796 | } | ||
707 | } | 797 | } |
708 | 798 | ||
709 | return 0; | 799 | return 0; |
710 | 800 | ||
711 | err_alloc: | 801 | err_alloc: |
712 | omap_usbhs_deinit(&pdev->dev); | ||
713 | |||
714 | for (i = 0; i < omap->nports; i++) { | 802 | for (i = 0; i < omap->nports; i++) { |
715 | if (!IS_ERR(omap->utmi_clk[i])) | 803 | if (!IS_ERR(omap->utmi_clk[i])) |
716 | clk_put(omap->utmi_clk[i]); | 804 | clk_put(omap->utmi_clk[i]); |
@@ -744,6 +832,13 @@ err_mem: | |||
744 | return ret; | 832 | return ret; |
745 | } | 833 | } |
746 | 834 | ||
835 | static int usbhs_omap_remove_child(struct device *dev, void *data) | ||
836 | { | ||
837 | dev_info(dev, "unregistering\n"); | ||
838 | platform_device_unregister(to_platform_device(dev)); | ||
839 | return 0; | ||
840 | } | ||
841 | |||
747 | /** | 842 | /** |
748 | * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs | 843 | * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs |
749 | * @pdev: USB Host Controller being removed | 844 | * @pdev: USB Host Controller being removed |
@@ -755,8 +850,6 @@ static int usbhs_omap_remove(struct platform_device *pdev) | |||
755 | struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); | 850 | struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); |
756 | int i; | 851 | int i; |
757 | 852 | ||
758 | omap_usbhs_deinit(&pdev->dev); | ||
759 | |||
760 | for (i = 0; i < omap->nports; i++) { | 853 | for (i = 0; i < omap->nports; i++) { |
761 | if (!IS_ERR(omap->utmi_clk[i])) | 854 | if (!IS_ERR(omap->utmi_clk[i])) |
762 | clk_put(omap->utmi_clk[i]); | 855 | clk_put(omap->utmi_clk[i]); |
@@ -777,6 +870,8 @@ static int usbhs_omap_remove(struct platform_device *pdev) | |||
777 | 870 | ||
778 | pm_runtime_disable(&pdev->dev); | 871 | pm_runtime_disable(&pdev->dev); |
779 | 872 | ||
873 | /* remove children */ | ||
874 | device_for_each_child(&pdev->dev, NULL, usbhs_omap_remove_child); | ||
780 | return 0; | 875 | return 0; |
781 | } | 876 | } |
782 | 877 | ||
@@ -785,16 +880,26 @@ static const struct dev_pm_ops usbhsomap_dev_pm_ops = { | |||
785 | .runtime_resume = usbhs_runtime_resume, | 880 | .runtime_resume = usbhs_runtime_resume, |
786 | }; | 881 | }; |
787 | 882 | ||
883 | static const struct of_device_id usbhs_omap_dt_ids[] = { | ||
884 | { .compatible = "ti,usbhs-host" }, | ||
885 | { } | ||
886 | }; | ||
887 | |||
888 | MODULE_DEVICE_TABLE(of, usbhs_omap_dt_ids); | ||
889 | |||
890 | |||
788 | static struct platform_driver usbhs_omap_driver = { | 891 | static struct platform_driver usbhs_omap_driver = { |
789 | .driver = { | 892 | .driver = { |
790 | .name = (char *)usbhs_driver_name, | 893 | .name = (char *)usbhs_driver_name, |
791 | .owner = THIS_MODULE, | 894 | .owner = THIS_MODULE, |
792 | .pm = &usbhsomap_dev_pm_ops, | 895 | .pm = &usbhsomap_dev_pm_ops, |
896 | .of_match_table = of_match_ptr(usbhs_omap_dt_ids), | ||
793 | }, | 897 | }, |
794 | .remove = usbhs_omap_remove, | 898 | .remove = usbhs_omap_remove, |
795 | }; | 899 | }; |
796 | 900 | ||
797 | MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); | 901 | MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); |
902 | MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>"); | ||
798 | MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); | 903 | MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); |
799 | MODULE_LICENSE("GPL v2"); | 904 | MODULE_LICENSE("GPL v2"); |
800 | MODULE_DESCRIPTION("usb host common core driver for omap EHCI and OHCI"); | 905 | MODULE_DESCRIPTION("usb host common core driver for omap EHCI and OHCI"); |
diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index 0aef1a768880..e59ac4cbac96 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c | |||
@@ -1,8 +1,9 @@ | |||
1 | /** | 1 | /** |
2 | * omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI | 2 | * omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI |
3 | * | 3 | * |
4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com | 4 | * Copyright (C) 2012-2013 Texas Instruments Incorporated - http://www.ti.com |
5 | * Author: Keshava Munegowda <keshava_mgowda@ti.com> | 5 | * Author: Keshava Munegowda <keshava_mgowda@ti.com> |
6 | * Author: Roger Quadros <rogerq@ti.com> | ||
6 | * | 7 | * |
7 | * This program is free software: you can redistribute it and/or modify | 8 | * 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 of | 9 | * it under the terms of the GNU General Public License version 2 of |
@@ -27,6 +28,7 @@ | |||
27 | #include <linux/err.h> | 28 | #include <linux/err.h> |
28 | #include <linux/pm_runtime.h> | 29 | #include <linux/pm_runtime.h> |
29 | #include <linux/platform_data/usb-omap.h> | 30 | #include <linux/platform_data/usb-omap.h> |
31 | #include <linux/of.h> | ||
30 | 32 | ||
31 | #define USBTLL_DRIVER_NAME "usbhs_tll" | 33 | #define USBTLL_DRIVER_NAME "usbhs_tll" |
32 | 34 | ||
@@ -105,8 +107,8 @@ | |||
105 | 107 | ||
106 | struct usbtll_omap { | 108 | struct usbtll_omap { |
107 | int nch; /* num. of channels */ | 109 | int nch; /* num. of channels */ |
108 | struct usbhs_omap_platform_data *pdata; | ||
109 | struct clk **ch_clk; | 110 | struct clk **ch_clk; |
111 | void __iomem *base; | ||
110 | }; | 112 | }; |
111 | 113 | ||
112 | /*-------------------------------------------------------------------------*/ | 114 | /*-------------------------------------------------------------------------*/ |
@@ -210,14 +212,10 @@ static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) | |||
210 | static int usbtll_omap_probe(struct platform_device *pdev) | 212 | static int usbtll_omap_probe(struct platform_device *pdev) |
211 | { | 213 | { |
212 | struct device *dev = &pdev->dev; | 214 | struct device *dev = &pdev->dev; |
213 | struct usbhs_omap_platform_data *pdata = dev->platform_data; | ||
214 | void __iomem *base; | ||
215 | struct resource *res; | 215 | struct resource *res; |
216 | struct usbtll_omap *tll; | 216 | struct usbtll_omap *tll; |
217 | unsigned reg; | ||
218 | int ret = 0; | 217 | int ret = 0; |
219 | int i, ver; | 218 | int i, ver; |
220 | bool needs_tll; | ||
221 | 219 | ||
222 | dev_dbg(dev, "starting TI HSUSB TLL Controller\n"); | 220 | dev_dbg(dev, "starting TI HSUSB TLL Controller\n"); |
223 | 221 | ||
@@ -227,26 +225,16 @@ static int usbtll_omap_probe(struct platform_device *pdev) | |||
227 | return -ENOMEM; | 225 | return -ENOMEM; |
228 | } | 226 | } |
229 | 227 | ||
230 | if (!pdata) { | ||
231 | dev_err(dev, "Platform data missing\n"); | ||
232 | return -ENODEV; | ||
233 | } | ||
234 | |||
235 | tll->pdata = pdata; | ||
236 | |||
237 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 228 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
238 | base = devm_request_and_ioremap(dev, res); | 229 | tll->base = devm_ioremap_resource(dev, res); |
239 | if (!base) { | 230 | if (IS_ERR(tll->base)) |
240 | ret = -EADDRNOTAVAIL; | 231 | return PTR_ERR(tll->base); |
241 | dev_err(dev, "Resource request/ioremap failed:%d\n", ret); | ||
242 | return ret; | ||
243 | } | ||
244 | 232 | ||
245 | platform_set_drvdata(pdev, tll); | 233 | platform_set_drvdata(pdev, tll); |
246 | pm_runtime_enable(dev); | 234 | pm_runtime_enable(dev); |
247 | pm_runtime_get_sync(dev); | 235 | pm_runtime_get_sync(dev); |
248 | 236 | ||
249 | ver = usbtll_read(base, OMAP_USBTLL_REVISION); | 237 | ver = usbtll_read(tll->base, OMAP_USBTLL_REVISION); |
250 | switch (ver) { | 238 | switch (ver) { |
251 | case OMAP_USBTLL_REV1: | 239 | case OMAP_USBTLL_REV1: |
252 | case OMAP_USBTLL_REV4: | 240 | case OMAP_USBTLL_REV4: |
@@ -283,11 +271,85 @@ static int usbtll_omap_probe(struct platform_device *pdev) | |||
283 | dev_dbg(dev, "can't get clock : %s\n", clkname); | 271 | dev_dbg(dev, "can't get clock : %s\n", clkname); |
284 | } | 272 | } |
285 | 273 | ||
274 | pm_runtime_put_sync(dev); | ||
275 | /* only after this can omap_tll_enable/disable work */ | ||
276 | spin_lock(&tll_lock); | ||
277 | tll_dev = dev; | ||
278 | spin_unlock(&tll_lock); | ||
279 | |||
280 | return 0; | ||
281 | |||
282 | err_clk_alloc: | ||
283 | pm_runtime_put_sync(dev); | ||
284 | pm_runtime_disable(dev); | ||
285 | |||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | /** | ||
290 | * usbtll_omap_remove - shutdown processing for UHH & TLL HCDs | ||
291 | * @pdev: USB Host Controller being removed | ||
292 | * | ||
293 | * Reverses the effect of usbtll_omap_probe(). | ||
294 | */ | ||
295 | static int usbtll_omap_remove(struct platform_device *pdev) | ||
296 | { | ||
297 | struct usbtll_omap *tll = platform_get_drvdata(pdev); | ||
298 | int i; | ||
299 | |||
300 | spin_lock(&tll_lock); | ||
301 | tll_dev = NULL; | ||
302 | spin_unlock(&tll_lock); | ||
303 | |||
304 | for (i = 0; i < tll->nch; i++) | ||
305 | if (!IS_ERR(tll->ch_clk[i])) | ||
306 | clk_put(tll->ch_clk[i]); | ||
307 | |||
308 | pm_runtime_disable(&pdev->dev); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static const struct of_device_id usbtll_omap_dt_ids[] = { | ||
313 | { .compatible = "ti,usbhs-tll" }, | ||
314 | { } | ||
315 | }; | ||
316 | |||
317 | MODULE_DEVICE_TABLE(of, usbtll_omap_dt_ids); | ||
318 | |||
319 | static struct platform_driver usbtll_omap_driver = { | ||
320 | .driver = { | ||
321 | .name = (char *)usbtll_driver_name, | ||
322 | .owner = THIS_MODULE, | ||
323 | .of_match_table = of_match_ptr(usbtll_omap_dt_ids), | ||
324 | }, | ||
325 | .probe = usbtll_omap_probe, | ||
326 | .remove = usbtll_omap_remove, | ||
327 | }; | ||
328 | |||
329 | int omap_tll_init(struct usbhs_omap_platform_data *pdata) | ||
330 | { | ||
331 | int i; | ||
332 | bool needs_tll; | ||
333 | unsigned reg; | ||
334 | struct usbtll_omap *tll; | ||
335 | |||
336 | spin_lock(&tll_lock); | ||
337 | |||
338 | if (!tll_dev) { | ||
339 | spin_unlock(&tll_lock); | ||
340 | return -ENODEV; | ||
341 | } | ||
342 | |||
343 | tll = dev_get_drvdata(tll_dev); | ||
344 | |||
286 | needs_tll = false; | 345 | needs_tll = false; |
287 | for (i = 0; i < tll->nch; i++) | 346 | for (i = 0; i < tll->nch; i++) |
288 | needs_tll |= omap_usb_mode_needs_tll(pdata->port_mode[i]); | 347 | needs_tll |= omap_usb_mode_needs_tll(pdata->port_mode[i]); |
289 | 348 | ||
349 | pm_runtime_get_sync(tll_dev); | ||
350 | |||
290 | if (needs_tll) { | 351 | if (needs_tll) { |
352 | void __iomem *base = tll->base; | ||
291 | 353 | ||
292 | /* Program Common TLL register */ | 354 | /* Program Common TLL register */ |
293 | reg = usbtll_read(base, OMAP_TLL_SHARED_CONF); | 355 | reg = usbtll_read(base, OMAP_TLL_SHARED_CONF); |
@@ -336,51 +398,29 @@ static int usbtll_omap_probe(struct platform_device *pdev) | |||
336 | } | 398 | } |
337 | } | 399 | } |
338 | 400 | ||
339 | pm_runtime_put_sync(dev); | 401 | pm_runtime_put_sync(tll_dev); |
340 | /* only after this can omap_tll_enable/disable work */ | 402 | |
341 | spin_lock(&tll_lock); | ||
342 | tll_dev = dev; | ||
343 | spin_unlock(&tll_lock); | 403 | spin_unlock(&tll_lock); |
344 | 404 | ||
345 | return 0; | 405 | return 0; |
346 | |||
347 | err_clk_alloc: | ||
348 | pm_runtime_put_sync(dev); | ||
349 | pm_runtime_disable(dev); | ||
350 | |||
351 | return ret; | ||
352 | } | 406 | } |
407 | EXPORT_SYMBOL_GPL(omap_tll_init); | ||
353 | 408 | ||
354 | /** | 409 | int omap_tll_enable(struct usbhs_omap_platform_data *pdata) |
355 | * usbtll_omap_remove - shutdown processing for UHH & TLL HCDs | ||
356 | * @pdev: USB Host Controller being removed | ||
357 | * | ||
358 | * Reverses the effect of usbtll_omap_probe(). | ||
359 | */ | ||
360 | static int usbtll_omap_remove(struct platform_device *pdev) | ||
361 | { | 410 | { |
362 | struct usbtll_omap *tll = platform_get_drvdata(pdev); | ||
363 | int i; | 411 | int i; |
412 | struct usbtll_omap *tll; | ||
364 | 413 | ||
365 | spin_lock(&tll_lock); | 414 | spin_lock(&tll_lock); |
366 | tll_dev = NULL; | ||
367 | spin_unlock(&tll_lock); | ||
368 | 415 | ||
369 | for (i = 0; i < tll->nch; i++) | 416 | if (!tll_dev) { |
370 | if (!IS_ERR(tll->ch_clk[i])) | 417 | spin_unlock(&tll_lock); |
371 | clk_put(tll->ch_clk[i]); | 418 | return -ENODEV; |
372 | 419 | } | |
373 | pm_runtime_disable(&pdev->dev); | ||
374 | return 0; | ||
375 | } | ||
376 | 420 | ||
377 | static int usbtll_runtime_resume(struct device *dev) | 421 | tll = dev_get_drvdata(tll_dev); |
378 | { | ||
379 | struct usbtll_omap *tll = dev_get_drvdata(dev); | ||
380 | struct usbhs_omap_platform_data *pdata = tll->pdata; | ||
381 | int i; | ||
382 | 422 | ||
383 | dev_dbg(dev, "usbtll_runtime_resume\n"); | 423 | pm_runtime_get_sync(tll_dev); |
384 | 424 | ||
385 | for (i = 0; i < tll->nch; i++) { | 425 | for (i = 0; i < tll->nch; i++) { |
386 | if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { | 426 | if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { |
@@ -391,22 +431,31 @@ static int usbtll_runtime_resume(struct device *dev) | |||
391 | 431 | ||
392 | r = clk_enable(tll->ch_clk[i]); | 432 | r = clk_enable(tll->ch_clk[i]); |
393 | if (r) { | 433 | if (r) { |
394 | dev_err(dev, | 434 | dev_err(tll_dev, |
395 | "Error enabling ch %d clock: %d\n", i, r); | 435 | "Error enabling ch %d clock: %d\n", i, r); |
396 | } | 436 | } |
397 | } | 437 | } |
398 | } | 438 | } |
399 | 439 | ||
440 | spin_unlock(&tll_lock); | ||
441 | |||
400 | return 0; | 442 | return 0; |
401 | } | 443 | } |
444 | EXPORT_SYMBOL_GPL(omap_tll_enable); | ||
402 | 445 | ||
403 | static int usbtll_runtime_suspend(struct device *dev) | 446 | int omap_tll_disable(struct usbhs_omap_platform_data *pdata) |
404 | { | 447 | { |
405 | struct usbtll_omap *tll = dev_get_drvdata(dev); | ||
406 | struct usbhs_omap_platform_data *pdata = tll->pdata; | ||
407 | int i; | 448 | int i; |
449 | struct usbtll_omap *tll; | ||
408 | 450 | ||
409 | dev_dbg(dev, "usbtll_runtime_suspend\n"); | 451 | spin_lock(&tll_lock); |
452 | |||
453 | if (!tll_dev) { | ||
454 | spin_unlock(&tll_lock); | ||
455 | return -ENODEV; | ||
456 | } | ||
457 | |||
458 | tll = dev_get_drvdata(tll_dev); | ||
410 | 459 | ||
411 | for (i = 0; i < tll->nch; i++) { | 460 | for (i = 0; i < tll->nch; i++) { |
412 | if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { | 461 | if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { |
@@ -415,64 +464,16 @@ static int usbtll_runtime_suspend(struct device *dev) | |||
415 | } | 464 | } |
416 | } | 465 | } |
417 | 466 | ||
418 | return 0; | 467 | pm_runtime_put_sync(tll_dev); |
419 | } | ||
420 | |||
421 | static const struct dev_pm_ops usbtllomap_dev_pm_ops = { | ||
422 | SET_RUNTIME_PM_OPS(usbtll_runtime_suspend, | ||
423 | usbtll_runtime_resume, | ||
424 | NULL) | ||
425 | }; | ||
426 | |||
427 | static struct platform_driver usbtll_omap_driver = { | ||
428 | .driver = { | ||
429 | .name = (char *)usbtll_driver_name, | ||
430 | .owner = THIS_MODULE, | ||
431 | .pm = &usbtllomap_dev_pm_ops, | ||
432 | }, | ||
433 | .probe = usbtll_omap_probe, | ||
434 | .remove = usbtll_omap_remove, | ||
435 | }; | ||
436 | |||
437 | int omap_tll_enable(void) | ||
438 | { | ||
439 | int ret; | ||
440 | |||
441 | spin_lock(&tll_lock); | ||
442 | |||
443 | if (!tll_dev) { | ||
444 | pr_err("%s: OMAP USB TLL not initialized\n", __func__); | ||
445 | ret = -ENODEV; | ||
446 | } else { | ||
447 | ret = pm_runtime_get_sync(tll_dev); | ||
448 | } | ||
449 | |||
450 | spin_unlock(&tll_lock); | ||
451 | |||
452 | return ret; | ||
453 | } | ||
454 | EXPORT_SYMBOL_GPL(omap_tll_enable); | ||
455 | |||
456 | int omap_tll_disable(void) | ||
457 | { | ||
458 | int ret; | ||
459 | |||
460 | spin_lock(&tll_lock); | ||
461 | |||
462 | if (!tll_dev) { | ||
463 | pr_err("%s: OMAP USB TLL not initialized\n", __func__); | ||
464 | ret = -ENODEV; | ||
465 | } else { | ||
466 | ret = pm_runtime_put_sync(tll_dev); | ||
467 | } | ||
468 | 468 | ||
469 | spin_unlock(&tll_lock); | 469 | spin_unlock(&tll_lock); |
470 | 470 | ||
471 | return ret; | 471 | return 0; |
472 | } | 472 | } |
473 | EXPORT_SYMBOL_GPL(omap_tll_disable); | 473 | EXPORT_SYMBOL_GPL(omap_tll_disable); |
474 | 474 | ||
475 | MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); | 475 | MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); |
476 | MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>"); | ||
476 | MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); | 477 | MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); |
477 | MODULE_LICENSE("GPL v2"); | 478 | MODULE_LICENSE("GPL v2"); |
478 | MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers"); | 479 | MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers"); |
diff --git a/drivers/mfd/omap-usb.h b/drivers/mfd/omap-usb.h index 972aa961b064..2a508b6aeac8 100644 --- a/drivers/mfd/omap-usb.h +++ b/drivers/mfd/omap-usb.h | |||
@@ -1,2 +1,3 @@ | |||
1 | extern int omap_tll_enable(void); | 1 | extern int omap_tll_init(struct usbhs_omap_platform_data *pdata); |
2 | extern int omap_tll_disable(void); | 2 | extern int omap_tll_enable(struct usbhs_omap_platform_data *pdata); |
3 | extern int omap_tll_disable(struct usbhs_omap_platform_data *pdata); | ||
diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index 73bf76df1044..53e9fe638d32 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c | |||
@@ -278,20 +278,20 @@ static void palmas_dt_to_pdata(struct i2c_client *i2c, | |||
278 | int ret; | 278 | int ret; |
279 | u32 prop; | 279 | u32 prop; |
280 | 280 | ||
281 | ret = of_property_read_u32(node, "ti,mux_pad1", &prop); | 281 | ret = of_property_read_u32(node, "ti,mux-pad1", &prop); |
282 | if (!ret) { | 282 | if (!ret) { |
283 | pdata->mux_from_pdata = 1; | 283 | pdata->mux_from_pdata = 1; |
284 | pdata->pad1 = prop; | 284 | pdata->pad1 = prop; |
285 | } | 285 | } |
286 | 286 | ||
287 | ret = of_property_read_u32(node, "ti,mux_pad2", &prop); | 287 | ret = of_property_read_u32(node, "ti,mux-pad2", &prop); |
288 | if (!ret) { | 288 | if (!ret) { |
289 | pdata->mux_from_pdata = 1; | 289 | pdata->mux_from_pdata = 1; |
290 | pdata->pad2 = prop; | 290 | pdata->pad2 = prop; |
291 | } | 291 | } |
292 | 292 | ||
293 | /* The default for this register is all masked */ | 293 | /* The default for this register is all masked */ |
294 | ret = of_property_read_u32(node, "ti,power_ctrl", &prop); | 294 | ret = of_property_read_u32(node, "ti,power-ctrl", &prop); |
295 | if (!ret) | 295 | if (!ret) |
296 | pdata->power_ctrl = prop; | 296 | pdata->power_ctrl = prop; |
297 | else | 297 | else |
@@ -349,6 +349,7 @@ static int palmas_i2c_probe(struct i2c_client *i2c, | |||
349 | ret = -ENOMEM; | 349 | ret = -ENOMEM; |
350 | goto err; | 350 | goto err; |
351 | } | 351 | } |
352 | palmas->i2c_clients[i]->dev.of_node = of_node_get(node); | ||
352 | } | 353 | } |
353 | palmas->regmap[i] = devm_regmap_init_i2c(palmas->i2c_clients[i], | 354 | palmas->regmap[i] = devm_regmap_init_i2c(palmas->i2c_clients[i], |
354 | &palmas_regmap_config[i]); | 355 | &palmas_regmap_config[i]); |
diff --git a/drivers/mfd/retu-mfd.c b/drivers/mfd/retu-mfd.c index 3ba048655bf3..a1830986eeb7 100644 --- a/drivers/mfd/retu-mfd.c +++ b/drivers/mfd/retu-mfd.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Retu MFD driver | 2 | * Retu/Tahvo MFD driver |
3 | * | 3 | * |
4 | * Copyright (C) 2004, 2005 Nokia Corporation | 4 | * Copyright (C) 2004, 2005 Nokia Corporation |
5 | * | 5 | * |
@@ -33,7 +33,8 @@ | |||
33 | #define RETU_REG_ASICR 0x00 /* ASIC ID and revision */ | 33 | #define RETU_REG_ASICR 0x00 /* ASIC ID and revision */ |
34 | #define RETU_REG_ASICR_VILMA (1 << 7) /* Bit indicating Vilma */ | 34 | #define RETU_REG_ASICR_VILMA (1 << 7) /* Bit indicating Vilma */ |
35 | #define RETU_REG_IDR 0x01 /* Interrupt ID */ | 35 | #define RETU_REG_IDR 0x01 /* Interrupt ID */ |
36 | #define RETU_REG_IMR 0x02 /* Interrupt mask */ | 36 | #define RETU_REG_IMR 0x02 /* Interrupt mask (Retu) */ |
37 | #define TAHVO_REG_IMR 0x03 /* Interrupt mask (Tahvo) */ | ||
37 | 38 | ||
38 | /* Interrupt sources */ | 39 | /* Interrupt sources */ |
39 | #define RETU_INT_PWR 0 /* Power button */ | 40 | #define RETU_INT_PWR 0 /* Power button */ |
@@ -84,6 +85,62 @@ static struct regmap_irq_chip retu_irq_chip = { | |||
84 | /* Retu device registered for the power off. */ | 85 | /* Retu device registered for the power off. */ |
85 | static struct retu_dev *retu_pm_power_off; | 86 | static struct retu_dev *retu_pm_power_off; |
86 | 87 | ||
88 | static struct resource tahvo_usb_res[] = { | ||
89 | { | ||
90 | .name = "tahvo-usb", | ||
91 | .start = TAHVO_INT_VBUS, | ||
92 | .end = TAHVO_INT_VBUS, | ||
93 | .flags = IORESOURCE_IRQ, | ||
94 | }, | ||
95 | }; | ||
96 | |||
97 | static struct mfd_cell tahvo_devs[] = { | ||
98 | { | ||
99 | .name = "tahvo-usb", | ||
100 | .resources = tahvo_usb_res, | ||
101 | .num_resources = ARRAY_SIZE(tahvo_usb_res), | ||
102 | }, | ||
103 | }; | ||
104 | |||
105 | static struct regmap_irq tahvo_irqs[] = { | ||
106 | [TAHVO_INT_VBUS] = { | ||
107 | .mask = 1 << TAHVO_INT_VBUS, | ||
108 | } | ||
109 | }; | ||
110 | |||
111 | static struct regmap_irq_chip tahvo_irq_chip = { | ||
112 | .name = "TAHVO", | ||
113 | .irqs = tahvo_irqs, | ||
114 | .num_irqs = ARRAY_SIZE(tahvo_irqs), | ||
115 | .num_regs = 1, | ||
116 | .status_base = RETU_REG_IDR, | ||
117 | .mask_base = TAHVO_REG_IMR, | ||
118 | .ack_base = RETU_REG_IDR, | ||
119 | }; | ||
120 | |||
121 | static const struct retu_data { | ||
122 | char *chip_name; | ||
123 | char *companion_name; | ||
124 | struct regmap_irq_chip *irq_chip; | ||
125 | struct mfd_cell *children; | ||
126 | int nchildren; | ||
127 | } retu_data[] = { | ||
128 | [0] = { | ||
129 | .chip_name = "Retu", | ||
130 | .companion_name = "Vilma", | ||
131 | .irq_chip = &retu_irq_chip, | ||
132 | .children = retu_devs, | ||
133 | .nchildren = ARRAY_SIZE(retu_devs), | ||
134 | }, | ||
135 | [1] = { | ||
136 | .chip_name = "Tahvo", | ||
137 | .companion_name = "Betty", | ||
138 | .irq_chip = &tahvo_irq_chip, | ||
139 | .children = tahvo_devs, | ||
140 | .nchildren = ARRAY_SIZE(tahvo_devs), | ||
141 | } | ||
142 | }; | ||
143 | |||
87 | int retu_read(struct retu_dev *rdev, u8 reg) | 144 | int retu_read(struct retu_dev *rdev, u8 reg) |
88 | { | 145 | { |
89 | int ret; | 146 | int ret; |
@@ -173,9 +230,14 @@ static struct regmap_config retu_config = { | |||
173 | 230 | ||
174 | static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) | 231 | static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) |
175 | { | 232 | { |
233 | struct retu_data const *rdat; | ||
176 | struct retu_dev *rdev; | 234 | struct retu_dev *rdev; |
177 | int ret; | 235 | int ret; |
178 | 236 | ||
237 | if (i2c->addr > ARRAY_SIZE(retu_data)) | ||
238 | return -ENODEV; | ||
239 | rdat = &retu_data[i2c->addr - 1]; | ||
240 | |||
179 | rdev = devm_kzalloc(&i2c->dev, sizeof(*rdev), GFP_KERNEL); | 241 | rdev = devm_kzalloc(&i2c->dev, sizeof(*rdev), GFP_KERNEL); |
180 | if (rdev == NULL) | 242 | if (rdev == NULL) |
181 | return -ENOMEM; | 243 | return -ENOMEM; |
@@ -190,25 +252,27 @@ static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) | |||
190 | 252 | ||
191 | ret = retu_read(rdev, RETU_REG_ASICR); | 253 | ret = retu_read(rdev, RETU_REG_ASICR); |
192 | if (ret < 0) { | 254 | if (ret < 0) { |
193 | dev_err(rdev->dev, "could not read Retu revision: %d\n", ret); | 255 | dev_err(rdev->dev, "could not read %s revision: %d\n", |
256 | rdat->chip_name, ret); | ||
194 | return ret; | 257 | return ret; |
195 | } | 258 | } |
196 | 259 | ||
197 | dev_info(rdev->dev, "Retu%s v%d.%d found\n", | 260 | dev_info(rdev->dev, "%s%s%s v%d.%d found\n", rdat->chip_name, |
198 | (ret & RETU_REG_ASICR_VILMA) ? " & Vilma" : "", | 261 | (ret & RETU_REG_ASICR_VILMA) ? " & " : "", |
262 | (ret & RETU_REG_ASICR_VILMA) ? rdat->companion_name : "", | ||
199 | (ret >> 4) & 0x7, ret & 0xf); | 263 | (ret >> 4) & 0x7, ret & 0xf); |
200 | 264 | ||
201 | /* Mask all RETU interrupts. */ | 265 | /* Mask all interrupts. */ |
202 | ret = retu_write(rdev, RETU_REG_IMR, 0xffff); | 266 | ret = retu_write(rdev, rdat->irq_chip->mask_base, 0xffff); |
203 | if (ret < 0) | 267 | if (ret < 0) |
204 | return ret; | 268 | return ret; |
205 | 269 | ||
206 | ret = regmap_add_irq_chip(rdev->regmap, i2c->irq, IRQF_ONESHOT, -1, | 270 | ret = regmap_add_irq_chip(rdev->regmap, i2c->irq, IRQF_ONESHOT, -1, |
207 | &retu_irq_chip, &rdev->irq_data); | 271 | rdat->irq_chip, &rdev->irq_data); |
208 | if (ret < 0) | 272 | if (ret < 0) |
209 | return ret; | 273 | return ret; |
210 | 274 | ||
211 | ret = mfd_add_devices(rdev->dev, -1, retu_devs, ARRAY_SIZE(retu_devs), | 275 | ret = mfd_add_devices(rdev->dev, -1, rdat->children, rdat->nchildren, |
212 | NULL, regmap_irq_chip_get_base(rdev->irq_data), | 276 | NULL, regmap_irq_chip_get_base(rdev->irq_data), |
213 | NULL); | 277 | NULL); |
214 | if (ret < 0) { | 278 | if (ret < 0) { |
@@ -216,7 +280,7 @@ static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) | |||
216 | return ret; | 280 | return ret; |
217 | } | 281 | } |
218 | 282 | ||
219 | if (!pm_power_off) { | 283 | if (i2c->addr == 1 && !pm_power_off) { |
220 | retu_pm_power_off = rdev; | 284 | retu_pm_power_off = rdev; |
221 | pm_power_off = retu_power_off; | 285 | pm_power_off = retu_power_off; |
222 | } | 286 | } |
@@ -240,6 +304,7 @@ static int retu_remove(struct i2c_client *i2c) | |||
240 | 304 | ||
241 | static const struct i2c_device_id retu_id[] = { | 305 | static const struct i2c_device_id retu_id[] = { |
242 | { "retu-mfd", 0 }, | 306 | { "retu-mfd", 0 }, |
307 | { "tahvo-mfd", 0 }, | ||
243 | { } | 308 | { } |
244 | }; | 309 | }; |
245 | MODULE_DEVICE_TABLE(i2c, retu_id); | 310 | MODULE_DEVICE_TABLE(i2c, retu_id); |
diff --git a/drivers/mfd/rts5249.c b/drivers/mfd/rts5249.c new file mode 100644 index 000000000000..15dc848bc081 --- /dev/null +++ b/drivers/mfd/rts5249.c | |||
@@ -0,0 +1,241 @@ | |||
1 | /* Driver for Realtek PCI-Express card reader | ||
2 | * | ||
3 | * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2, or (at your option) any | ||
8 | * later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * Author: | ||
19 | * Wei WANG <wei_wang@realsil.com.cn> | ||
20 | * No. 128, West Shenhu Road, Suzhou Industry Park, Suzhou, China | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/mfd/rtsx_pci.h> | ||
26 | |||
27 | #include "rtsx_pcr.h" | ||
28 | |||
29 | static u8 rts5249_get_ic_version(struct rtsx_pcr *pcr) | ||
30 | { | ||
31 | u8 val; | ||
32 | |||
33 | rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val); | ||
34 | return val & 0x0F; | ||
35 | } | ||
36 | |||
37 | static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) | ||
38 | { | ||
39 | rtsx_pci_init_cmd(pcr); | ||
40 | |||
41 | /* Configure GPIO as output */ | ||
42 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02); | ||
43 | /* Switch LDO3318 source from DV33 to card_3v3 */ | ||
44 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00); | ||
45 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); | ||
46 | /* LED shine disabled, set initial shine cycle period */ | ||
47 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02); | ||
48 | /* Correct driving */ | ||
49 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
50 | SD30_CLK_DRIVE_SEL, 0xFF, 0x99); | ||
51 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
52 | SD30_CMD_DRIVE_SEL, 0xFF, 0x99); | ||
53 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
54 | SD30_DAT_DRIVE_SEL, 0xFF, 0x92); | ||
55 | |||
56 | return rtsx_pci_send_cmd(pcr, 100); | ||
57 | } | ||
58 | |||
59 | static int rts5249_optimize_phy(struct rtsx_pcr *pcr) | ||
60 | { | ||
61 | int err; | ||
62 | |||
63 | err = rtsx_pci_write_phy_register(pcr, PHY_REG_REV, 0xFE46); | ||
64 | if (err < 0) | ||
65 | return err; | ||
66 | |||
67 | msleep(1); | ||
68 | |||
69 | return rtsx_pci_write_phy_register(pcr, PHY_BPCR, 0x05C0); | ||
70 | } | ||
71 | |||
72 | static int rts5249_turn_on_led(struct rtsx_pcr *pcr) | ||
73 | { | ||
74 | return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02); | ||
75 | } | ||
76 | |||
77 | static int rts5249_turn_off_led(struct rtsx_pcr *pcr) | ||
78 | { | ||
79 | return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00); | ||
80 | } | ||
81 | |||
82 | static int rts5249_enable_auto_blink(struct rtsx_pcr *pcr) | ||
83 | { | ||
84 | return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08); | ||
85 | } | ||
86 | |||
87 | static int rts5249_disable_auto_blink(struct rtsx_pcr *pcr) | ||
88 | { | ||
89 | return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00); | ||
90 | } | ||
91 | |||
92 | static int rts5249_card_power_on(struct rtsx_pcr *pcr, int card) | ||
93 | { | ||
94 | int err; | ||
95 | |||
96 | rtsx_pci_init_cmd(pcr); | ||
97 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, | ||
98 | SD_POWER_MASK, SD_VCC_PARTIAL_POWER_ON); | ||
99 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, | ||
100 | LDO3318_PWR_MASK, 0x02); | ||
101 | err = rtsx_pci_send_cmd(pcr, 100); | ||
102 | if (err < 0) | ||
103 | return err; | ||
104 | |||
105 | msleep(5); | ||
106 | |||
107 | rtsx_pci_init_cmd(pcr); | ||
108 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, | ||
109 | SD_POWER_MASK, SD_VCC_POWER_ON); | ||
110 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, | ||
111 | LDO3318_PWR_MASK, 0x06); | ||
112 | err = rtsx_pci_send_cmd(pcr, 100); | ||
113 | if (err < 0) | ||
114 | return err; | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int rts5249_card_power_off(struct rtsx_pcr *pcr, int card) | ||
120 | { | ||
121 | rtsx_pci_init_cmd(pcr); | ||
122 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, | ||
123 | SD_POWER_MASK, SD_POWER_OFF); | ||
124 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, | ||
125 | LDO3318_PWR_MASK, 0x00); | ||
126 | return rtsx_pci_send_cmd(pcr, 100); | ||
127 | } | ||
128 | |||
129 | static int rts5249_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) | ||
130 | { | ||
131 | int err; | ||
132 | u8 clk_drive, cmd_drive, dat_drive; | ||
133 | |||
134 | if (voltage == OUTPUT_3V3) { | ||
135 | err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, 0x4FC0 | 0x24); | ||
136 | if (err < 0) | ||
137 | return err; | ||
138 | clk_drive = 0x99; | ||
139 | cmd_drive = 0x99; | ||
140 | dat_drive = 0x92; | ||
141 | } else if (voltage == OUTPUT_1V8) { | ||
142 | err = rtsx_pci_write_phy_register(pcr, PHY_BACR, 0x3C02); | ||
143 | if (err < 0) | ||
144 | return err; | ||
145 | err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, 0x4C40 | 0x24); | ||
146 | if (err < 0) | ||
147 | return err; | ||
148 | clk_drive = 0xb3; | ||
149 | cmd_drive = 0xb3; | ||
150 | dat_drive = 0xb3; | ||
151 | } else { | ||
152 | return -EINVAL; | ||
153 | } | ||
154 | |||
155 | /* set pad drive */ | ||
156 | rtsx_pci_init_cmd(pcr); | ||
157 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL, | ||
158 | 0xFF, clk_drive); | ||
159 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL, | ||
160 | 0xFF, cmd_drive); | ||
161 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL, | ||
162 | 0xFF, dat_drive); | ||
163 | return rtsx_pci_send_cmd(pcr, 100); | ||
164 | } | ||
165 | |||
166 | static const struct pcr_ops rts5249_pcr_ops = { | ||
167 | .extra_init_hw = rts5249_extra_init_hw, | ||
168 | .optimize_phy = rts5249_optimize_phy, | ||
169 | .turn_on_led = rts5249_turn_on_led, | ||
170 | .turn_off_led = rts5249_turn_off_led, | ||
171 | .enable_auto_blink = rts5249_enable_auto_blink, | ||
172 | .disable_auto_blink = rts5249_disable_auto_blink, | ||
173 | .card_power_on = rts5249_card_power_on, | ||
174 | .card_power_off = rts5249_card_power_off, | ||
175 | .switch_output_voltage = rts5249_switch_output_voltage, | ||
176 | }; | ||
177 | |||
178 | /* SD Pull Control Enable: | ||
179 | * SD_DAT[3:0] ==> pull up | ||
180 | * SD_CD ==> pull up | ||
181 | * SD_WP ==> pull up | ||
182 | * SD_CMD ==> pull up | ||
183 | * SD_CLK ==> pull down | ||
184 | */ | ||
185 | static const u32 rts5249_sd_pull_ctl_enable_tbl[] = { | ||
186 | RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66), | ||
187 | RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), | ||
188 | RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9), | ||
189 | RTSX_REG_PAIR(CARD_PULL_CTL4, 0xAA), | ||
190 | 0, | ||
191 | }; | ||
192 | |||
193 | /* SD Pull Control Disable: | ||
194 | * SD_DAT[3:0] ==> pull down | ||
195 | * SD_CD ==> pull up | ||
196 | * SD_WP ==> pull down | ||
197 | * SD_CMD ==> pull down | ||
198 | * SD_CLK ==> pull down | ||
199 | */ | ||
200 | static const u32 rts5249_sd_pull_ctl_disable_tbl[] = { | ||
201 | RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66), | ||
202 | RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), | ||
203 | RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5), | ||
204 | RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), | ||
205 | 0, | ||
206 | }; | ||
207 | |||
208 | /* MS Pull Control Enable: | ||
209 | * MS CD ==> pull up | ||
210 | * others ==> pull down | ||
211 | */ | ||
212 | static const u32 rts5249_ms_pull_ctl_enable_tbl[] = { | ||
213 | RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), | ||
214 | RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), | ||
215 | RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), | ||
216 | 0, | ||
217 | }; | ||
218 | |||
219 | /* MS Pull Control Disable: | ||
220 | * MS CD ==> pull up | ||
221 | * others ==> pull down | ||
222 | */ | ||
223 | static const u32 rts5249_ms_pull_ctl_disable_tbl[] = { | ||
224 | RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), | ||
225 | RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), | ||
226 | RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), | ||
227 | 0, | ||
228 | }; | ||
229 | |||
230 | void rts5249_init_params(struct rtsx_pcr *pcr) | ||
231 | { | ||
232 | pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; | ||
233 | pcr->num_slots = 2; | ||
234 | pcr->ops = &rts5249_pcr_ops; | ||
235 | |||
236 | pcr->ic_version = rts5249_get_ic_version(pcr); | ||
237 | pcr->sd_pull_ctl_enable_tbl = rts5249_sd_pull_ctl_enable_tbl; | ||
238 | pcr->sd_pull_ctl_disable_tbl = rts5249_sd_pull_ctl_disable_tbl; | ||
239 | pcr->ms_pull_ctl_enable_tbl = rts5249_ms_pull_ctl_enable_tbl; | ||
240 | pcr->ms_pull_ctl_disable_tbl = rts5249_ms_pull_ctl_disable_tbl; | ||
241 | } | ||
diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index 2f12cc13489a..e968c01ca2ac 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c | |||
@@ -56,6 +56,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = { | |||
56 | { PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 }, | 56 | { PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 }, |
57 | { PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 }, | 57 | { PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 }, |
58 | { PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 }, | 58 | { PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 }, |
59 | { PCI_DEVICE(0x10EC, 0x5249), PCI_CLASS_OTHERS << 16, 0xFF0000 }, | ||
59 | { 0, } | 60 | { 0, } |
60 | }; | 61 | }; |
61 | 62 | ||
@@ -1033,6 +1034,10 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr) | |||
1033 | case 0x5227: | 1034 | case 0x5227: |
1034 | rts5227_init_params(pcr); | 1035 | rts5227_init_params(pcr); |
1035 | break; | 1036 | break; |
1037 | |||
1038 | case 0x5249: | ||
1039 | rts5249_init_params(pcr); | ||
1040 | break; | ||
1036 | } | 1041 | } |
1037 | 1042 | ||
1038 | dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n", | 1043 | dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n", |
@@ -1138,7 +1143,7 @@ static int rtsx_pci_probe(struct pci_dev *pcidev, | |||
1138 | 1143 | ||
1139 | ret = rtsx_pci_acquire_irq(pcr); | 1144 | ret = rtsx_pci_acquire_irq(pcr); |
1140 | if (ret < 0) | 1145 | if (ret < 0) |
1141 | goto free_dma; | 1146 | goto disable_msi; |
1142 | 1147 | ||
1143 | pci_set_master(pcidev); | 1148 | pci_set_master(pcidev); |
1144 | synchronize_irq(pcr->irq); | 1149 | synchronize_irq(pcr->irq); |
@@ -1162,7 +1167,9 @@ static int rtsx_pci_probe(struct pci_dev *pcidev, | |||
1162 | 1167 | ||
1163 | disable_irq: | 1168 | disable_irq: |
1164 | free_irq(pcr->irq, (void *)pcr); | 1169 | free_irq(pcr->irq, (void *)pcr); |
1165 | free_dma: | 1170 | disable_msi: |
1171 | if (pcr->msi_en) | ||
1172 | pci_disable_msi(pcr->pci); | ||
1166 | dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN, | 1173 | dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN, |
1167 | pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr); | 1174 | pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr); |
1168 | unmap: | 1175 | unmap: |
diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h index 2b3ab8a04823..55fcfc25c4e4 100644 --- a/drivers/mfd/rtsx_pcr.h +++ b/drivers/mfd/rtsx_pcr.h | |||
@@ -32,5 +32,6 @@ void rts5209_init_params(struct rtsx_pcr *pcr); | |||
32 | void rts5229_init_params(struct rtsx_pcr *pcr); | 32 | void rts5229_init_params(struct rtsx_pcr *pcr); |
33 | void rtl8411_init_params(struct rtsx_pcr *pcr); | 33 | void rtl8411_init_params(struct rtsx_pcr *pcr); |
34 | void rts5227_init_params(struct rtsx_pcr *pcr); | 34 | void rts5227_init_params(struct rtsx_pcr *pcr); |
35 | void rts5249_init_params(struct rtsx_pcr *pcr); | ||
35 | 36 | ||
36 | #endif | 37 | #endif |
diff --git a/drivers/mfd/si476x-cmd.c b/drivers/mfd/si476x-cmd.c new file mode 100644 index 000000000000..de48b4e88450 --- /dev/null +++ b/drivers/mfd/si476x-cmd.c | |||
@@ -0,0 +1,1553 @@ | |||
1 | /* | ||
2 | * drivers/mfd/si476x-cmd.c -- Subroutines implementing command | ||
3 | * protocol of si476x series of chips | ||
4 | * | ||
5 | * Copyright (C) 2012 Innovative Converged Devices(ICD) | ||
6 | * Copyright (C) 2013 Andrey Smirnov | ||
7 | * | ||
8 | * Author: Andrey Smirnov <andrew.smirnov@gmail.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; version 2 of the License. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/completion.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/atomic.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <linux/gpio.h> | ||
28 | #include <linux/videodev2.h> | ||
29 | |||
30 | #include <linux/mfd/si476x-core.h> | ||
31 | |||
32 | #define msb(x) ((u8)((u16) x >> 8)) | ||
33 | #define lsb(x) ((u8)((u16) x & 0x00FF)) | ||
34 | |||
35 | |||
36 | |||
37 | #define CMD_POWER_UP 0x01 | ||
38 | #define CMD_POWER_UP_A10_NRESP 1 | ||
39 | #define CMD_POWER_UP_A10_NARGS 5 | ||
40 | |||
41 | #define CMD_POWER_UP_A20_NRESP 1 | ||
42 | #define CMD_POWER_UP_A20_NARGS 5 | ||
43 | |||
44 | #define POWER_UP_DELAY_MS 110 | ||
45 | |||
46 | #define CMD_POWER_DOWN 0x11 | ||
47 | #define CMD_POWER_DOWN_A10_NRESP 1 | ||
48 | |||
49 | #define CMD_POWER_DOWN_A20_NRESP 1 | ||
50 | #define CMD_POWER_DOWN_A20_NARGS 1 | ||
51 | |||
52 | #define CMD_FUNC_INFO 0x12 | ||
53 | #define CMD_FUNC_INFO_NRESP 7 | ||
54 | |||
55 | #define CMD_SET_PROPERTY 0x13 | ||
56 | #define CMD_SET_PROPERTY_NARGS 5 | ||
57 | #define CMD_SET_PROPERTY_NRESP 1 | ||
58 | |||
59 | #define CMD_GET_PROPERTY 0x14 | ||
60 | #define CMD_GET_PROPERTY_NARGS 3 | ||
61 | #define CMD_GET_PROPERTY_NRESP 4 | ||
62 | |||
63 | #define CMD_AGC_STATUS 0x17 | ||
64 | #define CMD_AGC_STATUS_NRESP_A10 2 | ||
65 | #define CMD_AGC_STATUS_NRESP_A20 6 | ||
66 | |||
67 | #define PIN_CFG_BYTE(x) (0x7F & (x)) | ||
68 | #define CMD_DIG_AUDIO_PIN_CFG 0x18 | ||
69 | #define CMD_DIG_AUDIO_PIN_CFG_NARGS 4 | ||
70 | #define CMD_DIG_AUDIO_PIN_CFG_NRESP 5 | ||
71 | |||
72 | #define CMD_ZIF_PIN_CFG 0x19 | ||
73 | #define CMD_ZIF_PIN_CFG_NARGS 4 | ||
74 | #define CMD_ZIF_PIN_CFG_NRESP 5 | ||
75 | |||
76 | #define CMD_IC_LINK_GPO_CTL_PIN_CFG 0x1A | ||
77 | #define CMD_IC_LINK_GPO_CTL_PIN_CFG_NARGS 4 | ||
78 | #define CMD_IC_LINK_GPO_CTL_PIN_CFG_NRESP 5 | ||
79 | |||
80 | #define CMD_ANA_AUDIO_PIN_CFG 0x1B | ||
81 | #define CMD_ANA_AUDIO_PIN_CFG_NARGS 1 | ||
82 | #define CMD_ANA_AUDIO_PIN_CFG_NRESP 2 | ||
83 | |||
84 | #define CMD_INTB_PIN_CFG 0x1C | ||
85 | #define CMD_INTB_PIN_CFG_NARGS 2 | ||
86 | #define CMD_INTB_PIN_CFG_A10_NRESP 6 | ||
87 | #define CMD_INTB_PIN_CFG_A20_NRESP 3 | ||
88 | |||
89 | #define CMD_FM_TUNE_FREQ 0x30 | ||
90 | #define CMD_FM_TUNE_FREQ_A10_NARGS 5 | ||
91 | #define CMD_FM_TUNE_FREQ_A20_NARGS 3 | ||
92 | #define CMD_FM_TUNE_FREQ_NRESP 1 | ||
93 | |||
94 | #define CMD_FM_RSQ_STATUS 0x32 | ||
95 | |||
96 | #define CMD_FM_RSQ_STATUS_A10_NARGS 1 | ||
97 | #define CMD_FM_RSQ_STATUS_A10_NRESP 17 | ||
98 | #define CMD_FM_RSQ_STATUS_A30_NARGS 1 | ||
99 | #define CMD_FM_RSQ_STATUS_A30_NRESP 23 | ||
100 | |||
101 | |||
102 | #define CMD_FM_SEEK_START 0x31 | ||
103 | #define CMD_FM_SEEK_START_NARGS 1 | ||
104 | #define CMD_FM_SEEK_START_NRESP 1 | ||
105 | |||
106 | #define CMD_FM_RDS_STATUS 0x36 | ||
107 | #define CMD_FM_RDS_STATUS_NARGS 1 | ||
108 | #define CMD_FM_RDS_STATUS_NRESP 16 | ||
109 | |||
110 | #define CMD_FM_RDS_BLOCKCOUNT 0x37 | ||
111 | #define CMD_FM_RDS_BLOCKCOUNT_NARGS 1 | ||
112 | #define CMD_FM_RDS_BLOCKCOUNT_NRESP 8 | ||
113 | |||
114 | #define CMD_FM_PHASE_DIVERSITY 0x38 | ||
115 | #define CMD_FM_PHASE_DIVERSITY_NARGS 1 | ||
116 | #define CMD_FM_PHASE_DIVERSITY_NRESP 1 | ||
117 | |||
118 | #define CMD_FM_PHASE_DIV_STATUS 0x39 | ||
119 | #define CMD_FM_PHASE_DIV_STATUS_NRESP 2 | ||
120 | |||
121 | #define CMD_AM_TUNE_FREQ 0x40 | ||
122 | #define CMD_AM_TUNE_FREQ_NARGS 3 | ||
123 | #define CMD_AM_TUNE_FREQ_NRESP 1 | ||
124 | |||
125 | #define CMD_AM_RSQ_STATUS 0x42 | ||
126 | #define CMD_AM_RSQ_STATUS_NARGS 1 | ||
127 | #define CMD_AM_RSQ_STATUS_NRESP 13 | ||
128 | |||
129 | #define CMD_AM_SEEK_START 0x41 | ||
130 | #define CMD_AM_SEEK_START_NARGS 1 | ||
131 | #define CMD_AM_SEEK_START_NRESP 1 | ||
132 | |||
133 | |||
134 | #define CMD_AM_ACF_STATUS 0x45 | ||
135 | #define CMD_AM_ACF_STATUS_NRESP 6 | ||
136 | #define CMD_AM_ACF_STATUS_NARGS 1 | ||
137 | |||
138 | #define CMD_FM_ACF_STATUS 0x35 | ||
139 | #define CMD_FM_ACF_STATUS_NRESP 8 | ||
140 | #define CMD_FM_ACF_STATUS_NARGS 1 | ||
141 | |||
142 | #define CMD_MAX_ARGS_COUNT (10) | ||
143 | |||
144 | |||
145 | enum si476x_acf_status_report_bits { | ||
146 | SI476X_ACF_BLEND_INT = (1 << 4), | ||
147 | SI476X_ACF_HIBLEND_INT = (1 << 3), | ||
148 | SI476X_ACF_HICUT_INT = (1 << 2), | ||
149 | SI476X_ACF_CHBW_INT = (1 << 1), | ||
150 | SI476X_ACF_SOFTMUTE_INT = (1 << 0), | ||
151 | |||
152 | SI476X_ACF_SMUTE = (1 << 0), | ||
153 | SI476X_ACF_SMATTN = 0b11111, | ||
154 | SI476X_ACF_PILOT = (1 << 7), | ||
155 | SI476X_ACF_STBLEND = ~SI476X_ACF_PILOT, | ||
156 | }; | ||
157 | |||
158 | enum si476x_agc_status_report_bits { | ||
159 | SI476X_AGC_MXHI = (1 << 5), | ||
160 | SI476X_AGC_MXLO = (1 << 4), | ||
161 | SI476X_AGC_LNAHI = (1 << 3), | ||
162 | SI476X_AGC_LNALO = (1 << 2), | ||
163 | }; | ||
164 | |||
165 | enum si476x_errors { | ||
166 | SI476X_ERR_BAD_COMMAND = 0x10, | ||
167 | SI476X_ERR_BAD_ARG1 = 0x11, | ||
168 | SI476X_ERR_BAD_ARG2 = 0x12, | ||
169 | SI476X_ERR_BAD_ARG3 = 0x13, | ||
170 | SI476X_ERR_BAD_ARG4 = 0x14, | ||
171 | SI476X_ERR_BUSY = 0x18, | ||
172 | SI476X_ERR_BAD_INTERNAL_MEMORY = 0x20, | ||
173 | SI476X_ERR_BAD_PATCH = 0x30, | ||
174 | SI476X_ERR_BAD_BOOT_MODE = 0x31, | ||
175 | SI476X_ERR_BAD_PROPERTY = 0x40, | ||
176 | }; | ||
177 | |||
178 | static int si476x_core_parse_and_nag_about_error(struct si476x_core *core) | ||
179 | { | ||
180 | int err; | ||
181 | char *cause; | ||
182 | u8 buffer[2]; | ||
183 | |||
184 | if (core->revision != SI476X_REVISION_A10) { | ||
185 | err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, | ||
186 | buffer, sizeof(buffer)); | ||
187 | if (err == sizeof(buffer)) { | ||
188 | switch (buffer[1]) { | ||
189 | case SI476X_ERR_BAD_COMMAND: | ||
190 | cause = "Bad command"; | ||
191 | err = -EINVAL; | ||
192 | break; | ||
193 | case SI476X_ERR_BAD_ARG1: | ||
194 | cause = "Bad argument #1"; | ||
195 | err = -EINVAL; | ||
196 | break; | ||
197 | case SI476X_ERR_BAD_ARG2: | ||
198 | cause = "Bad argument #2"; | ||
199 | err = -EINVAL; | ||
200 | break; | ||
201 | case SI476X_ERR_BAD_ARG3: | ||
202 | cause = "Bad argument #3"; | ||
203 | err = -EINVAL; | ||
204 | break; | ||
205 | case SI476X_ERR_BAD_ARG4: | ||
206 | cause = "Bad argument #4"; | ||
207 | err = -EINVAL; | ||
208 | break; | ||
209 | case SI476X_ERR_BUSY: | ||
210 | cause = "Chip is busy"; | ||
211 | err = -EBUSY; | ||
212 | break; | ||
213 | case SI476X_ERR_BAD_INTERNAL_MEMORY: | ||
214 | cause = "Bad internal memory"; | ||
215 | err = -EIO; | ||
216 | break; | ||
217 | case SI476X_ERR_BAD_PATCH: | ||
218 | cause = "Bad patch"; | ||
219 | err = -EINVAL; | ||
220 | break; | ||
221 | case SI476X_ERR_BAD_BOOT_MODE: | ||
222 | cause = "Bad boot mode"; | ||
223 | err = -EINVAL; | ||
224 | break; | ||
225 | case SI476X_ERR_BAD_PROPERTY: | ||
226 | cause = "Bad property"; | ||
227 | err = -EINVAL; | ||
228 | break; | ||
229 | default: | ||
230 | cause = "Unknown"; | ||
231 | err = -EIO; | ||
232 | } | ||
233 | |||
234 | dev_err(&core->client->dev, | ||
235 | "[Chip error status]: %s\n", cause); | ||
236 | } else { | ||
237 | dev_err(&core->client->dev, | ||
238 | "Failed to fetch error code\n"); | ||
239 | err = (err >= 0) ? -EIO : err; | ||
240 | } | ||
241 | } else { | ||
242 | err = -EIO; | ||
243 | } | ||
244 | |||
245 | return err; | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * si476x_core_send_command() - sends a command to si476x and waits its | ||
250 | * response | ||
251 | * @core: si476x_device structure for the device we are | ||
252 | * communicating with | ||
253 | * @command: command id | ||
254 | * @args: command arguments we are sending | ||
255 | * @argn: actual size of @args | ||
256 | * @response: buffer to place the expected response from the device | ||
257 | * @respn: actual size of @response | ||
258 | * @usecs: amount of time to wait before reading the response (in | ||
259 | * usecs) | ||
260 | * | ||
261 | * Function returns 0 on succsess and negative error code on | ||
262 | * failure | ||
263 | */ | ||
264 | static int si476x_core_send_command(struct si476x_core *core, | ||
265 | const u8 command, | ||
266 | const u8 args[], | ||
267 | const int argn, | ||
268 | u8 resp[], | ||
269 | const int respn, | ||
270 | const int usecs) | ||
271 | { | ||
272 | struct i2c_client *client = core->client; | ||
273 | int err; | ||
274 | u8 data[CMD_MAX_ARGS_COUNT + 1]; | ||
275 | |||
276 | if (argn > CMD_MAX_ARGS_COUNT) { | ||
277 | err = -ENOMEM; | ||
278 | goto exit; | ||
279 | } | ||
280 | |||
281 | if (!client->adapter) { | ||
282 | err = -ENODEV; | ||
283 | goto exit; | ||
284 | } | ||
285 | |||
286 | /* First send the command and its arguments */ | ||
287 | data[0] = command; | ||
288 | memcpy(&data[1], args, argn); | ||
289 | dev_dbg(&client->dev, "Command:\n %*ph\n", argn + 1, data); | ||
290 | |||
291 | err = si476x_core_i2c_xfer(core, SI476X_I2C_SEND, | ||
292 | (char *) data, argn + 1); | ||
293 | if (err != argn + 1) { | ||
294 | dev_err(&core->client->dev, | ||
295 | "Error while sending command 0x%02x\n", | ||
296 | command); | ||
297 | err = (err >= 0) ? -EIO : err; | ||
298 | goto exit; | ||
299 | } | ||
300 | /* Set CTS to zero only after the command is send to avoid | ||
301 | * possible racing conditions when working in polling mode */ | ||
302 | atomic_set(&core->cts, 0); | ||
303 | |||
304 | /* if (unlikely(command == CMD_POWER_DOWN) */ | ||
305 | if (!wait_event_timeout(core->command, | ||
306 | atomic_read(&core->cts), | ||
307 | usecs_to_jiffies(usecs) + 1)) | ||
308 | dev_warn(&core->client->dev, | ||
309 | "(%s) [CMD 0x%02x] Answer timeout.\n", | ||
310 | __func__, command); | ||
311 | |||
312 | /* | ||
313 | When working in polling mode, for some reason the tuner will | ||
314 | report CTS bit as being set in the first status byte read, | ||
315 | but all the consequtive ones will return zeros until the | ||
316 | tuner is actually completed the POWER_UP command. To | ||
317 | workaround that we wait for second CTS to be reported | ||
318 | */ | ||
319 | if (unlikely(!core->client->irq && command == CMD_POWER_UP)) { | ||
320 | if (!wait_event_timeout(core->command, | ||
321 | atomic_read(&core->cts), | ||
322 | usecs_to_jiffies(usecs) + 1)) | ||
323 | dev_warn(&core->client->dev, | ||
324 | "(%s) Power up took too much time.\n", | ||
325 | __func__); | ||
326 | } | ||
327 | |||
328 | /* Then get the response */ | ||
329 | err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, resp, respn); | ||
330 | if (err != respn) { | ||
331 | dev_err(&core->client->dev, | ||
332 | "Error while reading response for command 0x%02x\n", | ||
333 | command); | ||
334 | err = (err >= 0) ? -EIO : err; | ||
335 | goto exit; | ||
336 | } | ||
337 | dev_dbg(&client->dev, "Response:\n %*ph\n", respn, resp); | ||
338 | |||
339 | err = 0; | ||
340 | |||
341 | if (resp[0] & SI476X_ERR) { | ||
342 | dev_err(&core->client->dev, | ||
343 | "[CMD 0x%02x] Chip set error flag\n", command); | ||
344 | err = si476x_core_parse_and_nag_about_error(core); | ||
345 | goto exit; | ||
346 | } | ||
347 | |||
348 | if (!(resp[0] & SI476X_CTS)) | ||
349 | err = -EBUSY; | ||
350 | exit: | ||
351 | return err; | ||
352 | } | ||
353 | |||
354 | static int si476x_cmd_clear_stc(struct si476x_core *core) | ||
355 | { | ||
356 | int err; | ||
357 | struct si476x_rsq_status_args args = { | ||
358 | .primary = false, | ||
359 | .rsqack = false, | ||
360 | .attune = false, | ||
361 | .cancel = false, | ||
362 | .stcack = true, | ||
363 | }; | ||
364 | |||
365 | switch (core->power_up_parameters.func) { | ||
366 | case SI476X_FUNC_FM_RECEIVER: | ||
367 | err = si476x_core_cmd_fm_rsq_status(core, &args, NULL); | ||
368 | break; | ||
369 | case SI476X_FUNC_AM_RECEIVER: | ||
370 | err = si476x_core_cmd_am_rsq_status(core, &args, NULL); | ||
371 | break; | ||
372 | default: | ||
373 | err = -EINVAL; | ||
374 | } | ||
375 | |||
376 | return err; | ||
377 | } | ||
378 | |||
379 | static int si476x_cmd_tune_seek_freq(struct si476x_core *core, | ||
380 | uint8_t cmd, | ||
381 | const uint8_t args[], size_t argn, | ||
382 | uint8_t *resp, size_t respn) | ||
383 | { | ||
384 | int err; | ||
385 | |||
386 | |||
387 | atomic_set(&core->stc, 0); | ||
388 | err = si476x_core_send_command(core, cmd, args, argn, resp, respn, | ||
389 | SI476X_TIMEOUT_TUNE); | ||
390 | if (!err) { | ||
391 | wait_event_killable(core->tuning, | ||
392 | atomic_read(&core->stc)); | ||
393 | si476x_cmd_clear_stc(core); | ||
394 | } | ||
395 | |||
396 | return err; | ||
397 | } | ||
398 | |||
399 | /** | ||
400 | * si476x_cmd_func_info() - send 'FUNC_INFO' command to the device | ||
401 | * @core: device to send the command to | ||
402 | * @info: struct si476x_func_info to fill all the information | ||
403 | * returned by the command | ||
404 | * | ||
405 | * The command requests the firmware and patch version for currently | ||
406 | * loaded firmware (dependent on the function of the device FM/AM/WB) | ||
407 | * | ||
408 | * Function returns 0 on succsess and negative error code on | ||
409 | * failure | ||
410 | */ | ||
411 | int si476x_core_cmd_func_info(struct si476x_core *core, | ||
412 | struct si476x_func_info *info) | ||
413 | { | ||
414 | int err; | ||
415 | u8 resp[CMD_FUNC_INFO_NRESP]; | ||
416 | |||
417 | err = si476x_core_send_command(core, CMD_FUNC_INFO, | ||
418 | NULL, 0, | ||
419 | resp, ARRAY_SIZE(resp), | ||
420 | SI476X_DEFAULT_TIMEOUT); | ||
421 | |||
422 | info->firmware.major = resp[1]; | ||
423 | info->firmware.minor[0] = resp[2]; | ||
424 | info->firmware.minor[1] = resp[3]; | ||
425 | |||
426 | info->patch_id = ((u16) resp[4] << 8) | resp[5]; | ||
427 | info->func = resp[6]; | ||
428 | |||
429 | return err; | ||
430 | } | ||
431 | EXPORT_SYMBOL_GPL(si476x_core_cmd_func_info); | ||
432 | |||
433 | /** | ||
434 | * si476x_cmd_set_property() - send 'SET_PROPERTY' command to the device | ||
435 | * @core: device to send the command to | ||
436 | * @property: property address | ||
437 | * @value: property value | ||
438 | * | ||
439 | * Function returns 0 on succsess and negative error code on | ||
440 | * failure | ||
441 | */ | ||
442 | int si476x_core_cmd_set_property(struct si476x_core *core, | ||
443 | u16 property, u16 value) | ||
444 | { | ||
445 | u8 resp[CMD_SET_PROPERTY_NRESP]; | ||
446 | const u8 args[CMD_SET_PROPERTY_NARGS] = { | ||
447 | 0x00, | ||
448 | msb(property), | ||
449 | lsb(property), | ||
450 | msb(value), | ||
451 | lsb(value), | ||
452 | }; | ||
453 | |||
454 | return si476x_core_send_command(core, CMD_SET_PROPERTY, | ||
455 | args, ARRAY_SIZE(args), | ||
456 | resp, ARRAY_SIZE(resp), | ||
457 | SI476X_DEFAULT_TIMEOUT); | ||
458 | } | ||
459 | EXPORT_SYMBOL_GPL(si476x_core_cmd_set_property); | ||
460 | |||
461 | /** | ||
462 | * si476x_cmd_get_property() - send 'GET_PROPERTY' command to the device | ||
463 | * @core: device to send the command to | ||
464 | * @property: property address | ||
465 | * | ||
466 | * Function return the value of property as u16 on success or a | ||
467 | * negative error on failure | ||
468 | */ | ||
469 | int si476x_core_cmd_get_property(struct si476x_core *core, u16 property) | ||
470 | { | ||
471 | int err; | ||
472 | u8 resp[CMD_GET_PROPERTY_NRESP]; | ||
473 | const u8 args[CMD_GET_PROPERTY_NARGS] = { | ||
474 | 0x00, | ||
475 | msb(property), | ||
476 | lsb(property), | ||
477 | }; | ||
478 | |||
479 | err = si476x_core_send_command(core, CMD_GET_PROPERTY, | ||
480 | args, ARRAY_SIZE(args), | ||
481 | resp, ARRAY_SIZE(resp), | ||
482 | SI476X_DEFAULT_TIMEOUT); | ||
483 | if (err < 0) | ||
484 | return err; | ||
485 | else | ||
486 | return be16_to_cpup((__be16 *)(resp + 2)); | ||
487 | } | ||
488 | EXPORT_SYMBOL_GPL(si476x_core_cmd_get_property); | ||
489 | |||
490 | /** | ||
491 | * si476x_cmd_dig_audio_pin_cfg() - send 'DIG_AUDIO_PIN_CFG' command to | ||
492 | * the device | ||
493 | * @core: device to send the command to | ||
494 | * @dclk: DCLK pin function configuration: | ||
495 | * #SI476X_DCLK_NOOP - do not modify the behaviour | ||
496 | * #SI476X_DCLK_TRISTATE - put the pin in tristate condition, | ||
497 | * enable 1MOhm pulldown | ||
498 | * #SI476X_DCLK_DAUDIO - set the pin to be a part of digital | ||
499 | * audio interface | ||
500 | * @dfs: DFS pin function configuration: | ||
501 | * #SI476X_DFS_NOOP - do not modify the behaviour | ||
502 | * #SI476X_DFS_TRISTATE - put the pin in tristate condition, | ||
503 | * enable 1MOhm pulldown | ||
504 | * SI476X_DFS_DAUDIO - set the pin to be a part of digital | ||
505 | * audio interface | ||
506 | * @dout - DOUT pin function configuration: | ||
507 | * SI476X_DOUT_NOOP - do not modify the behaviour | ||
508 | * SI476X_DOUT_TRISTATE - put the pin in tristate condition, | ||
509 | * enable 1MOhm pulldown | ||
510 | * SI476X_DOUT_I2S_OUTPUT - set this pin to be digital out on I2S | ||
511 | * port 1 | ||
512 | * SI476X_DOUT_I2S_INPUT - set this pin to be digital in on I2S | ||
513 | * port 1 | ||
514 | * @xout - XOUT pin function configuration: | ||
515 | * SI476X_XOUT_NOOP - do not modify the behaviour | ||
516 | * SI476X_XOUT_TRISTATE - put the pin in tristate condition, | ||
517 | * enable 1MOhm pulldown | ||
518 | * SI476X_XOUT_I2S_INPUT - set this pin to be digital in on I2S | ||
519 | * port 1 | ||
520 | * SI476X_XOUT_MODE_SELECT - set this pin to be the input that | ||
521 | * selects the mode of the I2S audio | ||
522 | * combiner (analog or HD) | ||
523 | * [SI4761/63/65/67 Only] | ||
524 | * | ||
525 | * Function returns 0 on success and negative error code on failure | ||
526 | */ | ||
527 | int si476x_core_cmd_dig_audio_pin_cfg(struct si476x_core *core, | ||
528 | enum si476x_dclk_config dclk, | ||
529 | enum si476x_dfs_config dfs, | ||
530 | enum si476x_dout_config dout, | ||
531 | enum si476x_xout_config xout) | ||
532 | { | ||
533 | u8 resp[CMD_DIG_AUDIO_PIN_CFG_NRESP]; | ||
534 | const u8 args[CMD_DIG_AUDIO_PIN_CFG_NARGS] = { | ||
535 | PIN_CFG_BYTE(dclk), | ||
536 | PIN_CFG_BYTE(dfs), | ||
537 | PIN_CFG_BYTE(dout), | ||
538 | PIN_CFG_BYTE(xout), | ||
539 | }; | ||
540 | |||
541 | return si476x_core_send_command(core, CMD_DIG_AUDIO_PIN_CFG, | ||
542 | args, ARRAY_SIZE(args), | ||
543 | resp, ARRAY_SIZE(resp), | ||
544 | SI476X_DEFAULT_TIMEOUT); | ||
545 | } | ||
546 | EXPORT_SYMBOL_GPL(si476x_core_cmd_dig_audio_pin_cfg); | ||
547 | |||
548 | /** | ||
549 | * si476x_cmd_zif_pin_cfg - send 'ZIF_PIN_CFG_COMMAND' | ||
550 | * @core - device to send the command to | ||
551 | * @iqclk - IQCL pin function configuration: | ||
552 | * SI476X_IQCLK_NOOP - do not modify the behaviour | ||
553 | * SI476X_IQCLK_TRISTATE - put the pin in tristate condition, | ||
554 | * enable 1MOhm pulldown | ||
555 | * SI476X_IQCLK_IQ - set pin to be a part of I/Q interace | ||
556 | * in master mode | ||
557 | * @iqfs - IQFS pin function configuration: | ||
558 | * SI476X_IQFS_NOOP - do not modify the behaviour | ||
559 | * SI476X_IQFS_TRISTATE - put the pin in tristate condition, | ||
560 | * enable 1MOhm pulldown | ||
561 | * SI476X_IQFS_IQ - set pin to be a part of I/Q interace | ||
562 | * in master mode | ||
563 | * @iout - IOUT pin function configuration: | ||
564 | * SI476X_IOUT_NOOP - do not modify the behaviour | ||
565 | * SI476X_IOUT_TRISTATE - put the pin in tristate condition, | ||
566 | * enable 1MOhm pulldown | ||
567 | * SI476X_IOUT_OUTPUT - set pin to be I out | ||
568 | * @qout - QOUT pin function configuration: | ||
569 | * SI476X_QOUT_NOOP - do not modify the behaviour | ||
570 | * SI476X_QOUT_TRISTATE - put the pin in tristate condition, | ||
571 | * enable 1MOhm pulldown | ||
572 | * SI476X_QOUT_OUTPUT - set pin to be Q out | ||
573 | * | ||
574 | * Function returns 0 on success and negative error code on failure | ||
575 | */ | ||
576 | int si476x_core_cmd_zif_pin_cfg(struct si476x_core *core, | ||
577 | enum si476x_iqclk_config iqclk, | ||
578 | enum si476x_iqfs_config iqfs, | ||
579 | enum si476x_iout_config iout, | ||
580 | enum si476x_qout_config qout) | ||
581 | { | ||
582 | u8 resp[CMD_ZIF_PIN_CFG_NRESP]; | ||
583 | const u8 args[CMD_ZIF_PIN_CFG_NARGS] = { | ||
584 | PIN_CFG_BYTE(iqclk), | ||
585 | PIN_CFG_BYTE(iqfs), | ||
586 | PIN_CFG_BYTE(iout), | ||
587 | PIN_CFG_BYTE(qout), | ||
588 | }; | ||
589 | |||
590 | return si476x_core_send_command(core, CMD_ZIF_PIN_CFG, | ||
591 | args, ARRAY_SIZE(args), | ||
592 | resp, ARRAY_SIZE(resp), | ||
593 | SI476X_DEFAULT_TIMEOUT); | ||
594 | } | ||
595 | EXPORT_SYMBOL_GPL(si476x_core_cmd_zif_pin_cfg); | ||
596 | |||
597 | /** | ||
598 | * si476x_cmd_ic_link_gpo_ctl_pin_cfg - send | ||
599 | * 'IC_LINK_GPIO_CTL_PIN_CFG' comand to the device | ||
600 | * @core - device to send the command to | ||
601 | * @icin - ICIN pin function configuration: | ||
602 | * SI476X_ICIN_NOOP - do not modify the behaviour | ||
603 | * SI476X_ICIN_TRISTATE - put the pin in tristate condition, | ||
604 | * enable 1MOhm pulldown | ||
605 | * SI476X_ICIN_GPO1_HIGH - set pin to be an output, drive it high | ||
606 | * SI476X_ICIN_GPO1_LOW - set pin to be an output, drive it low | ||
607 | * SI476X_ICIN_IC_LINK - set the pin to be a part of Inter-Chip link | ||
608 | * @icip - ICIP pin function configuration: | ||
609 | * SI476X_ICIP_NOOP - do not modify the behaviour | ||
610 | * SI476X_ICIP_TRISTATE - put the pin in tristate condition, | ||
611 | * enable 1MOhm pulldown | ||
612 | * SI476X_ICIP_GPO1_HIGH - set pin to be an output, drive it high | ||
613 | * SI476X_ICIP_GPO1_LOW - set pin to be an output, drive it low | ||
614 | * SI476X_ICIP_IC_LINK - set the pin to be a part of Inter-Chip link | ||
615 | * @icon - ICON pin function configuration: | ||
616 | * SI476X_ICON_NOOP - do not modify the behaviour | ||
617 | * SI476X_ICON_TRISTATE - put the pin in tristate condition, | ||
618 | * enable 1MOhm pulldown | ||
619 | * SI476X_ICON_I2S - set the pin to be a part of audio | ||
620 | * interface in slave mode (DCLK) | ||
621 | * SI476X_ICON_IC_LINK - set the pin to be a part of Inter-Chip link | ||
622 | * @icop - ICOP pin function configuration: | ||
623 | * SI476X_ICOP_NOOP - do not modify the behaviour | ||
624 | * SI476X_ICOP_TRISTATE - put the pin in tristate condition, | ||
625 | * enable 1MOhm pulldown | ||
626 | * SI476X_ICOP_I2S - set the pin to be a part of audio | ||
627 | * interface in slave mode (DOUT) | ||
628 | * [Si4761/63/65/67 Only] | ||
629 | * SI476X_ICOP_IC_LINK - set the pin to be a part of Inter-Chip link | ||
630 | * | ||
631 | * Function returns 0 on success and negative error code on failure | ||
632 | */ | ||
633 | int si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(struct si476x_core *core, | ||
634 | enum si476x_icin_config icin, | ||
635 | enum si476x_icip_config icip, | ||
636 | enum si476x_icon_config icon, | ||
637 | enum si476x_icop_config icop) | ||
638 | { | ||
639 | u8 resp[CMD_IC_LINK_GPO_CTL_PIN_CFG_NRESP]; | ||
640 | const u8 args[CMD_IC_LINK_GPO_CTL_PIN_CFG_NARGS] = { | ||
641 | PIN_CFG_BYTE(icin), | ||
642 | PIN_CFG_BYTE(icip), | ||
643 | PIN_CFG_BYTE(icon), | ||
644 | PIN_CFG_BYTE(icop), | ||
645 | }; | ||
646 | |||
647 | return si476x_core_send_command(core, CMD_IC_LINK_GPO_CTL_PIN_CFG, | ||
648 | args, ARRAY_SIZE(args), | ||
649 | resp, ARRAY_SIZE(resp), | ||
650 | SI476X_DEFAULT_TIMEOUT); | ||
651 | } | ||
652 | EXPORT_SYMBOL_GPL(si476x_core_cmd_ic_link_gpo_ctl_pin_cfg); | ||
653 | |||
654 | /** | ||
655 | * si476x_cmd_ana_audio_pin_cfg - send 'ANA_AUDIO_PIN_CFG' to the | ||
656 | * device | ||
657 | * @core - device to send the command to | ||
658 | * @lrout - LROUT pin function configuration: | ||
659 | * SI476X_LROUT_NOOP - do not modify the behaviour | ||
660 | * SI476X_LROUT_TRISTATE - put the pin in tristate condition, | ||
661 | * enable 1MOhm pulldown | ||
662 | * SI476X_LROUT_AUDIO - set pin to be audio output | ||
663 | * SI476X_LROUT_MPX - set pin to be MPX output | ||
664 | * | ||
665 | * Function returns 0 on success and negative error code on failure | ||
666 | */ | ||
667 | int si476x_core_cmd_ana_audio_pin_cfg(struct si476x_core *core, | ||
668 | enum si476x_lrout_config lrout) | ||
669 | { | ||
670 | u8 resp[CMD_ANA_AUDIO_PIN_CFG_NRESP]; | ||
671 | const u8 args[CMD_ANA_AUDIO_PIN_CFG_NARGS] = { | ||
672 | PIN_CFG_BYTE(lrout), | ||
673 | }; | ||
674 | |||
675 | return si476x_core_send_command(core, CMD_ANA_AUDIO_PIN_CFG, | ||
676 | args, ARRAY_SIZE(args), | ||
677 | resp, ARRAY_SIZE(resp), | ||
678 | SI476X_DEFAULT_TIMEOUT); | ||
679 | } | ||
680 | EXPORT_SYMBOL_GPL(si476x_core_cmd_ana_audio_pin_cfg); | ||
681 | |||
682 | |||
683 | /** | ||
684 | * si476x_cmd_intb_pin_cfg - send 'INTB_PIN_CFG' command to the device | ||
685 | * @core - device to send the command to | ||
686 | * @intb - INTB pin function configuration: | ||
687 | * SI476X_INTB_NOOP - do not modify the behaviour | ||
688 | * SI476X_INTB_TRISTATE - put the pin in tristate condition, | ||
689 | * enable 1MOhm pulldown | ||
690 | * SI476X_INTB_DAUDIO - set pin to be a part of digital | ||
691 | * audio interface in slave mode | ||
692 | * SI476X_INTB_IRQ - set pin to be an interrupt request line | ||
693 | * @a1 - A1 pin function configuration: | ||
694 | * SI476X_A1_NOOP - do not modify the behaviour | ||
695 | * SI476X_A1_TRISTATE - put the pin in tristate condition, | ||
696 | * enable 1MOhm pulldown | ||
697 | * SI476X_A1_IRQ - set pin to be an interrupt request line | ||
698 | * | ||
699 | * Function returns 0 on success and negative error code on failure | ||
700 | */ | ||
701 | static int si476x_core_cmd_intb_pin_cfg_a10(struct si476x_core *core, | ||
702 | enum si476x_intb_config intb, | ||
703 | enum si476x_a1_config a1) | ||
704 | { | ||
705 | u8 resp[CMD_INTB_PIN_CFG_A10_NRESP]; | ||
706 | const u8 args[CMD_INTB_PIN_CFG_NARGS] = { | ||
707 | PIN_CFG_BYTE(intb), | ||
708 | PIN_CFG_BYTE(a1), | ||
709 | }; | ||
710 | |||
711 | return si476x_core_send_command(core, CMD_INTB_PIN_CFG, | ||
712 | args, ARRAY_SIZE(args), | ||
713 | resp, ARRAY_SIZE(resp), | ||
714 | SI476X_DEFAULT_TIMEOUT); | ||
715 | } | ||
716 | |||
717 | static int si476x_core_cmd_intb_pin_cfg_a20(struct si476x_core *core, | ||
718 | enum si476x_intb_config intb, | ||
719 | enum si476x_a1_config a1) | ||
720 | { | ||
721 | u8 resp[CMD_INTB_PIN_CFG_A20_NRESP]; | ||
722 | const u8 args[CMD_INTB_PIN_CFG_NARGS] = { | ||
723 | PIN_CFG_BYTE(intb), | ||
724 | PIN_CFG_BYTE(a1), | ||
725 | }; | ||
726 | |||
727 | return si476x_core_send_command(core, CMD_INTB_PIN_CFG, | ||
728 | args, ARRAY_SIZE(args), | ||
729 | resp, ARRAY_SIZE(resp), | ||
730 | SI476X_DEFAULT_TIMEOUT); | ||
731 | } | ||
732 | |||
733 | |||
734 | |||
735 | /** | ||
736 | * si476x_cmd_am_rsq_status - send 'AM_RSQ_STATUS' command to the | ||
737 | * device | ||
738 | * @core - device to send the command to | ||
739 | * @rsqack - if set command clears RSQINT, SNRINT, SNRLINT, RSSIHINT, | ||
740 | * RSSSILINT, BLENDINT, MULTHINT and MULTLINT | ||
741 | * @attune - when set the values in the status report are the values | ||
742 | * that were calculated at tune | ||
743 | * @cancel - abort ongoing seek/tune opertation | ||
744 | * @stcack - clear the STCINT bin in status register | ||
745 | * @report - all signal quality information retured by the command | ||
746 | * (if NULL then the output of the command is ignored) | ||
747 | * | ||
748 | * Function returns 0 on success and negative error code on failure | ||
749 | */ | ||
750 | int si476x_core_cmd_am_rsq_status(struct si476x_core *core, | ||
751 | struct si476x_rsq_status_args *rsqargs, | ||
752 | struct si476x_rsq_status_report *report) | ||
753 | { | ||
754 | int err; | ||
755 | u8 resp[CMD_AM_RSQ_STATUS_NRESP]; | ||
756 | const u8 args[CMD_AM_RSQ_STATUS_NARGS] = { | ||
757 | rsqargs->rsqack << 3 | rsqargs->attune << 2 | | ||
758 | rsqargs->cancel << 1 | rsqargs->stcack, | ||
759 | }; | ||
760 | |||
761 | err = si476x_core_send_command(core, CMD_AM_RSQ_STATUS, | ||
762 | args, ARRAY_SIZE(args), | ||
763 | resp, ARRAY_SIZE(resp), | ||
764 | SI476X_DEFAULT_TIMEOUT); | ||
765 | /* | ||
766 | * Besides getting received signal quality information this | ||
767 | * command can be used to just acknowledge different interrupt | ||
768 | * flags in those cases it is useless to copy and parse | ||
769 | * received data so user can pass NULL, and thus avoid | ||
770 | * unnecessary copying. | ||
771 | */ | ||
772 | if (!report) | ||
773 | return err; | ||
774 | |||
775 | report->snrhint = 0b00001000 & resp[1]; | ||
776 | report->snrlint = 0b00000100 & resp[1]; | ||
777 | report->rssihint = 0b00000010 & resp[1]; | ||
778 | report->rssilint = 0b00000001 & resp[1]; | ||
779 | |||
780 | report->bltf = 0b10000000 & resp[2]; | ||
781 | report->snr_ready = 0b00100000 & resp[2]; | ||
782 | report->rssiready = 0b00001000 & resp[2]; | ||
783 | report->afcrl = 0b00000010 & resp[2]; | ||
784 | report->valid = 0b00000001 & resp[2]; | ||
785 | |||
786 | report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); | ||
787 | report->freqoff = resp[5]; | ||
788 | report->rssi = resp[6]; | ||
789 | report->snr = resp[7]; | ||
790 | report->lassi = resp[9]; | ||
791 | report->hassi = resp[10]; | ||
792 | report->mult = resp[11]; | ||
793 | report->dev = resp[12]; | ||
794 | |||
795 | return err; | ||
796 | } | ||
797 | EXPORT_SYMBOL_GPL(si476x_core_cmd_am_rsq_status); | ||
798 | |||
799 | int si476x_core_cmd_fm_acf_status(struct si476x_core *core, | ||
800 | struct si476x_acf_status_report *report) | ||
801 | { | ||
802 | int err; | ||
803 | u8 resp[CMD_FM_ACF_STATUS_NRESP]; | ||
804 | const u8 args[CMD_FM_ACF_STATUS_NARGS] = { | ||
805 | 0x0, | ||
806 | }; | ||
807 | |||
808 | if (!report) | ||
809 | return -EINVAL; | ||
810 | |||
811 | err = si476x_core_send_command(core, CMD_FM_ACF_STATUS, | ||
812 | args, ARRAY_SIZE(args), | ||
813 | resp, ARRAY_SIZE(resp), | ||
814 | SI476X_DEFAULT_TIMEOUT); | ||
815 | if (err < 0) | ||
816 | return err; | ||
817 | |||
818 | report->blend_int = resp[1] & SI476X_ACF_BLEND_INT; | ||
819 | report->hblend_int = resp[1] & SI476X_ACF_HIBLEND_INT; | ||
820 | report->hicut_int = resp[1] & SI476X_ACF_HICUT_INT; | ||
821 | report->chbw_int = resp[1] & SI476X_ACF_CHBW_INT; | ||
822 | report->softmute_int = resp[1] & SI476X_ACF_SOFTMUTE_INT; | ||
823 | report->smute = resp[2] & SI476X_ACF_SMUTE; | ||
824 | report->smattn = resp[3] & SI476X_ACF_SMATTN; | ||
825 | report->chbw = resp[4]; | ||
826 | report->hicut = resp[5]; | ||
827 | report->hiblend = resp[6]; | ||
828 | report->pilot = resp[7] & SI476X_ACF_PILOT; | ||
829 | report->stblend = resp[7] & SI476X_ACF_STBLEND; | ||
830 | |||
831 | return err; | ||
832 | } | ||
833 | EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_acf_status); | ||
834 | |||
835 | int si476x_core_cmd_am_acf_status(struct si476x_core *core, | ||
836 | struct si476x_acf_status_report *report) | ||
837 | { | ||
838 | int err; | ||
839 | u8 resp[CMD_AM_ACF_STATUS_NRESP]; | ||
840 | const u8 args[CMD_AM_ACF_STATUS_NARGS] = { | ||
841 | 0x0, | ||
842 | }; | ||
843 | |||
844 | if (!report) | ||
845 | return -EINVAL; | ||
846 | |||
847 | err = si476x_core_send_command(core, CMD_AM_ACF_STATUS, | ||
848 | args, ARRAY_SIZE(args), | ||
849 | resp, ARRAY_SIZE(resp), | ||
850 | SI476X_DEFAULT_TIMEOUT); | ||
851 | if (err < 0) | ||
852 | return err; | ||
853 | |||
854 | report->blend_int = resp[1] & SI476X_ACF_BLEND_INT; | ||
855 | report->hblend_int = resp[1] & SI476X_ACF_HIBLEND_INT; | ||
856 | report->hicut_int = resp[1] & SI476X_ACF_HICUT_INT; | ||
857 | report->chbw_int = resp[1] & SI476X_ACF_CHBW_INT; | ||
858 | report->softmute_int = resp[1] & SI476X_ACF_SOFTMUTE_INT; | ||
859 | report->smute = resp[2] & SI476X_ACF_SMUTE; | ||
860 | report->smattn = resp[3] & SI476X_ACF_SMATTN; | ||
861 | report->chbw = resp[4]; | ||
862 | report->hicut = resp[5]; | ||
863 | |||
864 | return err; | ||
865 | } | ||
866 | EXPORT_SYMBOL_GPL(si476x_core_cmd_am_acf_status); | ||
867 | |||
868 | |||
869 | /** | ||
870 | * si476x_cmd_fm_seek_start - send 'FM_SEEK_START' command to the | ||
871 | * device | ||
872 | * @core - device to send the command to | ||
873 | * @seekup - if set the direction of the search is 'up' | ||
874 | * @wrap - if set seek wraps when hitting band limit | ||
875 | * | ||
876 | * This function begins search for a valid station. The station is | ||
877 | * considered valid when 'FM_VALID_SNR_THRESHOLD' and | ||
878 | * 'FM_VALID_RSSI_THRESHOLD' and 'FM_VALID_MAX_TUNE_ERROR' criteria | ||
879 | * are met. | ||
880 | } * | ||
881 | * Function returns 0 on success and negative error code on failure | ||
882 | */ | ||
883 | int si476x_core_cmd_fm_seek_start(struct si476x_core *core, | ||
884 | bool seekup, bool wrap) | ||
885 | { | ||
886 | u8 resp[CMD_FM_SEEK_START_NRESP]; | ||
887 | const u8 args[CMD_FM_SEEK_START_NARGS] = { | ||
888 | seekup << 3 | wrap << 2, | ||
889 | }; | ||
890 | |||
891 | return si476x_cmd_tune_seek_freq(core, CMD_FM_SEEK_START, | ||
892 | args, sizeof(args), | ||
893 | resp, sizeof(resp)); | ||
894 | } | ||
895 | EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_seek_start); | ||
896 | |||
897 | /** | ||
898 | * si476x_cmd_fm_rds_status - send 'FM_RDS_STATUS' command to the | ||
899 | * device | ||
900 | * @core - device to send the command to | ||
901 | * @status_only - if set the data is not removed from RDSFIFO, | ||
902 | * RDSFIFOUSED is not decremented and data in all the | ||
903 | * rest RDS data contains the last valid info received | ||
904 | * @mtfifo if set the command clears RDS receive FIFO | ||
905 | * @intack if set the command clards the RDSINT bit. | ||
906 | * | ||
907 | * Function returns 0 on success and negative error code on failure | ||
908 | */ | ||
909 | int si476x_core_cmd_fm_rds_status(struct si476x_core *core, | ||
910 | bool status_only, | ||
911 | bool mtfifo, | ||
912 | bool intack, | ||
913 | struct si476x_rds_status_report *report) | ||
914 | { | ||
915 | int err; | ||
916 | u8 resp[CMD_FM_RDS_STATUS_NRESP]; | ||
917 | const u8 args[CMD_FM_RDS_STATUS_NARGS] = { | ||
918 | status_only << 2 | mtfifo << 1 | intack, | ||
919 | }; | ||
920 | |||
921 | err = si476x_core_send_command(core, CMD_FM_RDS_STATUS, | ||
922 | args, ARRAY_SIZE(args), | ||
923 | resp, ARRAY_SIZE(resp), | ||
924 | SI476X_DEFAULT_TIMEOUT); | ||
925 | /* | ||
926 | * Besides getting RDS status information this command can be | ||
927 | * used to just acknowledge different interrupt flags in those | ||
928 | * cases it is useless to copy and parse received data so user | ||
929 | * can pass NULL, and thus avoid unnecessary copying. | ||
930 | */ | ||
931 | if (err < 0 || report == NULL) | ||
932 | return err; | ||
933 | |||
934 | report->rdstpptyint = 0b00010000 & resp[1]; | ||
935 | report->rdspiint = 0b00001000 & resp[1]; | ||
936 | report->rdssyncint = 0b00000010 & resp[1]; | ||
937 | report->rdsfifoint = 0b00000001 & resp[1]; | ||
938 | |||
939 | report->tpptyvalid = 0b00010000 & resp[2]; | ||
940 | report->pivalid = 0b00001000 & resp[2]; | ||
941 | report->rdssync = 0b00000010 & resp[2]; | ||
942 | report->rdsfifolost = 0b00000001 & resp[2]; | ||
943 | |||
944 | report->tp = 0b00100000 & resp[3]; | ||
945 | report->pty = 0b00011111 & resp[3]; | ||
946 | |||
947 | report->pi = be16_to_cpup((__be16 *)(resp + 4)); | ||
948 | report->rdsfifoused = resp[6]; | ||
949 | |||
950 | report->ble[V4L2_RDS_BLOCK_A] = 0b11000000 & resp[7]; | ||
951 | report->ble[V4L2_RDS_BLOCK_B] = 0b00110000 & resp[7]; | ||
952 | report->ble[V4L2_RDS_BLOCK_C] = 0b00001100 & resp[7]; | ||
953 | report->ble[V4L2_RDS_BLOCK_D] = 0b00000011 & resp[7]; | ||
954 | |||
955 | report->rds[V4L2_RDS_BLOCK_A].block = V4L2_RDS_BLOCK_A; | ||
956 | report->rds[V4L2_RDS_BLOCK_A].msb = resp[8]; | ||
957 | report->rds[V4L2_RDS_BLOCK_A].lsb = resp[9]; | ||
958 | |||
959 | report->rds[V4L2_RDS_BLOCK_B].block = V4L2_RDS_BLOCK_B; | ||
960 | report->rds[V4L2_RDS_BLOCK_B].msb = resp[10]; | ||
961 | report->rds[V4L2_RDS_BLOCK_B].lsb = resp[11]; | ||
962 | |||
963 | report->rds[V4L2_RDS_BLOCK_C].block = V4L2_RDS_BLOCK_C; | ||
964 | report->rds[V4L2_RDS_BLOCK_C].msb = resp[12]; | ||
965 | report->rds[V4L2_RDS_BLOCK_C].lsb = resp[13]; | ||
966 | |||
967 | report->rds[V4L2_RDS_BLOCK_D].block = V4L2_RDS_BLOCK_D; | ||
968 | report->rds[V4L2_RDS_BLOCK_D].msb = resp[14]; | ||
969 | report->rds[V4L2_RDS_BLOCK_D].lsb = resp[15]; | ||
970 | |||
971 | return err; | ||
972 | } | ||
973 | EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rds_status); | ||
974 | |||
975 | int si476x_core_cmd_fm_rds_blockcount(struct si476x_core *core, | ||
976 | bool clear, | ||
977 | struct si476x_rds_blockcount_report *report) | ||
978 | { | ||
979 | int err; | ||
980 | u8 resp[CMD_FM_RDS_BLOCKCOUNT_NRESP]; | ||
981 | const u8 args[CMD_FM_RDS_BLOCKCOUNT_NARGS] = { | ||
982 | clear, | ||
983 | }; | ||
984 | |||
985 | if (!report) | ||
986 | return -EINVAL; | ||
987 | |||
988 | err = si476x_core_send_command(core, CMD_FM_RDS_BLOCKCOUNT, | ||
989 | args, ARRAY_SIZE(args), | ||
990 | resp, ARRAY_SIZE(resp), | ||
991 | SI476X_DEFAULT_TIMEOUT); | ||
992 | |||
993 | if (!err) { | ||
994 | report->expected = be16_to_cpup((__be16 *)(resp + 2)); | ||
995 | report->received = be16_to_cpup((__be16 *)(resp + 4)); | ||
996 | report->uncorrectable = be16_to_cpup((__be16 *)(resp + 6)); | ||
997 | } | ||
998 | |||
999 | return err; | ||
1000 | } | ||
1001 | EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rds_blockcount); | ||
1002 | |||
1003 | int si476x_core_cmd_fm_phase_diversity(struct si476x_core *core, | ||
1004 | enum si476x_phase_diversity_mode mode) | ||
1005 | { | ||
1006 | u8 resp[CMD_FM_PHASE_DIVERSITY_NRESP]; | ||
1007 | const u8 args[CMD_FM_PHASE_DIVERSITY_NARGS] = { | ||
1008 | mode & 0b111, | ||
1009 | }; | ||
1010 | |||
1011 | return si476x_core_send_command(core, CMD_FM_PHASE_DIVERSITY, | ||
1012 | args, ARRAY_SIZE(args), | ||
1013 | resp, ARRAY_SIZE(resp), | ||
1014 | SI476X_DEFAULT_TIMEOUT); | ||
1015 | } | ||
1016 | EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_diversity); | ||
1017 | /** | ||
1018 | * si476x_core_cmd_fm_phase_div_status() - get the phase diversity | ||
1019 | * status | ||
1020 | * | ||
1021 | * @core: si476x device | ||
1022 | * | ||
1023 | * NOTE caller must hold core lock | ||
1024 | * | ||
1025 | * Function returns the value of the status bit in case of success and | ||
1026 | * negative error code in case of failre. | ||
1027 | */ | ||
1028 | int si476x_core_cmd_fm_phase_div_status(struct si476x_core *core) | ||
1029 | { | ||
1030 | int err; | ||
1031 | u8 resp[CMD_FM_PHASE_DIV_STATUS_NRESP]; | ||
1032 | |||
1033 | err = si476x_core_send_command(core, CMD_FM_PHASE_DIV_STATUS, | ||
1034 | NULL, 0, | ||
1035 | resp, ARRAY_SIZE(resp), | ||
1036 | SI476X_DEFAULT_TIMEOUT); | ||
1037 | |||
1038 | return (err < 0) ? err : resp[1]; | ||
1039 | } | ||
1040 | EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_div_status); | ||
1041 | |||
1042 | |||
1043 | /** | ||
1044 | * si476x_cmd_am_seek_start - send 'FM_SEEK_START' command to the | ||
1045 | * device | ||
1046 | * @core - device to send the command to | ||
1047 | * @seekup - if set the direction of the search is 'up' | ||
1048 | * @wrap - if set seek wraps when hitting band limit | ||
1049 | * | ||
1050 | * This function begins search for a valid station. The station is | ||
1051 | * considered valid when 'FM_VALID_SNR_THRESHOLD' and | ||
1052 | * 'FM_VALID_RSSI_THRESHOLD' and 'FM_VALID_MAX_TUNE_ERROR' criteria | ||
1053 | * are met. | ||
1054 | * | ||
1055 | * Function returns 0 on success and negative error code on failure | ||
1056 | */ | ||
1057 | int si476x_core_cmd_am_seek_start(struct si476x_core *core, | ||
1058 | bool seekup, bool wrap) | ||
1059 | { | ||
1060 | u8 resp[CMD_AM_SEEK_START_NRESP]; | ||
1061 | const u8 args[CMD_AM_SEEK_START_NARGS] = { | ||
1062 | seekup << 3 | wrap << 2, | ||
1063 | }; | ||
1064 | |||
1065 | return si476x_cmd_tune_seek_freq(core, CMD_AM_SEEK_START, | ||
1066 | args, sizeof(args), | ||
1067 | resp, sizeof(resp)); | ||
1068 | } | ||
1069 | EXPORT_SYMBOL_GPL(si476x_core_cmd_am_seek_start); | ||
1070 | |||
1071 | |||
1072 | |||
1073 | static int si476x_core_cmd_power_up_a10(struct si476x_core *core, | ||
1074 | struct si476x_power_up_args *puargs) | ||
1075 | { | ||
1076 | u8 resp[CMD_POWER_UP_A10_NRESP]; | ||
1077 | const bool intsel = (core->pinmux.a1 == SI476X_A1_IRQ); | ||
1078 | const bool ctsen = (core->client->irq != 0); | ||
1079 | const u8 args[CMD_POWER_UP_A10_NARGS] = { | ||
1080 | 0xF7, /* Reserved, always 0xF7 */ | ||
1081 | 0x3F & puargs->xcload, /* First two bits are reserved to be | ||
1082 | * zeros */ | ||
1083 | ctsen << 7 | intsel << 6 | 0x07, /* Last five bits | ||
1084 | * are reserved to | ||
1085 | * be written as 0x7 */ | ||
1086 | puargs->func << 4 | puargs->freq, | ||
1087 | 0x11, /* Reserved, always 0x11 */ | ||
1088 | }; | ||
1089 | |||
1090 | return si476x_core_send_command(core, CMD_POWER_UP, | ||
1091 | args, ARRAY_SIZE(args), | ||
1092 | resp, ARRAY_SIZE(resp), | ||
1093 | SI476X_TIMEOUT_POWER_UP); | ||
1094 | } | ||
1095 | |||
1096 | static int si476x_core_cmd_power_up_a20(struct si476x_core *core, | ||
1097 | struct si476x_power_up_args *puargs) | ||
1098 | { | ||
1099 | u8 resp[CMD_POWER_UP_A20_NRESP]; | ||
1100 | const bool intsel = (core->pinmux.a1 == SI476X_A1_IRQ); | ||
1101 | const bool ctsen = (core->client->irq != 0); | ||
1102 | const u8 args[CMD_POWER_UP_A20_NARGS] = { | ||
1103 | puargs->ibias6x << 7 | puargs->xstart, | ||
1104 | 0x3F & puargs->xcload, /* First two bits are reserved to be | ||
1105 | * zeros */ | ||
1106 | ctsen << 7 | intsel << 6 | puargs->fastboot << 5 | | ||
1107 | puargs->xbiashc << 3 | puargs->xbias, | ||
1108 | puargs->func << 4 | puargs->freq, | ||
1109 | 0x10 | puargs->xmode, | ||
1110 | }; | ||
1111 | |||
1112 | return si476x_core_send_command(core, CMD_POWER_UP, | ||
1113 | args, ARRAY_SIZE(args), | ||
1114 | resp, ARRAY_SIZE(resp), | ||
1115 | SI476X_TIMEOUT_POWER_UP); | ||
1116 | } | ||
1117 | |||
1118 | static int si476x_core_cmd_power_down_a10(struct si476x_core *core, | ||
1119 | struct si476x_power_down_args *pdargs) | ||
1120 | { | ||
1121 | u8 resp[CMD_POWER_DOWN_A10_NRESP]; | ||
1122 | |||
1123 | return si476x_core_send_command(core, CMD_POWER_DOWN, | ||
1124 | NULL, 0, | ||
1125 | resp, ARRAY_SIZE(resp), | ||
1126 | SI476X_DEFAULT_TIMEOUT); | ||
1127 | } | ||
1128 | |||
1129 | static int si476x_core_cmd_power_down_a20(struct si476x_core *core, | ||
1130 | struct si476x_power_down_args *pdargs) | ||
1131 | { | ||
1132 | u8 resp[CMD_POWER_DOWN_A20_NRESP]; | ||
1133 | const u8 args[CMD_POWER_DOWN_A20_NARGS] = { | ||
1134 | pdargs->xosc, | ||
1135 | }; | ||
1136 | return si476x_core_send_command(core, CMD_POWER_DOWN, | ||
1137 | args, ARRAY_SIZE(args), | ||
1138 | resp, ARRAY_SIZE(resp), | ||
1139 | SI476X_DEFAULT_TIMEOUT); | ||
1140 | } | ||
1141 | |||
1142 | static int si476x_core_cmd_am_tune_freq_a10(struct si476x_core *core, | ||
1143 | struct si476x_tune_freq_args *tuneargs) | ||
1144 | { | ||
1145 | |||
1146 | const int am_freq = tuneargs->freq; | ||
1147 | u8 resp[CMD_AM_TUNE_FREQ_NRESP]; | ||
1148 | const u8 args[CMD_AM_TUNE_FREQ_NARGS] = { | ||
1149 | (tuneargs->hd << 6), | ||
1150 | msb(am_freq), | ||
1151 | lsb(am_freq), | ||
1152 | }; | ||
1153 | |||
1154 | return si476x_cmd_tune_seek_freq(core, CMD_AM_TUNE_FREQ, args, | ||
1155 | sizeof(args), | ||
1156 | resp, sizeof(resp)); | ||
1157 | } | ||
1158 | |||
1159 | static int si476x_core_cmd_am_tune_freq_a20(struct si476x_core *core, | ||
1160 | struct si476x_tune_freq_args *tuneargs) | ||
1161 | { | ||
1162 | const int am_freq = tuneargs->freq; | ||
1163 | u8 resp[CMD_AM_TUNE_FREQ_NRESP]; | ||
1164 | const u8 args[CMD_AM_TUNE_FREQ_NARGS] = { | ||
1165 | (tuneargs->zifsr << 6) | (tuneargs->injside & 0b11), | ||
1166 | msb(am_freq), | ||
1167 | lsb(am_freq), | ||
1168 | }; | ||
1169 | |||
1170 | return si476x_cmd_tune_seek_freq(core, CMD_AM_TUNE_FREQ, | ||
1171 | args, sizeof(args), | ||
1172 | resp, sizeof(resp)); | ||
1173 | } | ||
1174 | |||
1175 | static int si476x_core_cmd_fm_rsq_status_a10(struct si476x_core *core, | ||
1176 | struct si476x_rsq_status_args *rsqargs, | ||
1177 | struct si476x_rsq_status_report *report) | ||
1178 | { | ||
1179 | int err; | ||
1180 | u8 resp[CMD_FM_RSQ_STATUS_A10_NRESP]; | ||
1181 | const u8 args[CMD_FM_RSQ_STATUS_A10_NARGS] = { | ||
1182 | rsqargs->rsqack << 3 | rsqargs->attune << 2 | | ||
1183 | rsqargs->cancel << 1 | rsqargs->stcack, | ||
1184 | }; | ||
1185 | |||
1186 | err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, | ||
1187 | args, ARRAY_SIZE(args), | ||
1188 | resp, ARRAY_SIZE(resp), | ||
1189 | SI476X_DEFAULT_TIMEOUT); | ||
1190 | /* | ||
1191 | * Besides getting received signal quality information this | ||
1192 | * command can be used to just acknowledge different interrupt | ||
1193 | * flags in those cases it is useless to copy and parse | ||
1194 | * received data so user can pass NULL, and thus avoid | ||
1195 | * unnecessary copying. | ||
1196 | */ | ||
1197 | if (err < 0 || report == NULL) | ||
1198 | return err; | ||
1199 | |||
1200 | report->multhint = 0b10000000 & resp[1]; | ||
1201 | report->multlint = 0b01000000 & resp[1]; | ||
1202 | report->snrhint = 0b00001000 & resp[1]; | ||
1203 | report->snrlint = 0b00000100 & resp[1]; | ||
1204 | report->rssihint = 0b00000010 & resp[1]; | ||
1205 | report->rssilint = 0b00000001 & resp[1]; | ||
1206 | |||
1207 | report->bltf = 0b10000000 & resp[2]; | ||
1208 | report->snr_ready = 0b00100000 & resp[2]; | ||
1209 | report->rssiready = 0b00001000 & resp[2]; | ||
1210 | report->afcrl = 0b00000010 & resp[2]; | ||
1211 | report->valid = 0b00000001 & resp[2]; | ||
1212 | |||
1213 | report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); | ||
1214 | report->freqoff = resp[5]; | ||
1215 | report->rssi = resp[6]; | ||
1216 | report->snr = resp[7]; | ||
1217 | report->lassi = resp[9]; | ||
1218 | report->hassi = resp[10]; | ||
1219 | report->mult = resp[11]; | ||
1220 | report->dev = resp[12]; | ||
1221 | report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); | ||
1222 | report->assi = resp[15]; | ||
1223 | report->usn = resp[16]; | ||
1224 | |||
1225 | return err; | ||
1226 | } | ||
1227 | |||
1228 | static int si476x_core_cmd_fm_rsq_status_a20(struct si476x_core *core, | ||
1229 | struct si476x_rsq_status_args *rsqargs, | ||
1230 | struct si476x_rsq_status_report *report) | ||
1231 | { | ||
1232 | int err; | ||
1233 | u8 resp[CMD_FM_RSQ_STATUS_A10_NRESP]; | ||
1234 | const u8 args[CMD_FM_RSQ_STATUS_A30_NARGS] = { | ||
1235 | rsqargs->primary << 4 | rsqargs->rsqack << 3 | | ||
1236 | rsqargs->attune << 2 | rsqargs->cancel << 1 | | ||
1237 | rsqargs->stcack, | ||
1238 | }; | ||
1239 | |||
1240 | err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, | ||
1241 | args, ARRAY_SIZE(args), | ||
1242 | resp, ARRAY_SIZE(resp), | ||
1243 | SI476X_DEFAULT_TIMEOUT); | ||
1244 | /* | ||
1245 | * Besides getting received signal quality information this | ||
1246 | * command can be used to just acknowledge different interrupt | ||
1247 | * flags in those cases it is useless to copy and parse | ||
1248 | * received data so user can pass NULL, and thus avoid | ||
1249 | * unnecessary copying. | ||
1250 | */ | ||
1251 | if (err < 0 || report == NULL) | ||
1252 | return err; | ||
1253 | |||
1254 | report->multhint = 0b10000000 & resp[1]; | ||
1255 | report->multlint = 0b01000000 & resp[1]; | ||
1256 | report->snrhint = 0b00001000 & resp[1]; | ||
1257 | report->snrlint = 0b00000100 & resp[1]; | ||
1258 | report->rssihint = 0b00000010 & resp[1]; | ||
1259 | report->rssilint = 0b00000001 & resp[1]; | ||
1260 | |||
1261 | report->bltf = 0b10000000 & resp[2]; | ||
1262 | report->snr_ready = 0b00100000 & resp[2]; | ||
1263 | report->rssiready = 0b00001000 & resp[2]; | ||
1264 | report->afcrl = 0b00000010 & resp[2]; | ||
1265 | report->valid = 0b00000001 & resp[2]; | ||
1266 | |||
1267 | report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); | ||
1268 | report->freqoff = resp[5]; | ||
1269 | report->rssi = resp[6]; | ||
1270 | report->snr = resp[7]; | ||
1271 | report->lassi = resp[9]; | ||
1272 | report->hassi = resp[10]; | ||
1273 | report->mult = resp[11]; | ||
1274 | report->dev = resp[12]; | ||
1275 | report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); | ||
1276 | report->assi = resp[15]; | ||
1277 | report->usn = resp[16]; | ||
1278 | |||
1279 | return err; | ||
1280 | } | ||
1281 | |||
1282 | |||
1283 | static int si476x_core_cmd_fm_rsq_status_a30(struct si476x_core *core, | ||
1284 | struct si476x_rsq_status_args *rsqargs, | ||
1285 | struct si476x_rsq_status_report *report) | ||
1286 | { | ||
1287 | int err; | ||
1288 | u8 resp[CMD_FM_RSQ_STATUS_A30_NRESP]; | ||
1289 | const u8 args[CMD_FM_RSQ_STATUS_A30_NARGS] = { | ||
1290 | rsqargs->primary << 4 | rsqargs->rsqack << 3 | | ||
1291 | rsqargs->attune << 2 | rsqargs->cancel << 1 | | ||
1292 | rsqargs->stcack, | ||
1293 | }; | ||
1294 | |||
1295 | err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, | ||
1296 | args, ARRAY_SIZE(args), | ||
1297 | resp, ARRAY_SIZE(resp), | ||
1298 | SI476X_DEFAULT_TIMEOUT); | ||
1299 | /* | ||
1300 | * Besides getting received signal quality information this | ||
1301 | * command can be used to just acknowledge different interrupt | ||
1302 | * flags in those cases it is useless to copy and parse | ||
1303 | * received data so user can pass NULL, and thus avoid | ||
1304 | * unnecessary copying. | ||
1305 | */ | ||
1306 | if (err < 0 || report == NULL) | ||
1307 | return err; | ||
1308 | |||
1309 | report->multhint = 0b10000000 & resp[1]; | ||
1310 | report->multlint = 0b01000000 & resp[1]; | ||
1311 | report->snrhint = 0b00001000 & resp[1]; | ||
1312 | report->snrlint = 0b00000100 & resp[1]; | ||
1313 | report->rssihint = 0b00000010 & resp[1]; | ||
1314 | report->rssilint = 0b00000001 & resp[1]; | ||
1315 | |||
1316 | report->bltf = 0b10000000 & resp[2]; | ||
1317 | report->snr_ready = 0b00100000 & resp[2]; | ||
1318 | report->rssiready = 0b00001000 & resp[2]; | ||
1319 | report->injside = 0b00000100 & resp[2]; | ||
1320 | report->afcrl = 0b00000010 & resp[2]; | ||
1321 | report->valid = 0b00000001 & resp[2]; | ||
1322 | |||
1323 | report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); | ||
1324 | report->freqoff = resp[5]; | ||
1325 | report->rssi = resp[6]; | ||
1326 | report->snr = resp[7]; | ||
1327 | report->issi = resp[8]; | ||
1328 | report->lassi = resp[9]; | ||
1329 | report->hassi = resp[10]; | ||
1330 | report->mult = resp[11]; | ||
1331 | report->dev = resp[12]; | ||
1332 | report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); | ||
1333 | report->assi = resp[15]; | ||
1334 | report->usn = resp[16]; | ||
1335 | |||
1336 | report->pilotdev = resp[17]; | ||
1337 | report->rdsdev = resp[18]; | ||
1338 | report->assidev = resp[19]; | ||
1339 | report->strongdev = resp[20]; | ||
1340 | report->rdspi = be16_to_cpup((__be16 *)(resp + 21)); | ||
1341 | |||
1342 | return err; | ||
1343 | } | ||
1344 | |||
1345 | static int si476x_core_cmd_fm_tune_freq_a10(struct si476x_core *core, | ||
1346 | struct si476x_tune_freq_args *tuneargs) | ||
1347 | { | ||
1348 | u8 resp[CMD_FM_TUNE_FREQ_NRESP]; | ||
1349 | const u8 args[CMD_FM_TUNE_FREQ_A10_NARGS] = { | ||
1350 | (tuneargs->hd << 6) | (tuneargs->tunemode << 4) | ||
1351 | | (tuneargs->smoothmetrics << 2), | ||
1352 | msb(tuneargs->freq), | ||
1353 | lsb(tuneargs->freq), | ||
1354 | msb(tuneargs->antcap), | ||
1355 | lsb(tuneargs->antcap) | ||
1356 | }; | ||
1357 | |||
1358 | return si476x_cmd_tune_seek_freq(core, CMD_FM_TUNE_FREQ, | ||
1359 | args, sizeof(args), | ||
1360 | resp, sizeof(resp)); | ||
1361 | } | ||
1362 | |||
1363 | static int si476x_core_cmd_fm_tune_freq_a20(struct si476x_core *core, | ||
1364 | struct si476x_tune_freq_args *tuneargs) | ||
1365 | { | ||
1366 | u8 resp[CMD_FM_TUNE_FREQ_NRESP]; | ||
1367 | const u8 args[CMD_FM_TUNE_FREQ_A20_NARGS] = { | ||
1368 | (tuneargs->hd << 6) | (tuneargs->tunemode << 4) | ||
1369 | | (tuneargs->smoothmetrics << 2) | (tuneargs->injside), | ||
1370 | msb(tuneargs->freq), | ||
1371 | lsb(tuneargs->freq), | ||
1372 | }; | ||
1373 | |||
1374 | return si476x_cmd_tune_seek_freq(core, CMD_FM_TUNE_FREQ, | ||
1375 | args, sizeof(args), | ||
1376 | resp, sizeof(resp)); | ||
1377 | } | ||
1378 | |||
1379 | static int si476x_core_cmd_agc_status_a20(struct si476x_core *core, | ||
1380 | struct si476x_agc_status_report *report) | ||
1381 | { | ||
1382 | int err; | ||
1383 | u8 resp[CMD_AGC_STATUS_NRESP_A20]; | ||
1384 | |||
1385 | if (!report) | ||
1386 | return -EINVAL; | ||
1387 | |||
1388 | err = si476x_core_send_command(core, CMD_AGC_STATUS, | ||
1389 | NULL, 0, | ||
1390 | resp, ARRAY_SIZE(resp), | ||
1391 | SI476X_DEFAULT_TIMEOUT); | ||
1392 | if (err < 0) | ||
1393 | return err; | ||
1394 | |||
1395 | report->mxhi = resp[1] & SI476X_AGC_MXHI; | ||
1396 | report->mxlo = resp[1] & SI476X_AGC_MXLO; | ||
1397 | report->lnahi = resp[1] & SI476X_AGC_LNAHI; | ||
1398 | report->lnalo = resp[1] & SI476X_AGC_LNALO; | ||
1399 | report->fmagc1 = resp[2]; | ||
1400 | report->fmagc2 = resp[3]; | ||
1401 | report->pgagain = resp[4]; | ||
1402 | report->fmwblang = resp[5]; | ||
1403 | |||
1404 | return err; | ||
1405 | } | ||
1406 | |||
1407 | static int si476x_core_cmd_agc_status_a10(struct si476x_core *core, | ||
1408 | struct si476x_agc_status_report *report) | ||
1409 | { | ||
1410 | int err; | ||
1411 | u8 resp[CMD_AGC_STATUS_NRESP_A10]; | ||
1412 | |||
1413 | if (!report) | ||
1414 | return -EINVAL; | ||
1415 | |||
1416 | err = si476x_core_send_command(core, CMD_AGC_STATUS, | ||
1417 | NULL, 0, | ||
1418 | resp, ARRAY_SIZE(resp), | ||
1419 | SI476X_DEFAULT_TIMEOUT); | ||
1420 | if (err < 0) | ||
1421 | return err; | ||
1422 | |||
1423 | report->mxhi = resp[1] & SI476X_AGC_MXHI; | ||
1424 | report->mxlo = resp[1] & SI476X_AGC_MXLO; | ||
1425 | report->lnahi = resp[1] & SI476X_AGC_LNAHI; | ||
1426 | report->lnalo = resp[1] & SI476X_AGC_LNALO; | ||
1427 | |||
1428 | return err; | ||
1429 | } | ||
1430 | |||
1431 | typedef int (*tune_freq_func_t) (struct si476x_core *core, | ||
1432 | struct si476x_tune_freq_args *tuneargs); | ||
1433 | |||
1434 | static struct { | ||
1435 | int (*power_up) (struct si476x_core *, | ||
1436 | struct si476x_power_up_args *); | ||
1437 | int (*power_down) (struct si476x_core *, | ||
1438 | struct si476x_power_down_args *); | ||
1439 | |||
1440 | tune_freq_func_t fm_tune_freq; | ||
1441 | tune_freq_func_t am_tune_freq; | ||
1442 | |||
1443 | int (*fm_rsq_status)(struct si476x_core *, | ||
1444 | struct si476x_rsq_status_args *, | ||
1445 | struct si476x_rsq_status_report *); | ||
1446 | |||
1447 | int (*agc_status)(struct si476x_core *, | ||
1448 | struct si476x_agc_status_report *); | ||
1449 | int (*intb_pin_cfg)(struct si476x_core *core, | ||
1450 | enum si476x_intb_config intb, | ||
1451 | enum si476x_a1_config a1); | ||
1452 | } si476x_cmds_vtable[] = { | ||
1453 | [SI476X_REVISION_A10] = { | ||
1454 | .power_up = si476x_core_cmd_power_up_a10, | ||
1455 | .power_down = si476x_core_cmd_power_down_a10, | ||
1456 | .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a10, | ||
1457 | .am_tune_freq = si476x_core_cmd_am_tune_freq_a10, | ||
1458 | .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a10, | ||
1459 | .agc_status = si476x_core_cmd_agc_status_a10, | ||
1460 | .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a10, | ||
1461 | }, | ||
1462 | [SI476X_REVISION_A20] = { | ||
1463 | .power_up = si476x_core_cmd_power_up_a20, | ||
1464 | .power_down = si476x_core_cmd_power_down_a20, | ||
1465 | .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a20, | ||
1466 | .am_tune_freq = si476x_core_cmd_am_tune_freq_a20, | ||
1467 | .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a20, | ||
1468 | .agc_status = si476x_core_cmd_agc_status_a20, | ||
1469 | .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a20, | ||
1470 | }, | ||
1471 | [SI476X_REVISION_A30] = { | ||
1472 | .power_up = si476x_core_cmd_power_up_a20, | ||
1473 | .power_down = si476x_core_cmd_power_down_a20, | ||
1474 | .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a20, | ||
1475 | .am_tune_freq = si476x_core_cmd_am_tune_freq_a20, | ||
1476 | .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a30, | ||
1477 | .agc_status = si476x_core_cmd_agc_status_a20, | ||
1478 | .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a20, | ||
1479 | }, | ||
1480 | }; | ||
1481 | |||
1482 | int si476x_core_cmd_power_up(struct si476x_core *core, | ||
1483 | struct si476x_power_up_args *args) | ||
1484 | { | ||
1485 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
1486 | core->revision == -1); | ||
1487 | return si476x_cmds_vtable[core->revision].power_up(core, args); | ||
1488 | } | ||
1489 | EXPORT_SYMBOL_GPL(si476x_core_cmd_power_up); | ||
1490 | |||
1491 | int si476x_core_cmd_power_down(struct si476x_core *core, | ||
1492 | struct si476x_power_down_args *args) | ||
1493 | { | ||
1494 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
1495 | core->revision == -1); | ||
1496 | return si476x_cmds_vtable[core->revision].power_down(core, args); | ||
1497 | } | ||
1498 | EXPORT_SYMBOL_GPL(si476x_core_cmd_power_down); | ||
1499 | |||
1500 | int si476x_core_cmd_fm_tune_freq(struct si476x_core *core, | ||
1501 | struct si476x_tune_freq_args *args) | ||
1502 | { | ||
1503 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
1504 | core->revision == -1); | ||
1505 | return si476x_cmds_vtable[core->revision].fm_tune_freq(core, args); | ||
1506 | } | ||
1507 | EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_tune_freq); | ||
1508 | |||
1509 | int si476x_core_cmd_am_tune_freq(struct si476x_core *core, | ||
1510 | struct si476x_tune_freq_args *args) | ||
1511 | { | ||
1512 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
1513 | core->revision == -1); | ||
1514 | return si476x_cmds_vtable[core->revision].am_tune_freq(core, args); | ||
1515 | } | ||
1516 | EXPORT_SYMBOL_GPL(si476x_core_cmd_am_tune_freq); | ||
1517 | |||
1518 | int si476x_core_cmd_fm_rsq_status(struct si476x_core *core, | ||
1519 | struct si476x_rsq_status_args *args, | ||
1520 | struct si476x_rsq_status_report *report) | ||
1521 | |||
1522 | { | ||
1523 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
1524 | core->revision == -1); | ||
1525 | return si476x_cmds_vtable[core->revision].fm_rsq_status(core, args, | ||
1526 | report); | ||
1527 | } | ||
1528 | EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rsq_status); | ||
1529 | |||
1530 | int si476x_core_cmd_agc_status(struct si476x_core *core, | ||
1531 | struct si476x_agc_status_report *report) | ||
1532 | |||
1533 | { | ||
1534 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
1535 | core->revision == -1); | ||
1536 | return si476x_cmds_vtable[core->revision].agc_status(core, report); | ||
1537 | } | ||
1538 | EXPORT_SYMBOL_GPL(si476x_core_cmd_agc_status); | ||
1539 | |||
1540 | int si476x_core_cmd_intb_pin_cfg(struct si476x_core *core, | ||
1541 | enum si476x_intb_config intb, | ||
1542 | enum si476x_a1_config a1) | ||
1543 | { | ||
1544 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
1545 | core->revision == -1); | ||
1546 | |||
1547 | return si476x_cmds_vtable[core->revision].intb_pin_cfg(core, intb, a1); | ||
1548 | } | ||
1549 | EXPORT_SYMBOL_GPL(si476x_core_cmd_intb_pin_cfg); | ||
1550 | |||
1551 | MODULE_LICENSE("GPL"); | ||
1552 | MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>"); | ||
1553 | MODULE_DESCRIPTION("API for command exchange for si476x"); | ||
diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c new file mode 100644 index 000000000000..f5bc8e4bd4bf --- /dev/null +++ b/drivers/mfd/si476x-i2c.c | |||
@@ -0,0 +1,886 @@ | |||
1 | /* | ||
2 | * drivers/mfd/si476x-i2c.c -- Core device driver for si476x MFD | ||
3 | * device | ||
4 | * | ||
5 | * Copyright (C) 2012 Innovative Converged Devices(ICD) | ||
6 | * Copyright (C) 2013 Andrey Smirnov | ||
7 | * | ||
8 | * Author: Andrey Smirnov <andrew.smirnov@gmail.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; version 2 of the License. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | */ | ||
20 | #include <linux/module.h> | ||
21 | |||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/gpio.h> | ||
26 | #include <linux/regulator/consumer.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include <linux/err.h> | ||
29 | |||
30 | #include <linux/mfd/si476x-core.h> | ||
31 | |||
32 | #define SI476X_MAX_IO_ERRORS 10 | ||
33 | #define SI476X_DRIVER_RDS_FIFO_DEPTH 128 | ||
34 | |||
35 | /** | ||
36 | * si476x_core_config_pinmux() - pin function configuration function | ||
37 | * | ||
38 | * @core: Core device structure | ||
39 | * | ||
40 | * Configure the functions of the pins of the radio chip. | ||
41 | * | ||
42 | * The function returns zero in case of succes or negative error code | ||
43 | * otherwise. | ||
44 | */ | ||
45 | static int si476x_core_config_pinmux(struct si476x_core *core) | ||
46 | { | ||
47 | int err; | ||
48 | dev_dbg(&core->client->dev, "Configuring pinmux\n"); | ||
49 | err = si476x_core_cmd_dig_audio_pin_cfg(core, | ||
50 | core->pinmux.dclk, | ||
51 | core->pinmux.dfs, | ||
52 | core->pinmux.dout, | ||
53 | core->pinmux.xout); | ||
54 | if (err < 0) { | ||
55 | dev_err(&core->client->dev, | ||
56 | "Failed to configure digital audio pins(err = %d)\n", | ||
57 | err); | ||
58 | return err; | ||
59 | } | ||
60 | |||
61 | err = si476x_core_cmd_zif_pin_cfg(core, | ||
62 | core->pinmux.iqclk, | ||
63 | core->pinmux.iqfs, | ||
64 | core->pinmux.iout, | ||
65 | core->pinmux.qout); | ||
66 | if (err < 0) { | ||
67 | dev_err(&core->client->dev, | ||
68 | "Failed to configure ZIF pins(err = %d)\n", | ||
69 | err); | ||
70 | return err; | ||
71 | } | ||
72 | |||
73 | err = si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(core, | ||
74 | core->pinmux.icin, | ||
75 | core->pinmux.icip, | ||
76 | core->pinmux.icon, | ||
77 | core->pinmux.icop); | ||
78 | if (err < 0) { | ||
79 | dev_err(&core->client->dev, | ||
80 | "Failed to configure IC-Link/GPO pins(err = %d)\n", | ||
81 | err); | ||
82 | return err; | ||
83 | } | ||
84 | |||
85 | err = si476x_core_cmd_ana_audio_pin_cfg(core, | ||
86 | core->pinmux.lrout); | ||
87 | if (err < 0) { | ||
88 | dev_err(&core->client->dev, | ||
89 | "Failed to configure analog audio pins(err = %d)\n", | ||
90 | err); | ||
91 | return err; | ||
92 | } | ||
93 | |||
94 | err = si476x_core_cmd_intb_pin_cfg(core, | ||
95 | core->pinmux.intb, | ||
96 | core->pinmux.a1); | ||
97 | if (err < 0) { | ||
98 | dev_err(&core->client->dev, | ||
99 | "Failed to configure interrupt pins(err = %d)\n", | ||
100 | err); | ||
101 | return err; | ||
102 | } | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static inline void si476x_core_schedule_polling_work(struct si476x_core *core) | ||
108 | { | ||
109 | schedule_delayed_work(&core->status_monitor, | ||
110 | usecs_to_jiffies(SI476X_STATUS_POLL_US)); | ||
111 | } | ||
112 | |||
113 | /** | ||
114 | * si476x_core_start() - early chip startup function | ||
115 | * @core: Core device structure | ||
116 | * @soft: When set, this flag forces "soft" startup, where "soft" | ||
117 | * power down is the one done by sending appropriate command instead | ||
118 | * of using reset pin of the tuner | ||
119 | * | ||
120 | * Perform required startup sequence to correctly power | ||
121 | * up the chip and perform initial configuration. It does the | ||
122 | * following sequence of actions: | ||
123 | * 1. Claims and enables the power supplies VD and VIO1 required | ||
124 | * for I2C interface of the chip operation. | ||
125 | * 2. Waits for 100us, pulls the reset line up, enables irq, | ||
126 | * waits for another 100us as it is specified by the | ||
127 | * datasheet. | ||
128 | * 3. Sends 'POWER_UP' command to the device with all provided | ||
129 | * information about power-up parameters. | ||
130 | * 4. Configures, pin multiplexor, disables digital audio and | ||
131 | * configures interrupt sources. | ||
132 | * | ||
133 | * The function returns zero in case of succes or negative error code | ||
134 | * otherwise. | ||
135 | */ | ||
136 | int si476x_core_start(struct si476x_core *core, bool soft) | ||
137 | { | ||
138 | struct i2c_client *client = core->client; | ||
139 | int err; | ||
140 | |||
141 | if (!soft) { | ||
142 | if (gpio_is_valid(core->gpio_reset)) | ||
143 | gpio_set_value_cansleep(core->gpio_reset, 1); | ||
144 | |||
145 | if (client->irq) | ||
146 | enable_irq(client->irq); | ||
147 | |||
148 | udelay(100); | ||
149 | |||
150 | if (!client->irq) { | ||
151 | atomic_set(&core->is_alive, 1); | ||
152 | si476x_core_schedule_polling_work(core); | ||
153 | } | ||
154 | } else { | ||
155 | if (client->irq) | ||
156 | enable_irq(client->irq); | ||
157 | else { | ||
158 | atomic_set(&core->is_alive, 1); | ||
159 | si476x_core_schedule_polling_work(core); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | err = si476x_core_cmd_power_up(core, | ||
164 | &core->power_up_parameters); | ||
165 | |||
166 | if (err < 0) { | ||
167 | dev_err(&core->client->dev, | ||
168 | "Power up failure(err = %d)\n", | ||
169 | err); | ||
170 | goto disable_irq; | ||
171 | } | ||
172 | |||
173 | if (client->irq) | ||
174 | atomic_set(&core->is_alive, 1); | ||
175 | |||
176 | err = si476x_core_config_pinmux(core); | ||
177 | if (err < 0) { | ||
178 | dev_err(&core->client->dev, | ||
179 | "Failed to configure pinmux(err = %d)\n", | ||
180 | err); | ||
181 | goto disable_irq; | ||
182 | } | ||
183 | |||
184 | if (client->irq) { | ||
185 | err = regmap_write(core->regmap, | ||
186 | SI476X_PROP_INT_CTL_ENABLE, | ||
187 | SI476X_RDSIEN | | ||
188 | SI476X_STCIEN | | ||
189 | SI476X_CTSIEN); | ||
190 | if (err < 0) { | ||
191 | dev_err(&core->client->dev, | ||
192 | "Failed to configure interrupt sources" | ||
193 | "(err = %d)\n", err); | ||
194 | goto disable_irq; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | return 0; | ||
199 | |||
200 | disable_irq: | ||
201 | if (err == -ENODEV) | ||
202 | atomic_set(&core->is_alive, 0); | ||
203 | |||
204 | if (client->irq) | ||
205 | disable_irq(client->irq); | ||
206 | else | ||
207 | cancel_delayed_work_sync(&core->status_monitor); | ||
208 | |||
209 | if (gpio_is_valid(core->gpio_reset)) | ||
210 | gpio_set_value_cansleep(core->gpio_reset, 0); | ||
211 | |||
212 | return err; | ||
213 | } | ||
214 | EXPORT_SYMBOL_GPL(si476x_core_start); | ||
215 | |||
216 | /** | ||
217 | * si476x_core_stop() - chip power-down function | ||
218 | * @core: Core device structure | ||
219 | * @soft: When set, function sends a POWER_DOWN command instead of | ||
220 | * bringing reset line low | ||
221 | * | ||
222 | * Power down the chip by performing following actions: | ||
223 | * 1. Disable IRQ or stop the polling worker | ||
224 | * 2. Send the POWER_DOWN command if the power down is soft or bring | ||
225 | * reset line low if not. | ||
226 | * | ||
227 | * The function returns zero in case of succes or negative error code | ||
228 | * otherwise. | ||
229 | */ | ||
230 | int si476x_core_stop(struct si476x_core *core, bool soft) | ||
231 | { | ||
232 | int err = 0; | ||
233 | atomic_set(&core->is_alive, 0); | ||
234 | |||
235 | if (soft) { | ||
236 | /* TODO: This probably shoud be a configurable option, | ||
237 | * so it is possible to have the chips keep their | ||
238 | * oscillators running | ||
239 | */ | ||
240 | struct si476x_power_down_args args = { | ||
241 | .xosc = false, | ||
242 | }; | ||
243 | err = si476x_core_cmd_power_down(core, &args); | ||
244 | } | ||
245 | |||
246 | /* We couldn't disable those before | ||
247 | * 'si476x_core_cmd_power_down' since we expect to get CTS | ||
248 | * interrupt */ | ||
249 | if (core->client->irq) | ||
250 | disable_irq(core->client->irq); | ||
251 | else | ||
252 | cancel_delayed_work_sync(&core->status_monitor); | ||
253 | |||
254 | if (!soft) { | ||
255 | if (gpio_is_valid(core->gpio_reset)) | ||
256 | gpio_set_value_cansleep(core->gpio_reset, 0); | ||
257 | } | ||
258 | return err; | ||
259 | } | ||
260 | EXPORT_SYMBOL_GPL(si476x_core_stop); | ||
261 | |||
262 | /** | ||
263 | * si476x_core_set_power_state() - set the level at which the power is | ||
264 | * supplied for the chip. | ||
265 | * @core: Core device structure | ||
266 | * @next_state: enum si476x_power_state describing power state to | ||
267 | * switch to. | ||
268 | * | ||
269 | * Switch on all the required power supplies | ||
270 | * | ||
271 | * This function returns 0 in case of suvccess and negative error code | ||
272 | * otherwise. | ||
273 | */ | ||
274 | int si476x_core_set_power_state(struct si476x_core *core, | ||
275 | enum si476x_power_state next_state) | ||
276 | { | ||
277 | /* | ||
278 | It is not clear form the datasheet if it is possible to | ||
279 | work with device if not all power domains are operational. | ||
280 | So for now the power-up policy is "power-up all the things!" | ||
281 | */ | ||
282 | int err = 0; | ||
283 | |||
284 | if (core->power_state == SI476X_POWER_INCONSISTENT) { | ||
285 | dev_err(&core->client->dev, | ||
286 | "The device in inconsistent power state\n"); | ||
287 | return -EINVAL; | ||
288 | } | ||
289 | |||
290 | if (next_state != core->power_state) { | ||
291 | switch (next_state) { | ||
292 | case SI476X_POWER_UP_FULL: | ||
293 | err = regulator_bulk_enable(ARRAY_SIZE(core->supplies), | ||
294 | core->supplies); | ||
295 | if (err < 0) { | ||
296 | core->power_state = SI476X_POWER_INCONSISTENT; | ||
297 | break; | ||
298 | } | ||
299 | /* | ||
300 | * Startup timing diagram recommends to have a | ||
301 | * 100 us delay between enabling of the power | ||
302 | * supplies and turning the tuner on. | ||
303 | */ | ||
304 | udelay(100); | ||
305 | |||
306 | err = si476x_core_start(core, false); | ||
307 | if (err < 0) | ||
308 | goto disable_regulators; | ||
309 | |||
310 | core->power_state = next_state; | ||
311 | break; | ||
312 | |||
313 | case SI476X_POWER_DOWN: | ||
314 | core->power_state = next_state; | ||
315 | err = si476x_core_stop(core, false); | ||
316 | if (err < 0) | ||
317 | core->power_state = SI476X_POWER_INCONSISTENT; | ||
318 | disable_regulators: | ||
319 | err = regulator_bulk_disable(ARRAY_SIZE(core->supplies), | ||
320 | core->supplies); | ||
321 | if (err < 0) | ||
322 | core->power_state = SI476X_POWER_INCONSISTENT; | ||
323 | break; | ||
324 | default: | ||
325 | BUG(); | ||
326 | } | ||
327 | } | ||
328 | |||
329 | return err; | ||
330 | } | ||
331 | EXPORT_SYMBOL_GPL(si476x_core_set_power_state); | ||
332 | |||
333 | /** | ||
334 | * si476x_core_report_drainer_stop() - mark the completion of the RDS | ||
335 | * buffer drain porcess by the worker. | ||
336 | * | ||
337 | * @core: Core device structure | ||
338 | */ | ||
339 | static inline void si476x_core_report_drainer_stop(struct si476x_core *core) | ||
340 | { | ||
341 | mutex_lock(&core->rds_drainer_status_lock); | ||
342 | core->rds_drainer_is_working = false; | ||
343 | mutex_unlock(&core->rds_drainer_status_lock); | ||
344 | } | ||
345 | |||
346 | /** | ||
347 | * si476x_core_start_rds_drainer_once() - start RDS drainer worker if | ||
348 | * ther is none working, do nothing otherwise | ||
349 | * | ||
350 | * @core: Datastructure corresponding to the chip. | ||
351 | */ | ||
352 | static inline void si476x_core_start_rds_drainer_once(struct si476x_core *core) | ||
353 | { | ||
354 | mutex_lock(&core->rds_drainer_status_lock); | ||
355 | if (!core->rds_drainer_is_working) { | ||
356 | core->rds_drainer_is_working = true; | ||
357 | schedule_work(&core->rds_fifo_drainer); | ||
358 | } | ||
359 | mutex_unlock(&core->rds_drainer_status_lock); | ||
360 | } | ||
361 | /** | ||
362 | * si476x_drain_rds_fifo() - RDS buffer drainer. | ||
363 | * @work: struct work_struct being ppassed to the function by the | ||
364 | * kernel. | ||
365 | * | ||
366 | * Drain the contents of the RDS FIFO of | ||
367 | */ | ||
368 | static void si476x_core_drain_rds_fifo(struct work_struct *work) | ||
369 | { | ||
370 | int err; | ||
371 | |||
372 | struct si476x_core *core = container_of(work, struct si476x_core, | ||
373 | rds_fifo_drainer); | ||
374 | |||
375 | struct si476x_rds_status_report report; | ||
376 | |||
377 | si476x_core_lock(core); | ||
378 | err = si476x_core_cmd_fm_rds_status(core, true, false, false, &report); | ||
379 | if (!err) { | ||
380 | int i = report.rdsfifoused; | ||
381 | dev_dbg(&core->client->dev, | ||
382 | "%d elements in RDS FIFO. Draining.\n", i); | ||
383 | for (; i > 0; --i) { | ||
384 | err = si476x_core_cmd_fm_rds_status(core, false, false, | ||
385 | (i == 1), &report); | ||
386 | if (err < 0) | ||
387 | goto unlock; | ||
388 | |||
389 | kfifo_in(&core->rds_fifo, report.rds, | ||
390 | sizeof(report.rds)); | ||
391 | dev_dbg(&core->client->dev, "RDS data:\n %*ph\n", | ||
392 | (int)sizeof(report.rds), report.rds); | ||
393 | } | ||
394 | dev_dbg(&core->client->dev, "Drrrrained!\n"); | ||
395 | wake_up_interruptible(&core->rds_read_queue); | ||
396 | } | ||
397 | |||
398 | unlock: | ||
399 | si476x_core_unlock(core); | ||
400 | si476x_core_report_drainer_stop(core); | ||
401 | } | ||
402 | |||
403 | /** | ||
404 | * si476x_core_pronounce_dead() | ||
405 | * | ||
406 | * @core: Core device structure | ||
407 | * | ||
408 | * Mark the device as being dead and wake up all potentially waiting | ||
409 | * threads of execution. | ||
410 | * | ||
411 | */ | ||
412 | static void si476x_core_pronounce_dead(struct si476x_core *core) | ||
413 | { | ||
414 | dev_info(&core->client->dev, "Core device is dead.\n"); | ||
415 | |||
416 | atomic_set(&core->is_alive, 0); | ||
417 | |||
418 | /* Wake up al possible waiting processes */ | ||
419 | wake_up_interruptible(&core->rds_read_queue); | ||
420 | |||
421 | atomic_set(&core->cts, 1); | ||
422 | wake_up(&core->command); | ||
423 | |||
424 | atomic_set(&core->stc, 1); | ||
425 | wake_up(&core->tuning); | ||
426 | } | ||
427 | |||
428 | /** | ||
429 | * si476x_core_i2c_xfer() | ||
430 | * | ||
431 | * @core: Core device structure | ||
432 | * @type: Transfer type | ||
433 | * @buf: Transfer buffer for/with data | ||
434 | * @count: Transfer buffer size | ||
435 | * | ||
436 | * Perfrom and I2C transfer(either read or write) and keep a counter | ||
437 | * of I/O errors. If the error counter rises above the threshold | ||
438 | * pronounce device dead. | ||
439 | * | ||
440 | * The function returns zero on succes or negative error code on | ||
441 | * failure. | ||
442 | */ | ||
443 | int si476x_core_i2c_xfer(struct si476x_core *core, | ||
444 | enum si476x_i2c_type type, | ||
445 | char *buf, int count) | ||
446 | { | ||
447 | static int io_errors_count; | ||
448 | int err; | ||
449 | if (type == SI476X_I2C_SEND) | ||
450 | err = i2c_master_send(core->client, buf, count); | ||
451 | else | ||
452 | err = i2c_master_recv(core->client, buf, count); | ||
453 | |||
454 | if (err < 0) { | ||
455 | if (io_errors_count++ > SI476X_MAX_IO_ERRORS) | ||
456 | si476x_core_pronounce_dead(core); | ||
457 | } else { | ||
458 | io_errors_count = 0; | ||
459 | } | ||
460 | |||
461 | return err; | ||
462 | } | ||
463 | EXPORT_SYMBOL_GPL(si476x_core_i2c_xfer); | ||
464 | |||
465 | /** | ||
466 | * si476x_get_status() | ||
467 | * @core: Core device structure | ||
468 | * | ||
469 | * Get the status byte of the core device by berforming one byte I2C | ||
470 | * read. | ||
471 | * | ||
472 | * The function returns a status value or a negative error code on | ||
473 | * error. | ||
474 | */ | ||
475 | static int si476x_core_get_status(struct si476x_core *core) | ||
476 | { | ||
477 | u8 response; | ||
478 | int err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, | ||
479 | &response, sizeof(response)); | ||
480 | |||
481 | return (err < 0) ? err : response; | ||
482 | } | ||
483 | |||
484 | /** | ||
485 | * si476x_get_and_signal_status() - IRQ dispatcher | ||
486 | * @core: Core device structure | ||
487 | * | ||
488 | * Dispatch the arrived interrupt request based on the value of the | ||
489 | * status byte reported by the tuner. | ||
490 | * | ||
491 | */ | ||
492 | static void si476x_core_get_and_signal_status(struct si476x_core *core) | ||
493 | { | ||
494 | int status = si476x_core_get_status(core); | ||
495 | if (status < 0) { | ||
496 | dev_err(&core->client->dev, "Failed to get status\n"); | ||
497 | return; | ||
498 | } | ||
499 | |||
500 | if (status & SI476X_CTS) { | ||
501 | /* Unfortunately completions could not be used for | ||
502 | * signalling CTS since this flag cannot be cleared | ||
503 | * in status byte, and therefore once it becomes true | ||
504 | * multiple calls to 'complete' would cause the | ||
505 | * commands following the current one to be completed | ||
506 | * before they actually are */ | ||
507 | dev_dbg(&core->client->dev, "[interrupt] CTSINT\n"); | ||
508 | atomic_set(&core->cts, 1); | ||
509 | wake_up(&core->command); | ||
510 | } | ||
511 | |||
512 | if (status & SI476X_FM_RDS_INT) { | ||
513 | dev_dbg(&core->client->dev, "[interrupt] RDSINT\n"); | ||
514 | si476x_core_start_rds_drainer_once(core); | ||
515 | } | ||
516 | |||
517 | if (status & SI476X_STC_INT) { | ||
518 | dev_dbg(&core->client->dev, "[interrupt] STCINT\n"); | ||
519 | atomic_set(&core->stc, 1); | ||
520 | wake_up(&core->tuning); | ||
521 | } | ||
522 | } | ||
523 | |||
524 | static void si476x_core_poll_loop(struct work_struct *work) | ||
525 | { | ||
526 | struct si476x_core *core = SI476X_WORK_TO_CORE(work); | ||
527 | |||
528 | si476x_core_get_and_signal_status(core); | ||
529 | |||
530 | if (atomic_read(&core->is_alive)) | ||
531 | si476x_core_schedule_polling_work(core); | ||
532 | } | ||
533 | |||
534 | static irqreturn_t si476x_core_interrupt(int irq, void *dev) | ||
535 | { | ||
536 | struct si476x_core *core = dev; | ||
537 | |||
538 | si476x_core_get_and_signal_status(core); | ||
539 | |||
540 | return IRQ_HANDLED; | ||
541 | } | ||
542 | |||
543 | /** | ||
544 | * si476x_firmware_version_to_revision() | ||
545 | * @core: Core device structure | ||
546 | * @major: Firmware major number | ||
547 | * @minor1: Firmware first minor number | ||
548 | * @minor2: Firmware second minor number | ||
549 | * | ||
550 | * Convert a chip's firmware version number into an offset that later | ||
551 | * will be used to as offset in "vtable" of tuner functions | ||
552 | * | ||
553 | * This function returns a positive offset in case of success and a -1 | ||
554 | * in case of failure. | ||
555 | */ | ||
556 | static int si476x_core_fwver_to_revision(struct si476x_core *core, | ||
557 | int func, int major, | ||
558 | int minor1, int minor2) | ||
559 | { | ||
560 | switch (func) { | ||
561 | case SI476X_FUNC_FM_RECEIVER: | ||
562 | switch (major) { | ||
563 | case 5: | ||
564 | return SI476X_REVISION_A10; | ||
565 | case 8: | ||
566 | return SI476X_REVISION_A20; | ||
567 | case 10: | ||
568 | return SI476X_REVISION_A30; | ||
569 | default: | ||
570 | goto unknown_revision; | ||
571 | } | ||
572 | case SI476X_FUNC_AM_RECEIVER: | ||
573 | switch (major) { | ||
574 | case 5: | ||
575 | return SI476X_REVISION_A10; | ||
576 | case 7: | ||
577 | return SI476X_REVISION_A20; | ||
578 | case 9: | ||
579 | return SI476X_REVISION_A30; | ||
580 | default: | ||
581 | goto unknown_revision; | ||
582 | } | ||
583 | case SI476X_FUNC_WB_RECEIVER: | ||
584 | switch (major) { | ||
585 | case 3: | ||
586 | return SI476X_REVISION_A10; | ||
587 | case 5: | ||
588 | return SI476X_REVISION_A20; | ||
589 | case 7: | ||
590 | return SI476X_REVISION_A30; | ||
591 | default: | ||
592 | goto unknown_revision; | ||
593 | } | ||
594 | case SI476X_FUNC_BOOTLOADER: | ||
595 | default: /* FALLTHROUG */ | ||
596 | BUG(); | ||
597 | return -1; | ||
598 | } | ||
599 | |||
600 | unknown_revision: | ||
601 | dev_err(&core->client->dev, | ||
602 | "Unsupported version of the firmware: %d.%d.%d, " | ||
603 | "reverting to A10 comptible functions\n", | ||
604 | major, minor1, minor2); | ||
605 | |||
606 | return SI476X_REVISION_A10; | ||
607 | } | ||
608 | |||
609 | /** | ||
610 | * si476x_get_revision_info() | ||
611 | * @core: Core device structure | ||
612 | * | ||
613 | * Get the firmware version number of the device. It is done in | ||
614 | * following three steps: | ||
615 | * 1. Power-up the device | ||
616 | * 2. Send the 'FUNC_INFO' command | ||
617 | * 3. Powering the device down. | ||
618 | * | ||
619 | * The function return zero on success and a negative error code on | ||
620 | * failure. | ||
621 | */ | ||
622 | static int si476x_core_get_revision_info(struct si476x_core *core) | ||
623 | { | ||
624 | int rval; | ||
625 | struct si476x_func_info info; | ||
626 | |||
627 | si476x_core_lock(core); | ||
628 | rval = si476x_core_set_power_state(core, SI476X_POWER_UP_FULL); | ||
629 | if (rval < 0) | ||
630 | goto exit; | ||
631 | |||
632 | rval = si476x_core_cmd_func_info(core, &info); | ||
633 | if (rval < 0) | ||
634 | goto power_down; | ||
635 | |||
636 | core->revision = si476x_core_fwver_to_revision(core, info.func, | ||
637 | info.firmware.major, | ||
638 | info.firmware.minor[0], | ||
639 | info.firmware.minor[1]); | ||
640 | power_down: | ||
641 | si476x_core_set_power_state(core, SI476X_POWER_DOWN); | ||
642 | exit: | ||
643 | si476x_core_unlock(core); | ||
644 | |||
645 | return rval; | ||
646 | } | ||
647 | |||
648 | bool si476x_core_has_am(struct si476x_core *core) | ||
649 | { | ||
650 | return core->chip_id == SI476X_CHIP_SI4761 || | ||
651 | core->chip_id == SI476X_CHIP_SI4764; | ||
652 | } | ||
653 | EXPORT_SYMBOL_GPL(si476x_core_has_am); | ||
654 | |||
655 | bool si476x_core_has_diversity(struct si476x_core *core) | ||
656 | { | ||
657 | return core->chip_id == SI476X_CHIP_SI4764; | ||
658 | } | ||
659 | EXPORT_SYMBOL_GPL(si476x_core_has_diversity); | ||
660 | |||
661 | bool si476x_core_is_a_secondary_tuner(struct si476x_core *core) | ||
662 | { | ||
663 | return si476x_core_has_diversity(core) && | ||
664 | (core->diversity_mode == SI476X_PHDIV_SECONDARY_ANTENNA || | ||
665 | core->diversity_mode == SI476X_PHDIV_SECONDARY_COMBINING); | ||
666 | } | ||
667 | EXPORT_SYMBOL_GPL(si476x_core_is_a_secondary_tuner); | ||
668 | |||
669 | bool si476x_core_is_a_primary_tuner(struct si476x_core *core) | ||
670 | { | ||
671 | return si476x_core_has_diversity(core) && | ||
672 | (core->diversity_mode == SI476X_PHDIV_PRIMARY_ANTENNA || | ||
673 | core->diversity_mode == SI476X_PHDIV_PRIMARY_COMBINING); | ||
674 | } | ||
675 | EXPORT_SYMBOL_GPL(si476x_core_is_a_primary_tuner); | ||
676 | |||
677 | bool si476x_core_is_in_am_receiver_mode(struct si476x_core *core) | ||
678 | { | ||
679 | return si476x_core_has_am(core) && | ||
680 | (core->power_up_parameters.func == SI476X_FUNC_AM_RECEIVER); | ||
681 | } | ||
682 | EXPORT_SYMBOL_GPL(si476x_core_is_in_am_receiver_mode); | ||
683 | |||
684 | bool si476x_core_is_powered_up(struct si476x_core *core) | ||
685 | { | ||
686 | return core->power_state == SI476X_POWER_UP_FULL; | ||
687 | } | ||
688 | EXPORT_SYMBOL_GPL(si476x_core_is_powered_up); | ||
689 | |||
690 | static int si476x_core_probe(struct i2c_client *client, | ||
691 | const struct i2c_device_id *id) | ||
692 | { | ||
693 | int rval; | ||
694 | struct si476x_core *core; | ||
695 | struct si476x_platform_data *pdata; | ||
696 | struct mfd_cell *cell; | ||
697 | int cell_num; | ||
698 | |||
699 | core = devm_kzalloc(&client->dev, sizeof(*core), GFP_KERNEL); | ||
700 | if (!core) { | ||
701 | dev_err(&client->dev, | ||
702 | "failed to allocate 'struct si476x_core'\n"); | ||
703 | return -ENOMEM; | ||
704 | } | ||
705 | core->client = client; | ||
706 | |||
707 | core->regmap = devm_regmap_init_si476x(core); | ||
708 | if (IS_ERR(core->regmap)) { | ||
709 | rval = PTR_ERR(core->regmap); | ||
710 | dev_err(&client->dev, | ||
711 | "Failed to allocate register map: %d\n", | ||
712 | rval); | ||
713 | return rval; | ||
714 | } | ||
715 | |||
716 | i2c_set_clientdata(client, core); | ||
717 | |||
718 | atomic_set(&core->is_alive, 0); | ||
719 | core->power_state = SI476X_POWER_DOWN; | ||
720 | |||
721 | pdata = client->dev.platform_data; | ||
722 | if (pdata) { | ||
723 | memcpy(&core->power_up_parameters, | ||
724 | &pdata->power_up_parameters, | ||
725 | sizeof(core->power_up_parameters)); | ||
726 | |||
727 | core->gpio_reset = -1; | ||
728 | if (gpio_is_valid(pdata->gpio_reset)) { | ||
729 | rval = gpio_request(pdata->gpio_reset, "si476x reset"); | ||
730 | if (rval) { | ||
731 | dev_err(&client->dev, | ||
732 | "Failed to request gpio: %d\n", rval); | ||
733 | return rval; | ||
734 | } | ||
735 | core->gpio_reset = pdata->gpio_reset; | ||
736 | gpio_direction_output(core->gpio_reset, 0); | ||
737 | } | ||
738 | |||
739 | core->diversity_mode = pdata->diversity_mode; | ||
740 | memcpy(&core->pinmux, &pdata->pinmux, | ||
741 | sizeof(struct si476x_pinmux)); | ||
742 | } else { | ||
743 | dev_err(&client->dev, "No platform data provided\n"); | ||
744 | return -EINVAL; | ||
745 | } | ||
746 | |||
747 | core->supplies[0].supply = "vd"; | ||
748 | core->supplies[1].supply = "va"; | ||
749 | core->supplies[2].supply = "vio1"; | ||
750 | core->supplies[3].supply = "vio2"; | ||
751 | |||
752 | rval = devm_regulator_bulk_get(&client->dev, | ||
753 | ARRAY_SIZE(core->supplies), | ||
754 | core->supplies); | ||
755 | if (rval) { | ||
756 | dev_err(&client->dev, "Failet to gett all of the regulators\n"); | ||
757 | goto free_gpio; | ||
758 | } | ||
759 | |||
760 | mutex_init(&core->cmd_lock); | ||
761 | init_waitqueue_head(&core->command); | ||
762 | init_waitqueue_head(&core->tuning); | ||
763 | |||
764 | rval = kfifo_alloc(&core->rds_fifo, | ||
765 | SI476X_DRIVER_RDS_FIFO_DEPTH * | ||
766 | sizeof(struct v4l2_rds_data), | ||
767 | GFP_KERNEL); | ||
768 | if (rval) { | ||
769 | dev_err(&client->dev, "Could not alloate the FIFO\n"); | ||
770 | goto free_gpio; | ||
771 | } | ||
772 | mutex_init(&core->rds_drainer_status_lock); | ||
773 | init_waitqueue_head(&core->rds_read_queue); | ||
774 | INIT_WORK(&core->rds_fifo_drainer, si476x_core_drain_rds_fifo); | ||
775 | |||
776 | if (client->irq) { | ||
777 | rval = devm_request_threaded_irq(&client->dev, | ||
778 | client->irq, NULL, | ||
779 | si476x_core_interrupt, | ||
780 | IRQF_TRIGGER_FALLING, | ||
781 | client->name, core); | ||
782 | if (rval < 0) { | ||
783 | dev_err(&client->dev, "Could not request IRQ %d\n", | ||
784 | client->irq); | ||
785 | goto free_kfifo; | ||
786 | } | ||
787 | disable_irq(client->irq); | ||
788 | dev_dbg(&client->dev, "IRQ requested.\n"); | ||
789 | |||
790 | core->rds_fifo_depth = 20; | ||
791 | } else { | ||
792 | INIT_DELAYED_WORK(&core->status_monitor, | ||
793 | si476x_core_poll_loop); | ||
794 | dev_info(&client->dev, | ||
795 | "No IRQ number specified, will use polling\n"); | ||
796 | |||
797 | core->rds_fifo_depth = 5; | ||
798 | } | ||
799 | |||
800 | core->chip_id = id->driver_data; | ||
801 | |||
802 | rval = si476x_core_get_revision_info(core); | ||
803 | if (rval < 0) { | ||
804 | rval = -ENODEV; | ||
805 | goto free_kfifo; | ||
806 | } | ||
807 | |||
808 | cell_num = 0; | ||
809 | |||
810 | cell = &core->cells[SI476X_RADIO_CELL]; | ||
811 | cell->name = "si476x-radio"; | ||
812 | cell_num++; | ||
813 | |||
814 | #ifdef CONFIG_SND_SOC_SI476X | ||
815 | if ((core->chip_id == SI476X_CHIP_SI4761 || | ||
816 | core->chip_id == SI476X_CHIP_SI4764) && | ||
817 | core->pinmux.dclk == SI476X_DCLK_DAUDIO && | ||
818 | core->pinmux.dfs == SI476X_DFS_DAUDIO && | ||
819 | core->pinmux.dout == SI476X_DOUT_I2S_OUTPUT && | ||
820 | core->pinmux.xout == SI476X_XOUT_TRISTATE) { | ||
821 | cell = &core->cells[SI476X_CODEC_CELL]; | ||
822 | cell->name = "si476x-codec"; | ||
823 | cell_num++; | ||
824 | } | ||
825 | #endif | ||
826 | rval = mfd_add_devices(&client->dev, | ||
827 | (client->adapter->nr << 8) + client->addr, | ||
828 | core->cells, cell_num, | ||
829 | NULL, 0, NULL); | ||
830 | if (!rval) | ||
831 | return 0; | ||
832 | |||
833 | free_kfifo: | ||
834 | kfifo_free(&core->rds_fifo); | ||
835 | |||
836 | free_gpio: | ||
837 | if (gpio_is_valid(core->gpio_reset)) | ||
838 | gpio_free(core->gpio_reset); | ||
839 | |||
840 | return rval; | ||
841 | } | ||
842 | |||
843 | static int si476x_core_remove(struct i2c_client *client) | ||
844 | { | ||
845 | struct si476x_core *core = i2c_get_clientdata(client); | ||
846 | |||
847 | si476x_core_pronounce_dead(core); | ||
848 | mfd_remove_devices(&client->dev); | ||
849 | |||
850 | if (client->irq) | ||
851 | disable_irq(client->irq); | ||
852 | else | ||
853 | cancel_delayed_work_sync(&core->status_monitor); | ||
854 | |||
855 | kfifo_free(&core->rds_fifo); | ||
856 | |||
857 | if (gpio_is_valid(core->gpio_reset)) | ||
858 | gpio_free(core->gpio_reset); | ||
859 | |||
860 | return 0; | ||
861 | } | ||
862 | |||
863 | |||
864 | static const struct i2c_device_id si476x_id[] = { | ||
865 | { "si4761", SI476X_CHIP_SI4761 }, | ||
866 | { "si4764", SI476X_CHIP_SI4764 }, | ||
867 | { "si4768", SI476X_CHIP_SI4768 }, | ||
868 | { }, | ||
869 | }; | ||
870 | MODULE_DEVICE_TABLE(i2c, si476x_id); | ||
871 | |||
872 | static struct i2c_driver si476x_core_driver = { | ||
873 | .driver = { | ||
874 | .name = "si476x-core", | ||
875 | .owner = THIS_MODULE, | ||
876 | }, | ||
877 | .probe = si476x_core_probe, | ||
878 | .remove = si476x_core_remove, | ||
879 | .id_table = si476x_id, | ||
880 | }; | ||
881 | module_i2c_driver(si476x_core_driver); | ||
882 | |||
883 | |||
884 | MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>"); | ||
885 | MODULE_DESCRIPTION("Si4761/64/68 AM/FM MFD core device driver"); | ||
886 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/si476x-prop.c b/drivers/mfd/si476x-prop.c new file mode 100644 index 000000000000..cfeffa6e15d9 --- /dev/null +++ b/drivers/mfd/si476x-prop.c | |||
@@ -0,0 +1,241 @@ | |||
1 | /* | ||
2 | * drivers/mfd/si476x-prop.c -- Subroutines to access | ||
3 | * properties of si476x chips | ||
4 | * | ||
5 | * Copyright (C) 2012 Innovative Converged Devices(ICD) | ||
6 | * Copyright (C) 2013 Andrey Smirnov | ||
7 | * | ||
8 | * Author: Andrey Smirnov <andrew.smirnov@gmail.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; version 2 of the License. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | */ | ||
19 | #include <linux/module.h> | ||
20 | |||
21 | #include <linux/mfd/si476x-core.h> | ||
22 | |||
23 | struct si476x_property_range { | ||
24 | u16 low, high; | ||
25 | }; | ||
26 | |||
27 | static bool si476x_core_element_is_in_array(u16 element, | ||
28 | const u16 array[], | ||
29 | size_t size) | ||
30 | { | ||
31 | int i; | ||
32 | |||
33 | for (i = 0; i < size; i++) | ||
34 | if (element == array[i]) | ||
35 | return true; | ||
36 | |||
37 | return false; | ||
38 | } | ||
39 | |||
40 | static bool si476x_core_element_is_in_range(u16 element, | ||
41 | const struct si476x_property_range range[], | ||
42 | size_t size) | ||
43 | { | ||
44 | int i; | ||
45 | |||
46 | for (i = 0; i < size; i++) | ||
47 | if (element <= range[i].high && element >= range[i].low) | ||
48 | return true; | ||
49 | |||
50 | return false; | ||
51 | } | ||
52 | |||
53 | static bool si476x_core_is_valid_property_a10(struct si476x_core *core, | ||
54 | u16 property) | ||
55 | { | ||
56 | static const u16 valid_properties[] = { | ||
57 | 0x0000, | ||
58 | 0x0500, 0x0501, | ||
59 | 0x0600, | ||
60 | 0x0709, 0x070C, 0x070D, 0x70E, 0x710, | ||
61 | 0x0718, | ||
62 | 0x1207, 0x1208, | ||
63 | 0x2007, | ||
64 | 0x2300, | ||
65 | }; | ||
66 | |||
67 | static const struct si476x_property_range valid_ranges[] = { | ||
68 | { 0x0200, 0x0203 }, | ||
69 | { 0x0300, 0x0303 }, | ||
70 | { 0x0400, 0x0404 }, | ||
71 | { 0x0700, 0x0707 }, | ||
72 | { 0x1100, 0x1102 }, | ||
73 | { 0x1200, 0x1204 }, | ||
74 | { 0x1300, 0x1306 }, | ||
75 | { 0x2000, 0x2005 }, | ||
76 | { 0x2100, 0x2104 }, | ||
77 | { 0x2106, 0x2106 }, | ||
78 | { 0x2200, 0x220E }, | ||
79 | { 0x3100, 0x3104 }, | ||
80 | { 0x3207, 0x320F }, | ||
81 | { 0x3300, 0x3304 }, | ||
82 | { 0x3500, 0x3517 }, | ||
83 | { 0x3600, 0x3617 }, | ||
84 | { 0x3700, 0x3717 }, | ||
85 | { 0x4000, 0x4003 }, | ||
86 | }; | ||
87 | |||
88 | return si476x_core_element_is_in_range(property, valid_ranges, | ||
89 | ARRAY_SIZE(valid_ranges)) || | ||
90 | si476x_core_element_is_in_array(property, valid_properties, | ||
91 | ARRAY_SIZE(valid_properties)); | ||
92 | } | ||
93 | |||
94 | static bool si476x_core_is_valid_property_a20(struct si476x_core *core, | ||
95 | u16 property) | ||
96 | { | ||
97 | static const u16 valid_properties[] = { | ||
98 | 0x071B, | ||
99 | 0x1006, | ||
100 | 0x2210, | ||
101 | 0x3401, | ||
102 | }; | ||
103 | |||
104 | static const struct si476x_property_range valid_ranges[] = { | ||
105 | { 0x2215, 0x2219 }, | ||
106 | }; | ||
107 | |||
108 | return si476x_core_is_valid_property_a10(core, property) || | ||
109 | si476x_core_element_is_in_range(property, valid_ranges, | ||
110 | ARRAY_SIZE(valid_ranges)) || | ||
111 | si476x_core_element_is_in_array(property, valid_properties, | ||
112 | ARRAY_SIZE(valid_properties)); | ||
113 | } | ||
114 | |||
115 | static bool si476x_core_is_valid_property_a30(struct si476x_core *core, | ||
116 | u16 property) | ||
117 | { | ||
118 | static const u16 valid_properties[] = { | ||
119 | 0x071C, 0x071D, | ||
120 | 0x1007, 0x1008, | ||
121 | 0x220F, 0x2214, | ||
122 | 0x2301, | ||
123 | 0x3105, 0x3106, | ||
124 | 0x3402, | ||
125 | }; | ||
126 | |||
127 | static const struct si476x_property_range valid_ranges[] = { | ||
128 | { 0x0405, 0x0411 }, | ||
129 | { 0x2008, 0x200B }, | ||
130 | { 0x2220, 0x2223 }, | ||
131 | { 0x3100, 0x3106 }, | ||
132 | }; | ||
133 | |||
134 | return si476x_core_is_valid_property_a20(core, property) || | ||
135 | si476x_core_element_is_in_range(property, valid_ranges, | ||
136 | ARRAY_SIZE(valid_ranges)) || | ||
137 | si476x_core_element_is_in_array(property, valid_properties, | ||
138 | ARRAY_SIZE(valid_properties)); | ||
139 | } | ||
140 | |||
141 | typedef bool (*valid_property_pred_t) (struct si476x_core *, u16); | ||
142 | |||
143 | static bool si476x_core_is_valid_property(struct si476x_core *core, | ||
144 | u16 property) | ||
145 | { | ||
146 | static const valid_property_pred_t is_valid_property[] = { | ||
147 | [SI476X_REVISION_A10] = si476x_core_is_valid_property_a10, | ||
148 | [SI476X_REVISION_A20] = si476x_core_is_valid_property_a20, | ||
149 | [SI476X_REVISION_A30] = si476x_core_is_valid_property_a30, | ||
150 | }; | ||
151 | |||
152 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
153 | core->revision == -1); | ||
154 | return is_valid_property[core->revision](core, property); | ||
155 | } | ||
156 | |||
157 | |||
158 | static bool si476x_core_is_readonly_property(struct si476x_core *core, | ||
159 | u16 property) | ||
160 | { | ||
161 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
162 | core->revision == -1); | ||
163 | |||
164 | switch (core->revision) { | ||
165 | case SI476X_REVISION_A10: | ||
166 | return (property == 0x3200); | ||
167 | case SI476X_REVISION_A20: | ||
168 | return (property == 0x1006 || | ||
169 | property == 0x2210 || | ||
170 | property == 0x3200); | ||
171 | case SI476X_REVISION_A30: | ||
172 | return false; | ||
173 | } | ||
174 | |||
175 | return false; | ||
176 | } | ||
177 | |||
178 | static bool si476x_core_regmap_readable_register(struct device *dev, | ||
179 | unsigned int reg) | ||
180 | { | ||
181 | struct i2c_client *client = to_i2c_client(dev); | ||
182 | struct si476x_core *core = i2c_get_clientdata(client); | ||
183 | |||
184 | return si476x_core_is_valid_property(core, (u16) reg); | ||
185 | |||
186 | } | ||
187 | |||
188 | static bool si476x_core_regmap_writable_register(struct device *dev, | ||
189 | unsigned int reg) | ||
190 | { | ||
191 | struct i2c_client *client = to_i2c_client(dev); | ||
192 | struct si476x_core *core = i2c_get_clientdata(client); | ||
193 | |||
194 | return si476x_core_is_valid_property(core, (u16) reg) && | ||
195 | !si476x_core_is_readonly_property(core, (u16) reg); | ||
196 | } | ||
197 | |||
198 | |||
199 | static int si476x_core_regmap_write(void *context, unsigned int reg, | ||
200 | unsigned int val) | ||
201 | { | ||
202 | return si476x_core_cmd_set_property(context, reg, val); | ||
203 | } | ||
204 | |||
205 | static int si476x_core_regmap_read(void *context, unsigned int reg, | ||
206 | unsigned *val) | ||
207 | { | ||
208 | struct si476x_core *core = context; | ||
209 | int err; | ||
210 | |||
211 | err = si476x_core_cmd_get_property(core, reg); | ||
212 | if (err < 0) | ||
213 | return err; | ||
214 | |||
215 | *val = err; | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | |||
221 | static const struct regmap_config si476x_regmap_config = { | ||
222 | .reg_bits = 16, | ||
223 | .val_bits = 16, | ||
224 | |||
225 | .max_register = 0x4003, | ||
226 | |||
227 | .writeable_reg = si476x_core_regmap_writable_register, | ||
228 | .readable_reg = si476x_core_regmap_readable_register, | ||
229 | |||
230 | .reg_read = si476x_core_regmap_read, | ||
231 | .reg_write = si476x_core_regmap_write, | ||
232 | |||
233 | .cache_type = REGCACHE_RBTREE, | ||
234 | }; | ||
235 | |||
236 | struct regmap *devm_regmap_init_si476x(struct si476x_core *core) | ||
237 | { | ||
238 | return devm_regmap_init(&core->client->dev, NULL, | ||
239 | core, &si476x_regmap_config); | ||
240 | } | ||
241 | EXPORT_SYMBOL_GPL(devm_regmap_init_si476x); | ||
diff --git a/drivers/mfd/sta2x11-mfd.c b/drivers/mfd/sta2x11-mfd.c index 9bd33169a111..d70a343078fd 100644 --- a/drivers/mfd/sta2x11-mfd.c +++ b/drivers/mfd/sta2x11-mfd.c | |||
@@ -98,17 +98,6 @@ static int sta2x11_mfd_add(struct pci_dev *pdev, gfp_t flags) | |||
98 | return 0; | 98 | return 0; |
99 | } | 99 | } |
100 | 100 | ||
101 | static int mfd_remove(struct pci_dev *pdev) | ||
102 | { | ||
103 | struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev); | ||
104 | |||
105 | if (!mfd) | ||
106 | return -ENODEV; | ||
107 | list_del(&mfd->list); | ||
108 | kfree(mfd); | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | /* This function is exported and is not expected to fail */ | 101 | /* This function is exported and is not expected to fail */ |
113 | u32 __sta2x11_mfd_mask(struct pci_dev *pdev, u32 reg, u32 mask, u32 val, | 102 | u32 __sta2x11_mfd_mask(struct pci_dev *pdev, u32 reg, u32 mask, u32 val, |
114 | enum sta2x11_mfd_plat_dev index) | 103 | enum sta2x11_mfd_plat_dev index) |
diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c index fd5fcb630685..0da02e11d58e 100644 --- a/drivers/mfd/stmpe-i2c.c +++ b/drivers/mfd/stmpe-i2c.c | |||
@@ -75,6 +75,7 @@ static const struct i2c_device_id stmpe_i2c_id[] = { | |||
75 | { "stmpe801", STMPE801 }, | 75 | { "stmpe801", STMPE801 }, |
76 | { "stmpe811", STMPE811 }, | 76 | { "stmpe811", STMPE811 }, |
77 | { "stmpe1601", STMPE1601 }, | 77 | { "stmpe1601", STMPE1601 }, |
78 | { "stmpe1801", STMPE1801 }, | ||
78 | { "stmpe2401", STMPE2401 }, | 79 | { "stmpe2401", STMPE2401 }, |
79 | { "stmpe2403", STMPE2403 }, | 80 | { "stmpe2403", STMPE2403 }, |
80 | { } | 81 | { } |
diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c index 973659f8abd9..a81badbaa917 100644 --- a/drivers/mfd/stmpe-spi.c +++ b/drivers/mfd/stmpe-spi.c | |||
@@ -103,7 +103,7 @@ stmpe_spi_probe(struct spi_device *spi) | |||
103 | 103 | ||
104 | static int stmpe_spi_remove(struct spi_device *spi) | 104 | static int stmpe_spi_remove(struct spi_device *spi) |
105 | { | 105 | { |
106 | struct stmpe *stmpe = dev_get_drvdata(&spi->dev); | 106 | struct stmpe *stmpe = spi_get_drvdata(spi); |
107 | 107 | ||
108 | return stmpe_remove(stmpe); | 108 | return stmpe_remove(stmpe); |
109 | } | 109 | } |
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 4b11202061be..bbccd514d3ec 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/mfd/core.h> | 21 | #include <linux/mfd/core.h> |
22 | #include <linux/delay.h> | ||
22 | #include "stmpe.h" | 23 | #include "stmpe.h" |
23 | 24 | ||
24 | static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks) | 25 | static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks) |
@@ -643,6 +644,88 @@ static struct stmpe_variant_info stmpe1601 = { | |||
643 | }; | 644 | }; |
644 | 645 | ||
645 | /* | 646 | /* |
647 | * STMPE1801 | ||
648 | */ | ||
649 | static const u8 stmpe1801_regs[] = { | ||
650 | [STMPE_IDX_CHIP_ID] = STMPE1801_REG_CHIP_ID, | ||
651 | [STMPE_IDX_ICR_LSB] = STMPE1801_REG_INT_CTRL_LOW, | ||
652 | [STMPE_IDX_IER_LSB] = STMPE1801_REG_INT_EN_MASK_LOW, | ||
653 | [STMPE_IDX_ISR_LSB] = STMPE1801_REG_INT_STA_LOW, | ||
654 | [STMPE_IDX_GPMR_LSB] = STMPE1801_REG_GPIO_MP_LOW, | ||
655 | [STMPE_IDX_GPSR_LSB] = STMPE1801_REG_GPIO_SET_LOW, | ||
656 | [STMPE_IDX_GPCR_LSB] = STMPE1801_REG_GPIO_CLR_LOW, | ||
657 | [STMPE_IDX_GPDR_LSB] = STMPE1801_REG_GPIO_SET_DIR_LOW, | ||
658 | [STMPE_IDX_GPRER_LSB] = STMPE1801_REG_GPIO_RE_LOW, | ||
659 | [STMPE_IDX_GPFER_LSB] = STMPE1801_REG_GPIO_FE_LOW, | ||
660 | [STMPE_IDX_IEGPIOR_LSB] = STMPE1801_REG_INT_EN_GPIO_MASK_LOW, | ||
661 | [STMPE_IDX_ISGPIOR_LSB] = STMPE1801_REG_INT_STA_GPIO_LOW, | ||
662 | }; | ||
663 | |||
664 | static struct stmpe_variant_block stmpe1801_blocks[] = { | ||
665 | { | ||
666 | .cell = &stmpe_gpio_cell, | ||
667 | .irq = STMPE1801_IRQ_GPIOC, | ||
668 | .block = STMPE_BLOCK_GPIO, | ||
669 | }, | ||
670 | { | ||
671 | .cell = &stmpe_keypad_cell, | ||
672 | .irq = STMPE1801_IRQ_KEYPAD, | ||
673 | .block = STMPE_BLOCK_KEYPAD, | ||
674 | }, | ||
675 | }; | ||
676 | |||
677 | static int stmpe1801_enable(struct stmpe *stmpe, unsigned int blocks, | ||
678 | bool enable) | ||
679 | { | ||
680 | unsigned int mask = 0; | ||
681 | if (blocks & STMPE_BLOCK_GPIO) | ||
682 | mask |= STMPE1801_MSK_INT_EN_GPIO; | ||
683 | |||
684 | if (blocks & STMPE_BLOCK_KEYPAD) | ||
685 | mask |= STMPE1801_MSK_INT_EN_KPC; | ||
686 | |||
687 | return __stmpe_set_bits(stmpe, STMPE1801_REG_INT_EN_MASK_LOW, mask, | ||
688 | enable ? mask : 0); | ||
689 | } | ||
690 | |||
691 | static int stmpe1801_reset(struct stmpe *stmpe) | ||
692 | { | ||
693 | unsigned long timeout; | ||
694 | int ret = 0; | ||
695 | |||
696 | ret = __stmpe_set_bits(stmpe, STMPE1801_REG_SYS_CTRL, | ||
697 | STMPE1801_MSK_SYS_CTRL_RESET, STMPE1801_MSK_SYS_CTRL_RESET); | ||
698 | if (ret < 0) | ||
699 | return ret; | ||
700 | |||
701 | timeout = jiffies + msecs_to_jiffies(100); | ||
702 | while (time_before(jiffies, timeout)) { | ||
703 | ret = __stmpe_reg_read(stmpe, STMPE1801_REG_SYS_CTRL); | ||
704 | if (ret < 0) | ||
705 | return ret; | ||
706 | if (!(ret & STMPE1801_MSK_SYS_CTRL_RESET)) | ||
707 | return 0; | ||
708 | usleep_range(100, 200); | ||
709 | }; | ||
710 | return -EIO; | ||
711 | } | ||
712 | |||
713 | static struct stmpe_variant_info stmpe1801 = { | ||
714 | .name = "stmpe1801", | ||
715 | .id_val = STMPE1801_ID, | ||
716 | .id_mask = 0xfff0, | ||
717 | .num_gpios = 18, | ||
718 | .af_bits = 0, | ||
719 | .regs = stmpe1801_regs, | ||
720 | .blocks = stmpe1801_blocks, | ||
721 | .num_blocks = ARRAY_SIZE(stmpe1801_blocks), | ||
722 | .num_irqs = STMPE1801_NR_INTERNAL_IRQS, | ||
723 | .enable = stmpe1801_enable, | ||
724 | /* stmpe1801 do not have any gpio alternate function */ | ||
725 | .get_altfunc = NULL, | ||
726 | }; | ||
727 | |||
728 | /* | ||
646 | * STMPE24XX | 729 | * STMPE24XX |
647 | */ | 730 | */ |
648 | 731 | ||
@@ -740,6 +823,7 @@ static struct stmpe_variant_info *stmpe_variant_info[STMPE_NBR_PARTS] = { | |||
740 | [STMPE801] = &stmpe801, | 823 | [STMPE801] = &stmpe801, |
741 | [STMPE811] = &stmpe811, | 824 | [STMPE811] = &stmpe811, |
742 | [STMPE1601] = &stmpe1601, | 825 | [STMPE1601] = &stmpe1601, |
826 | [STMPE1801] = &stmpe1801, | ||
743 | [STMPE2401] = &stmpe2401, | 827 | [STMPE2401] = &stmpe2401, |
744 | [STMPE2403] = &stmpe2403, | 828 | [STMPE2403] = &stmpe2403, |
745 | }; | 829 | }; |
@@ -759,7 +843,7 @@ static irqreturn_t stmpe_irq(int irq, void *data) | |||
759 | struct stmpe *stmpe = data; | 843 | struct stmpe *stmpe = data; |
760 | struct stmpe_variant_info *variant = stmpe->variant; | 844 | struct stmpe_variant_info *variant = stmpe->variant; |
761 | int num = DIV_ROUND_UP(variant->num_irqs, 8); | 845 | int num = DIV_ROUND_UP(variant->num_irqs, 8); |
762 | u8 israddr = stmpe->regs[STMPE_IDX_ISR_MSB]; | 846 | u8 israddr; |
763 | u8 isr[num]; | 847 | u8 isr[num]; |
764 | int ret; | 848 | int ret; |
765 | int i; | 849 | int i; |
@@ -771,6 +855,11 @@ static irqreturn_t stmpe_irq(int irq, void *data) | |||
771 | return IRQ_HANDLED; | 855 | return IRQ_HANDLED; |
772 | } | 856 | } |
773 | 857 | ||
858 | if (variant->id_val == STMPE1801_ID) | ||
859 | israddr = stmpe->regs[STMPE_IDX_ISR_LSB]; | ||
860 | else | ||
861 | israddr = stmpe->regs[STMPE_IDX_ISR_MSB]; | ||
862 | |||
774 | ret = stmpe_block_read(stmpe, israddr, num, isr); | 863 | ret = stmpe_block_read(stmpe, israddr, num, isr); |
775 | if (ret < 0) | 864 | if (ret < 0) |
776 | return IRQ_NONE; | 865 | return IRQ_NONE; |
@@ -938,6 +1027,12 @@ static int stmpe_chip_init(struct stmpe *stmpe) | |||
938 | if (ret) | 1027 | if (ret) |
939 | return ret; | 1028 | return ret; |
940 | 1029 | ||
1030 | if (id == STMPE1801_ID) { | ||
1031 | ret = stmpe1801_reset(stmpe); | ||
1032 | if (ret < 0) | ||
1033 | return ret; | ||
1034 | } | ||
1035 | |||
941 | if (stmpe->irq >= 0) { | 1036 | if (stmpe->irq >= 0) { |
942 | if (id == STMPE801_ID) | 1037 | if (id == STMPE801_ID) |
943 | icr = STMPE801_REG_SYS_CTRL_INT_EN; | 1038 | icr = STMPE801_REG_SYS_CTRL_INT_EN; |
@@ -1015,7 +1110,10 @@ void stmpe_of_probe(struct stmpe_platform_data *pdata, struct device_node *np) | |||
1015 | { | 1110 | { |
1016 | struct device_node *child; | 1111 | struct device_node *child; |
1017 | 1112 | ||
1018 | pdata->id = -1; | 1113 | pdata->id = of_alias_get_id(np, "stmpe-i2c"); |
1114 | if (pdata->id < 0) | ||
1115 | pdata->id = -1; | ||
1116 | |||
1019 | pdata->irq_trigger = IRQF_TRIGGER_NONE; | 1117 | pdata->irq_trigger = IRQF_TRIGGER_NONE; |
1020 | 1118 | ||
1021 | of_property_read_u32(np, "st,autosleep-timeout", | 1119 | of_property_read_u32(np, "st,autosleep-timeout", |
@@ -1057,6 +1155,9 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum) | |||
1057 | return -ENOMEM; | 1155 | return -ENOMEM; |
1058 | 1156 | ||
1059 | stmpe_of_probe(pdata, np); | 1157 | stmpe_of_probe(pdata, np); |
1158 | |||
1159 | if (of_find_property(np, "interrupts", NULL) == NULL) | ||
1160 | ci->irq = -1; | ||
1060 | } | 1161 | } |
1061 | 1162 | ||
1062 | stmpe = devm_kzalloc(ci->dev, sizeof(struct stmpe), GFP_KERNEL); | 1163 | stmpe = devm_kzalloc(ci->dev, sizeof(struct stmpe), GFP_KERNEL); |
diff --git a/drivers/mfd/stmpe.h b/drivers/mfd/stmpe.h index 7b8e13f5b764..ff2b09ba8797 100644 --- a/drivers/mfd/stmpe.h +++ b/drivers/mfd/stmpe.h | |||
@@ -199,6 +199,55 @@ int stmpe_remove(struct stmpe *stmpe); | |||
199 | #define STPME1601_AUTOSLEEP_ENABLE (1 << 3) | 199 | #define STPME1601_AUTOSLEEP_ENABLE (1 << 3) |
200 | 200 | ||
201 | /* | 201 | /* |
202 | * STMPE1801 | ||
203 | */ | ||
204 | #define STMPE1801_ID 0xc110 | ||
205 | #define STMPE1801_NR_INTERNAL_IRQS 5 | ||
206 | #define STMPE1801_IRQ_KEYPAD_COMBI 4 | ||
207 | #define STMPE1801_IRQ_GPIOC 3 | ||
208 | #define STMPE1801_IRQ_KEYPAD_OVER 2 | ||
209 | #define STMPE1801_IRQ_KEYPAD 1 | ||
210 | #define STMPE1801_IRQ_WAKEUP 0 | ||
211 | |||
212 | #define STMPE1801_REG_CHIP_ID 0x00 | ||
213 | #define STMPE1801_REG_SYS_CTRL 0x02 | ||
214 | #define STMPE1801_REG_INT_CTRL_LOW 0x04 | ||
215 | #define STMPE1801_REG_INT_EN_MASK_LOW 0x06 | ||
216 | #define STMPE1801_REG_INT_STA_LOW 0x08 | ||
217 | #define STMPE1801_REG_INT_EN_GPIO_MASK_LOW 0x0A | ||
218 | #define STMPE1801_REG_INT_EN_GPIO_MASK_MID 0x0B | ||
219 | #define STMPE1801_REG_INT_EN_GPIO_MASK_HIGH 0x0C | ||
220 | #define STMPE1801_REG_INT_STA_GPIO_LOW 0x0D | ||
221 | #define STMPE1801_REG_INT_STA_GPIO_MID 0x0E | ||
222 | #define STMPE1801_REG_INT_STA_GPIO_HIGH 0x0F | ||
223 | #define STMPE1801_REG_GPIO_SET_LOW 0x10 | ||
224 | #define STMPE1801_REG_GPIO_SET_MID 0x11 | ||
225 | #define STMPE1801_REG_GPIO_SET_HIGH 0x12 | ||
226 | #define STMPE1801_REG_GPIO_CLR_LOW 0x13 | ||
227 | #define STMPE1801_REG_GPIO_CLR_MID 0x14 | ||
228 | #define STMPE1801_REG_GPIO_CLR_HIGH 0x15 | ||
229 | #define STMPE1801_REG_GPIO_MP_LOW 0x16 | ||
230 | #define STMPE1801_REG_GPIO_MP_MID 0x17 | ||
231 | #define STMPE1801_REG_GPIO_MP_HIGH 0x18 | ||
232 | #define STMPE1801_REG_GPIO_SET_DIR_LOW 0x19 | ||
233 | #define STMPE1801_REG_GPIO_SET_DIR_MID 0x1A | ||
234 | #define STMPE1801_REG_GPIO_SET_DIR_HIGH 0x1B | ||
235 | #define STMPE1801_REG_GPIO_RE_LOW 0x1C | ||
236 | #define STMPE1801_REG_GPIO_RE_MID 0x1D | ||
237 | #define STMPE1801_REG_GPIO_RE_HIGH 0x1E | ||
238 | #define STMPE1801_REG_GPIO_FE_LOW 0x1F | ||
239 | #define STMPE1801_REG_GPIO_FE_MID 0x20 | ||
240 | #define STMPE1801_REG_GPIO_FE_HIGH 0x21 | ||
241 | #define STMPE1801_REG_GPIO_PULL_UP_LOW 0x22 | ||
242 | #define STMPE1801_REG_GPIO_PULL_UP_MID 0x23 | ||
243 | #define STMPE1801_REG_GPIO_PULL_UP_HIGH 0x24 | ||
244 | |||
245 | #define STMPE1801_MSK_SYS_CTRL_RESET (1 << 7) | ||
246 | |||
247 | #define STMPE1801_MSK_INT_EN_KPC (1 << 1) | ||
248 | #define STMPE1801_MSK_INT_EN_GPIO (1 << 3) | ||
249 | |||
250 | /* | ||
202 | * STMPE24xx | 251 | * STMPE24xx |
203 | */ | 252 | */ |
204 | 253 | ||
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 61aea6381cdf..962a6e17a01a 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c | |||
@@ -25,17 +25,15 @@ | |||
25 | static struct platform_driver syscon_driver; | 25 | static struct platform_driver syscon_driver; |
26 | 26 | ||
27 | struct syscon { | 27 | struct syscon { |
28 | struct device *dev; | ||
29 | void __iomem *base; | 28 | void __iomem *base; |
30 | struct regmap *regmap; | 29 | struct regmap *regmap; |
31 | }; | 30 | }; |
32 | 31 | ||
33 | static int syscon_match(struct device *dev, void *data) | 32 | static int syscon_match_node(struct device *dev, void *data) |
34 | { | 33 | { |
35 | struct syscon *syscon = dev_get_drvdata(dev); | ||
36 | struct device_node *dn = data; | 34 | struct device_node *dn = data; |
37 | 35 | ||
38 | return (syscon->dev->of_node == dn) ? 1 : 0; | 36 | return (dev->of_node == dn) ? 1 : 0; |
39 | } | 37 | } |
40 | 38 | ||
41 | struct regmap *syscon_node_to_regmap(struct device_node *np) | 39 | struct regmap *syscon_node_to_regmap(struct device_node *np) |
@@ -44,7 +42,7 @@ struct regmap *syscon_node_to_regmap(struct device_node *np) | |||
44 | struct device *dev; | 42 | struct device *dev; |
45 | 43 | ||
46 | dev = driver_find_device(&syscon_driver.driver, NULL, np, | 44 | dev = driver_find_device(&syscon_driver.driver, NULL, np, |
47 | syscon_match); | 45 | syscon_match_node); |
48 | if (!dev) | 46 | if (!dev) |
49 | return ERR_PTR(-EPROBE_DEFER); | 47 | return ERR_PTR(-EPROBE_DEFER); |
50 | 48 | ||
@@ -70,6 +68,34 @@ struct regmap *syscon_regmap_lookup_by_compatible(const char *s) | |||
70 | } | 68 | } |
71 | EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible); | 69 | EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible); |
72 | 70 | ||
71 | static int syscon_match_pdevname(struct device *dev, void *data) | ||
72 | { | ||
73 | struct platform_device *pdev = to_platform_device(dev); | ||
74 | const struct platform_device_id *id = platform_get_device_id(pdev); | ||
75 | |||
76 | if (id) | ||
77 | if (!strcmp(id->name, (const char *)data)) | ||
78 | return 1; | ||
79 | |||
80 | return !strcmp(dev_name(dev), (const char *)data); | ||
81 | } | ||
82 | |||
83 | struct regmap *syscon_regmap_lookup_by_pdevname(const char *s) | ||
84 | { | ||
85 | struct device *dev; | ||
86 | struct syscon *syscon; | ||
87 | |||
88 | dev = driver_find_device(&syscon_driver.driver, NULL, (void *)s, | ||
89 | syscon_match_pdevname); | ||
90 | if (!dev) | ||
91 | return ERR_PTR(-EPROBE_DEFER); | ||
92 | |||
93 | syscon = dev_get_drvdata(dev); | ||
94 | |||
95 | return syscon->regmap; | ||
96 | } | ||
97 | EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_pdevname); | ||
98 | |||
73 | struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, | 99 | struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, |
74 | const char *property) | 100 | const char *property) |
75 | { | 101 | { |
@@ -101,28 +127,22 @@ static struct regmap_config syscon_regmap_config = { | |||
101 | static int syscon_probe(struct platform_device *pdev) | 127 | static int syscon_probe(struct platform_device *pdev) |
102 | { | 128 | { |
103 | struct device *dev = &pdev->dev; | 129 | struct device *dev = &pdev->dev; |
104 | struct device_node *np = dev->of_node; | ||
105 | struct syscon *syscon; | 130 | struct syscon *syscon; |
106 | struct resource res; | 131 | struct resource *res; |
107 | int ret; | ||
108 | |||
109 | if (!np) | ||
110 | return -ENOENT; | ||
111 | 132 | ||
112 | syscon = devm_kzalloc(dev, sizeof(struct syscon), | 133 | syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL); |
113 | GFP_KERNEL); | ||
114 | if (!syscon) | 134 | if (!syscon) |
115 | return -ENOMEM; | 135 | return -ENOMEM; |
116 | 136 | ||
117 | syscon->base = of_iomap(np, 0); | 137 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
118 | if (!syscon->base) | 138 | if (!res) |
119 | return -EADDRNOTAVAIL; | 139 | return -ENOENT; |
120 | 140 | ||
121 | ret = of_address_to_resource(np, 0, &res); | 141 | syscon->base = devm_ioremap(dev, res->start, resource_size(res)); |
122 | if (ret) | 142 | if (!syscon->base) |
123 | return ret; | 143 | return -ENOMEM; |
124 | 144 | ||
125 | syscon_regmap_config.max_register = res.end - res.start - 3; | 145 | syscon_regmap_config.max_register = res->end - res->start - 3; |
126 | syscon->regmap = devm_regmap_init_mmio(dev, syscon->base, | 146 | syscon->regmap = devm_regmap_init_mmio(dev, syscon->base, |
127 | &syscon_regmap_config); | 147 | &syscon_regmap_config); |
128 | if (IS_ERR(syscon->regmap)) { | 148 | if (IS_ERR(syscon->regmap)) { |
@@ -130,25 +150,17 @@ static int syscon_probe(struct platform_device *pdev) | |||
130 | return PTR_ERR(syscon->regmap); | 150 | return PTR_ERR(syscon->regmap); |
131 | } | 151 | } |
132 | 152 | ||
133 | syscon->dev = dev; | ||
134 | platform_set_drvdata(pdev, syscon); | 153 | platform_set_drvdata(pdev, syscon); |
135 | 154 | ||
136 | dev_info(dev, "syscon regmap start 0x%x end 0x%x registered\n", | 155 | dev_info(dev, "regmap %pR registered\n", res); |
137 | res.start, res.end); | ||
138 | 156 | ||
139 | return 0; | 157 | return 0; |
140 | } | 158 | } |
141 | 159 | ||
142 | static int syscon_remove(struct platform_device *pdev) | 160 | static const struct platform_device_id syscon_ids[] = { |
143 | { | 161 | { "syscon", }, |
144 | struct syscon *syscon; | 162 | { } |
145 | 163 | }; | |
146 | syscon = platform_get_drvdata(pdev); | ||
147 | iounmap(syscon->base); | ||
148 | platform_set_drvdata(pdev, NULL); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | 164 | ||
153 | static struct platform_driver syscon_driver = { | 165 | static struct platform_driver syscon_driver = { |
154 | .driver = { | 166 | .driver = { |
@@ -157,7 +169,7 @@ static struct platform_driver syscon_driver = { | |||
157 | .of_match_table = of_syscon_match, | 169 | .of_match_table = of_syscon_match, |
158 | }, | 170 | }, |
159 | .probe = syscon_probe, | 171 | .probe = syscon_probe, |
160 | .remove = syscon_remove, | 172 | .id_table = syscon_ids, |
161 | }; | 173 | }; |
162 | 174 | ||
163 | static int __init syscon_init(void) | 175 | static int __init syscon_init(void) |
diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index ecc092c7f745..4cb92bb2aea2 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c | |||
@@ -350,7 +350,8 @@ static int tc3589x_probe(struct i2c_client *i2c, | |||
350 | | I2C_FUNC_SMBUS_I2C_BLOCK)) | 350 | | I2C_FUNC_SMBUS_I2C_BLOCK)) |
351 | return -EIO; | 351 | return -EIO; |
352 | 352 | ||
353 | tc3589x = kzalloc(sizeof(struct tc3589x), GFP_KERNEL); | 353 | tc3589x = devm_kzalloc(&i2c->dev, sizeof(struct tc3589x), |
354 | GFP_KERNEL); | ||
354 | if (!tc3589x) | 355 | if (!tc3589x) |
355 | return -ENOMEM; | 356 | return -ENOMEM; |
356 | 357 | ||
@@ -366,33 +367,27 @@ static int tc3589x_probe(struct i2c_client *i2c, | |||
366 | 367 | ||
367 | ret = tc3589x_chip_init(tc3589x); | 368 | ret = tc3589x_chip_init(tc3589x); |
368 | if (ret) | 369 | if (ret) |
369 | goto out_free; | 370 | return ret; |
370 | 371 | ||
371 | ret = tc3589x_irq_init(tc3589x, np); | 372 | ret = tc3589x_irq_init(tc3589x, np); |
372 | if (ret) | 373 | if (ret) |
373 | goto out_free; | 374 | return ret; |
374 | 375 | ||
375 | ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq, | 376 | ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq, |
376 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | 377 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
377 | "tc3589x", tc3589x); | 378 | "tc3589x", tc3589x); |
378 | if (ret) { | 379 | if (ret) { |
379 | dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret); | 380 | dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret); |
380 | goto out_free; | 381 | return ret; |
381 | } | 382 | } |
382 | 383 | ||
383 | ret = tc3589x_device_init(tc3589x); | 384 | ret = tc3589x_device_init(tc3589x); |
384 | if (ret) { | 385 | if (ret) { |
385 | dev_err(tc3589x->dev, "failed to add child devices\n"); | 386 | dev_err(tc3589x->dev, "failed to add child devices\n"); |
386 | goto out_freeirq; | 387 | return ret; |
387 | } | 388 | } |
388 | 389 | ||
389 | return 0; | 390 | return 0; |
390 | |||
391 | out_freeirq: | ||
392 | free_irq(tc3589x->i2c->irq, tc3589x); | ||
393 | out_free: | ||
394 | kfree(tc3589x); | ||
395 | return ret; | ||
396 | } | 391 | } |
397 | 392 | ||
398 | static int tc3589x_remove(struct i2c_client *client) | 393 | static int tc3589x_remove(struct i2c_client *client) |
@@ -401,10 +396,6 @@ static int tc3589x_remove(struct i2c_client *client) | |||
401 | 396 | ||
402 | mfd_remove_devices(tc3589x->dev); | 397 | mfd_remove_devices(tc3589x->dev); |
403 | 398 | ||
404 | free_irq(tc3589x->i2c->irq, tc3589x); | ||
405 | |||
406 | kfree(tc3589x); | ||
407 | |||
408 | return 0; | 399 | return 0; |
409 | } | 400 | } |
410 | 401 | ||
diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index 98edb5be85c6..fbd6ee67b5a5 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c | |||
@@ -56,12 +56,23 @@ | |||
56 | #define TPS65090_INT2_MASK_OVERLOAD_FET6 6 | 56 | #define TPS65090_INT2_MASK_OVERLOAD_FET6 6 |
57 | #define TPS65090_INT2_MASK_OVERLOAD_FET7 7 | 57 | #define TPS65090_INT2_MASK_OVERLOAD_FET7 7 |
58 | 58 | ||
59 | static struct resource charger_resources[] = { | ||
60 | { | ||
61 | .start = TPS65090_IRQ_VAC_STATUS_CHANGE, | ||
62 | .end = TPS65090_IRQ_VAC_STATUS_CHANGE, | ||
63 | .flags = IORESOURCE_IRQ, | ||
64 | } | ||
65 | }; | ||
66 | |||
59 | static struct mfd_cell tps65090s[] = { | 67 | static struct mfd_cell tps65090s[] = { |
60 | { | 68 | { |
61 | .name = "tps65090-pmic", | 69 | .name = "tps65090-pmic", |
62 | }, | 70 | }, |
63 | { | 71 | { |
64 | .name = "tps65090-charger", | 72 | .name = "tps65090-charger", |
73 | .num_resources = ARRAY_SIZE(charger_resources), | ||
74 | .resources = &charger_resources[0], | ||
75 | .of_compatible = "ti,tps65090-charger", | ||
65 | }, | 76 | }, |
66 | }; | 77 | }; |
67 | 78 | ||
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 942b666a2a07..42bd3ea5df3c 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c | |||
@@ -211,12 +211,14 @@ static int twl4030battery_current(int raw_volt) | |||
211 | * @reg_base - Base address of the first channel | 211 | * @reg_base - Base address of the first channel |
212 | * @Channels - 16 bit bitmap. If the bit is set, channel value is read | 212 | * @Channels - 16 bit bitmap. If the bit is set, channel value is read |
213 | * @buf - The channel values are stored here. if read fails error | 213 | * @buf - The channel values are stored here. if read fails error |
214 | * @raw - Return raw values without conversion | ||
214 | * value is stored | 215 | * value is stored |
215 | * Returns the number of successfully read channels. | 216 | * Returns the number of successfully read channels. |
216 | */ | 217 | */ |
217 | static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, | 218 | static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, |
218 | u8 reg_base, unsigned | 219 | u8 reg_base, unsigned |
219 | long channels, int *buf) | 220 | long channels, int *buf, |
221 | bool raw) | ||
220 | { | 222 | { |
221 | int count = 0, count_req = 0, i; | 223 | int count = 0, count_req = 0, i; |
222 | u8 reg; | 224 | u8 reg; |
@@ -230,6 +232,10 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, | |||
230 | count_req++; | 232 | count_req++; |
231 | continue; | 233 | continue; |
232 | } | 234 | } |
235 | if (raw) { | ||
236 | count++; | ||
237 | continue; | ||
238 | } | ||
233 | switch (i) { | 239 | switch (i) { |
234 | case 10: | 240 | case 10: |
235 | buf[i] = twl4030battery_current(buf[i]); | 241 | buf[i] = twl4030battery_current(buf[i]); |
@@ -371,7 +377,7 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc) | |||
371 | method = &twl4030_conversion_methods[r->method]; | 377 | method = &twl4030_conversion_methods[r->method]; |
372 | /* Read results */ | 378 | /* Read results */ |
373 | len = twl4030_madc_read_channels(madc, method->rbase, | 379 | len = twl4030_madc_read_channels(madc, method->rbase, |
374 | r->channels, r->rbuf); | 380 | r->channels, r->rbuf, r->raw); |
375 | /* Return results to caller */ | 381 | /* Return results to caller */ |
376 | if (r->func_cb != NULL) { | 382 | if (r->func_cb != NULL) { |
377 | r->func_cb(len, r->channels, r->rbuf); | 383 | r->func_cb(len, r->channels, r->rbuf); |
@@ -397,7 +403,7 @@ err_i2c: | |||
397 | method = &twl4030_conversion_methods[r->method]; | 403 | method = &twl4030_conversion_methods[r->method]; |
398 | /* Read results */ | 404 | /* Read results */ |
399 | len = twl4030_madc_read_channels(madc, method->rbase, | 405 | len = twl4030_madc_read_channels(madc, method->rbase, |
400 | r->channels, r->rbuf); | 406 | r->channels, r->rbuf, r->raw); |
401 | /* Return results to caller */ | 407 | /* Return results to caller */ |
402 | if (r->func_cb != NULL) { | 408 | if (r->func_cb != NULL) { |
403 | r->func_cb(len, r->channels, r->rbuf); | 409 | r->func_cb(len, r->channels, r->rbuf); |
@@ -585,7 +591,7 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req) | |||
585 | goto out; | 591 | goto out; |
586 | } | 592 | } |
587 | ret = twl4030_madc_read_channels(twl4030_madc, method->rbase, | 593 | ret = twl4030_madc_read_channels(twl4030_madc, method->rbase, |
588 | req->channels, req->rbuf); | 594 | req->channels, req->rbuf, req->raw); |
589 | twl4030_madc->requests[req->method].active = 0; | 595 | twl4030_madc->requests[req->method].active = 0; |
590 | 596 | ||
591 | out: | 597 | out: |
diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index f361bf38a0aa..492ee2cd3400 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c | |||
@@ -554,7 +554,7 @@ static int twl6040_probe(struct i2c_client *client, | |||
554 | 554 | ||
555 | twl6040->supplies[0].supply = "vio"; | 555 | twl6040->supplies[0].supply = "vio"; |
556 | twl6040->supplies[1].supply = "v2v1"; | 556 | twl6040->supplies[1].supply = "v2v1"; |
557 | ret = regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES, | 557 | ret = devm_regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES, |
558 | twl6040->supplies); | 558 | twl6040->supplies); |
559 | if (ret != 0) { | 559 | if (ret != 0) { |
560 | dev_err(&client->dev, "Failed to get supplies: %d\n", ret); | 560 | dev_err(&client->dev, "Failed to get supplies: %d\n", ret); |
@@ -564,7 +564,7 @@ static int twl6040_probe(struct i2c_client *client, | |||
564 | ret = regulator_bulk_enable(TWL6040_NUM_SUPPLIES, twl6040->supplies); | 564 | ret = regulator_bulk_enable(TWL6040_NUM_SUPPLIES, twl6040->supplies); |
565 | if (ret != 0) { | 565 | if (ret != 0) { |
566 | dev_err(&client->dev, "Failed to enable supplies: %d\n", ret); | 566 | dev_err(&client->dev, "Failed to enable supplies: %d\n", ret); |
567 | goto power_err; | 567 | goto regulator_get_err; |
568 | } | 568 | } |
569 | 569 | ||
570 | twl6040->dev = &client->dev; | 570 | twl6040->dev = &client->dev; |
@@ -586,8 +586,8 @@ static int twl6040_probe(struct i2c_client *client, | |||
586 | twl6040->audpwron = -EINVAL; | 586 | twl6040->audpwron = -EINVAL; |
587 | 587 | ||
588 | if (gpio_is_valid(twl6040->audpwron)) { | 588 | if (gpio_is_valid(twl6040->audpwron)) { |
589 | ret = gpio_request_one(twl6040->audpwron, GPIOF_OUT_INIT_LOW, | 589 | ret = devm_gpio_request_one(&client->dev, twl6040->audpwron, |
590 | "audpwron"); | 590 | GPIOF_OUT_INIT_LOW, "audpwron"); |
591 | if (ret) | 591 | if (ret) |
592 | goto gpio_err; | 592 | goto gpio_err; |
593 | } | 593 | } |
@@ -596,14 +596,14 @@ static int twl6040_probe(struct i2c_client *client, | |||
596 | IRQF_ONESHOT, 0, &twl6040_irq_chip, | 596 | IRQF_ONESHOT, 0, &twl6040_irq_chip, |
597 | &twl6040->irq_data); | 597 | &twl6040->irq_data); |
598 | if (ret < 0) | 598 | if (ret < 0) |
599 | goto irq_init_err; | 599 | goto gpio_err; |
600 | 600 | ||
601 | twl6040->irq_ready = regmap_irq_get_virq(twl6040->irq_data, | 601 | twl6040->irq_ready = regmap_irq_get_virq(twl6040->irq_data, |
602 | TWL6040_IRQ_READY); | 602 | TWL6040_IRQ_READY); |
603 | twl6040->irq_th = regmap_irq_get_virq(twl6040->irq_data, | 603 | twl6040->irq_th = regmap_irq_get_virq(twl6040->irq_data, |
604 | TWL6040_IRQ_TH); | 604 | TWL6040_IRQ_TH); |
605 | 605 | ||
606 | ret = request_threaded_irq(twl6040->irq_ready, NULL, | 606 | ret = devm_request_threaded_irq(twl6040->dev, twl6040->irq_ready, NULL, |
607 | twl6040_readyint_handler, IRQF_ONESHOT, | 607 | twl6040_readyint_handler, IRQF_ONESHOT, |
608 | "twl6040_irq_ready", twl6040); | 608 | "twl6040_irq_ready", twl6040); |
609 | if (ret) { | 609 | if (ret) { |
@@ -611,7 +611,7 @@ static int twl6040_probe(struct i2c_client *client, | |||
611 | goto readyirq_err; | 611 | goto readyirq_err; |
612 | } | 612 | } |
613 | 613 | ||
614 | ret = request_threaded_irq(twl6040->irq_th, NULL, | 614 | ret = devm_request_threaded_irq(twl6040->dev, twl6040->irq_th, NULL, |
615 | twl6040_thint_handler, IRQF_ONESHOT, | 615 | twl6040_thint_handler, IRQF_ONESHOT, |
616 | "twl6040_irq_th", twl6040); | 616 | "twl6040_irq_th", twl6040); |
617 | if (ret) { | 617 | if (ret) { |
@@ -681,18 +681,13 @@ static int twl6040_probe(struct i2c_client *client, | |||
681 | return 0; | 681 | return 0; |
682 | 682 | ||
683 | mfd_err: | 683 | mfd_err: |
684 | free_irq(twl6040->irq_th, twl6040); | 684 | devm_free_irq(&client->dev, twl6040->irq_th, twl6040); |
685 | thirq_err: | 685 | thirq_err: |
686 | free_irq(twl6040->irq_ready, twl6040); | 686 | devm_free_irq(&client->dev, twl6040->irq_ready, twl6040); |
687 | readyirq_err: | 687 | readyirq_err: |
688 | regmap_del_irq_chip(twl6040->irq, twl6040->irq_data); | 688 | regmap_del_irq_chip(twl6040->irq, twl6040->irq_data); |
689 | irq_init_err: | ||
690 | if (gpio_is_valid(twl6040->audpwron)) | ||
691 | gpio_free(twl6040->audpwron); | ||
692 | gpio_err: | 689 | gpio_err: |
693 | regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies); | 690 | regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies); |
694 | power_err: | ||
695 | regulator_bulk_free(TWL6040_NUM_SUPPLIES, twl6040->supplies); | ||
696 | regulator_get_err: | 691 | regulator_get_err: |
697 | i2c_set_clientdata(client, NULL); | 692 | i2c_set_clientdata(client, NULL); |
698 | err: | 693 | err: |
@@ -706,18 +701,14 @@ static int twl6040_remove(struct i2c_client *client) | |||
706 | if (twl6040->power_count) | 701 | if (twl6040->power_count) |
707 | twl6040_power(twl6040, 0); | 702 | twl6040_power(twl6040, 0); |
708 | 703 | ||
709 | if (gpio_is_valid(twl6040->audpwron)) | 704 | devm_free_irq(&client->dev, twl6040->irq_ready, twl6040); |
710 | gpio_free(twl6040->audpwron); | 705 | devm_free_irq(&client->dev, twl6040->irq_th, twl6040); |
711 | |||
712 | free_irq(twl6040->irq_ready, twl6040); | ||
713 | free_irq(twl6040->irq_th, twl6040); | ||
714 | regmap_del_irq_chip(twl6040->irq, twl6040->irq_data); | 706 | regmap_del_irq_chip(twl6040->irq, twl6040->irq_data); |
715 | 707 | ||
716 | mfd_remove_devices(&client->dev); | 708 | mfd_remove_devices(&client->dev); |
717 | i2c_set_clientdata(client, NULL); | 709 | i2c_set_clientdata(client, NULL); |
718 | 710 | ||
719 | regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies); | 711 | regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies); |
720 | regulator_bulk_free(TWL6040_NUM_SUPPLIES, twl6040->supplies); | ||
721 | 712 | ||
722 | return 0; | 713 | return 0; |
723 | } | 714 | } |
diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c index daf69527ed83..e9031fa9d53d 100644 --- a/drivers/mfd/ucb1400_core.c +++ b/drivers/mfd/ucb1400_core.c | |||
@@ -75,6 +75,11 @@ static int ucb1400_core_probe(struct device *dev) | |||
75 | 75 | ||
76 | /* GPIO */ | 76 | /* GPIO */ |
77 | ucb_gpio.ac97 = ac97; | 77 | ucb_gpio.ac97 = ac97; |
78 | if (pdata) { | ||
79 | ucb_gpio.gpio_setup = pdata->gpio_setup; | ||
80 | ucb_gpio.gpio_teardown = pdata->gpio_teardown; | ||
81 | ucb_gpio.gpio_offset = pdata->gpio_offset; | ||
82 | } | ||
78 | ucb->ucb1400_gpio = platform_device_alloc("ucb1400_gpio", -1); | 83 | ucb->ucb1400_gpio = platform_device_alloc("ucb1400_gpio", -1); |
79 | if (!ucb->ucb1400_gpio) { | 84 | if (!ucb->ucb1400_gpio) { |
80 | err = -ENOMEM; | 85 | err = -ENOMEM; |
diff --git a/drivers/mfd/vexpress-config.c b/drivers/mfd/vexpress-config.c index 3c1723aa6225..84ce6b9daa3d 100644 --- a/drivers/mfd/vexpress-config.c +++ b/drivers/mfd/vexpress-config.c | |||
@@ -184,13 +184,14 @@ static int vexpress_config_schedule(struct vexpress_config_trans *trans) | |||
184 | 184 | ||
185 | spin_lock_irqsave(&bridge->transactions_lock, flags); | 185 | spin_lock_irqsave(&bridge->transactions_lock, flags); |
186 | 186 | ||
187 | vexpress_config_dump_trans("Executing", trans); | 187 | if (list_empty(&bridge->transactions)) { |
188 | 188 | vexpress_config_dump_trans("Executing", trans); | |
189 | if (list_empty(&bridge->transactions)) | ||
190 | status = bridge->info->func_exec(trans->func->func, | 189 | status = bridge->info->func_exec(trans->func->func, |
191 | trans->offset, trans->write, trans->data); | 190 | trans->offset, trans->write, trans->data); |
192 | else | 191 | } else { |
192 | vexpress_config_dump_trans("Queuing", trans); | ||
193 | status = VEXPRESS_CONFIG_STATUS_WAIT; | 193 | status = VEXPRESS_CONFIG_STATUS_WAIT; |
194 | } | ||
194 | 195 | ||
195 | switch (status) { | 196 | switch (status) { |
196 | case VEXPRESS_CONFIG_STATUS_DONE: | 197 | case VEXPRESS_CONFIG_STATUS_DONE: |
@@ -212,25 +213,31 @@ void vexpress_config_complete(struct vexpress_config_bridge *bridge, | |||
212 | { | 213 | { |
213 | struct vexpress_config_trans *trans; | 214 | struct vexpress_config_trans *trans; |
214 | unsigned long flags; | 215 | unsigned long flags; |
216 | const char *message = "Completed"; | ||
215 | 217 | ||
216 | spin_lock_irqsave(&bridge->transactions_lock, flags); | 218 | spin_lock_irqsave(&bridge->transactions_lock, flags); |
217 | 219 | ||
218 | trans = list_first_entry(&bridge->transactions, | 220 | trans = list_first_entry(&bridge->transactions, |
219 | struct vexpress_config_trans, list); | 221 | struct vexpress_config_trans, list); |
220 | vexpress_config_dump_trans("Completed", trans); | ||
221 | |||
222 | trans->status = status; | 222 | trans->status = status; |
223 | list_del(&trans->list); | ||
224 | 223 | ||
225 | if (!list_empty(&bridge->transactions)) { | 224 | do { |
226 | vexpress_config_dump_trans("Pending", trans); | 225 | vexpress_config_dump_trans(message, trans); |
226 | list_del(&trans->list); | ||
227 | complete(&trans->completion); | ||
227 | 228 | ||
228 | bridge->info->func_exec(trans->func->func, trans->offset, | 229 | if (list_empty(&bridge->transactions)) |
229 | trans->write, trans->data); | 230 | break; |
230 | } | 231 | |
231 | spin_unlock_irqrestore(&bridge->transactions_lock, flags); | 232 | trans = list_first_entry(&bridge->transactions, |
233 | struct vexpress_config_trans, list); | ||
234 | vexpress_config_dump_trans("Executing pending", trans); | ||
235 | trans->status = bridge->info->func_exec(trans->func->func, | ||
236 | trans->offset, trans->write, trans->data); | ||
237 | message = "Finished pending"; | ||
238 | } while (trans->status == VEXPRESS_CONFIG_STATUS_DONE); | ||
232 | 239 | ||
233 | complete(&trans->completion); | 240 | spin_unlock_irqrestore(&bridge->transactions_lock, flags); |
234 | } | 241 | } |
235 | EXPORT_SYMBOL(vexpress_config_complete); | 242 | EXPORT_SYMBOL(vexpress_config_complete); |
236 | 243 | ||
diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c index bf75e967a1f3..96a020b1dcd1 100644 --- a/drivers/mfd/vexpress-sysreg.c +++ b/drivers/mfd/vexpress-sysreg.c | |||
@@ -490,12 +490,12 @@ static int vexpress_sysreg_probe(struct platform_device *pdev) | |||
490 | return err; | 490 | return err; |
491 | } | 491 | } |
492 | 492 | ||
493 | vexpress_sysreg_dev = &pdev->dev; | ||
494 | |||
493 | platform_device_register_data(vexpress_sysreg_dev, "leds-gpio", | 495 | platform_device_register_data(vexpress_sysreg_dev, "leds-gpio", |
494 | PLATFORM_DEVID_AUTO, &vexpress_sysreg_leds_pdata, | 496 | PLATFORM_DEVID_AUTO, &vexpress_sysreg_leds_pdata, |
495 | sizeof(vexpress_sysreg_leds_pdata)); | 497 | sizeof(vexpress_sysreg_leds_pdata)); |
496 | 498 | ||
497 | vexpress_sysreg_dev = &pdev->dev; | ||
498 | |||
499 | device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id); | 499 | device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id); |
500 | 500 | ||
501 | return 0; | 501 | return 0; |
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index f70c4956ff9d..155c4a1a6a99 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c | |||
@@ -10,6 +10,7 @@ | |||
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/device.h> | ||
13 | #include <linux/module.h> | 14 | #include <linux/module.h> |
14 | 15 | ||
15 | #include <linux/mfd/arizona/core.h> | 16 | #include <linux/mfd/arizona/core.h> |
@@ -57,31 +58,54 @@ static const struct reg_default wm5102_reva_patch[] = { | |||
57 | }; | 58 | }; |
58 | 59 | ||
59 | static const struct reg_default wm5102_revb_patch[] = { | 60 | static const struct reg_default wm5102_revb_patch[] = { |
61 | { 0x19, 0x0001 }, | ||
60 | { 0x80, 0x0003 }, | 62 | { 0x80, 0x0003 }, |
61 | { 0x081, 0xE022 }, | 63 | { 0x081, 0xE022 }, |
62 | { 0x410, 0x4080 }, | 64 | { 0x410, 0x6080 }, |
63 | { 0x418, 0x4080 }, | 65 | { 0x418, 0xa080 }, |
64 | { 0x420, 0x4080 }, | 66 | { 0x420, 0xa080 }, |
65 | { 0x428, 0xC000 }, | 67 | { 0x428, 0xe000 }, |
68 | { 0x443, 0xDC1A }, | ||
66 | { 0x4B0, 0x0066 }, | 69 | { 0x4B0, 0x0066 }, |
67 | { 0x458, 0x000b }, | 70 | { 0x458, 0x000b }, |
68 | { 0x212, 0x0000 }, | 71 | { 0x212, 0x0000 }, |
72 | { 0x171, 0x0000 }, | ||
73 | { 0x35E, 0x000C }, | ||
74 | { 0x2D4, 0x0000 }, | ||
69 | { 0x80, 0x0000 }, | 75 | { 0x80, 0x0000 }, |
70 | }; | 76 | }; |
71 | 77 | ||
72 | /* We use a function so we can use ARRAY_SIZE() */ | 78 | /* We use a function so we can use ARRAY_SIZE() */ |
73 | int wm5102_patch(struct arizona *arizona) | 79 | int wm5102_patch(struct arizona *arizona) |
74 | { | 80 | { |
81 | const struct reg_default *wm5102_patch; | ||
82 | int ret = 0; | ||
83 | int i, patch_size; | ||
84 | |||
75 | switch (arizona->rev) { | 85 | switch (arizona->rev) { |
76 | case 0: | 86 | case 0: |
77 | return regmap_register_patch(arizona->regmap, | 87 | wm5102_patch = wm5102_reva_patch; |
78 | wm5102_reva_patch, | 88 | patch_size = ARRAY_SIZE(wm5102_reva_patch); |
79 | ARRAY_SIZE(wm5102_reva_patch)); | ||
80 | default: | 89 | default: |
81 | return regmap_register_patch(arizona->regmap, | 90 | wm5102_patch = wm5102_revb_patch; |
82 | wm5102_revb_patch, | 91 | patch_size = ARRAY_SIZE(wm5102_revb_patch); |
83 | ARRAY_SIZE(wm5102_revb_patch)); | 92 | } |
93 | |||
94 | regcache_cache_bypass(arizona->regmap, true); | ||
95 | |||
96 | for (i = 0; i < patch_size; i++) { | ||
97 | ret = regmap_write(arizona->regmap, wm5102_patch[i].reg, | ||
98 | wm5102_patch[i].def); | ||
99 | if (ret != 0) { | ||
100 | dev_err(arizona->dev, "Failed to write %x = %x: %d\n", | ||
101 | wm5102_patch[i].reg, wm5102_patch[i].def, ret); | ||
102 | goto out; | ||
103 | } | ||
84 | } | 104 | } |
105 | |||
106 | out: | ||
107 | regcache_cache_bypass(arizona->regmap, false); | ||
108 | return ret; | ||
85 | } | 109 | } |
86 | 110 | ||
87 | static const struct regmap_irq wm5102_aod_irqs[ARIZONA_NUM_IRQ] = { | 111 | static const struct regmap_irq wm5102_aod_irqs[ARIZONA_NUM_IRQ] = { |
@@ -282,7 +306,7 @@ static const struct reg_default wm5102_reg_default[] = { | |||
282 | { 0x00000155, 0x0000 }, /* R341 - Rate Estimator 4 */ | 306 | { 0x00000155, 0x0000 }, /* R341 - Rate Estimator 4 */ |
283 | { 0x00000156, 0x0000 }, /* R342 - Rate Estimator 5 */ | 307 | { 0x00000156, 0x0000 }, /* R342 - Rate Estimator 5 */ |
284 | { 0x00000161, 0x0000 }, /* R353 - Dynamic Frequency Scaling 1 */ | 308 | { 0x00000161, 0x0000 }, /* R353 - Dynamic Frequency Scaling 1 */ |
285 | { 0x00000171, 0x0002 }, /* R369 - FLL1 Control 1 */ | 309 | { 0x00000171, 0x0000 }, /* R369 - FLL1 Control 1 */ |
286 | { 0x00000172, 0x0008 }, /* R370 - FLL1 Control 2 */ | 310 | { 0x00000172, 0x0008 }, /* R370 - FLL1 Control 2 */ |
287 | { 0x00000173, 0x0018 }, /* R371 - FLL1 Control 3 */ | 311 | { 0x00000173, 0x0018 }, /* R371 - FLL1 Control 3 */ |
288 | { 0x00000174, 0x007D }, /* R372 - FLL1 Control 4 */ | 312 | { 0x00000174, 0x007D }, /* R372 - FLL1 Control 4 */ |
@@ -366,7 +390,7 @@ static const struct reg_default wm5102_reg_default[] = { | |||
366 | { 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */ | 390 | { 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */ |
367 | { 0x00000408, 0x0000 }, /* R1032 - Output Rate 1 */ | 391 | { 0x00000408, 0x0000 }, /* R1032 - Output Rate 1 */ |
368 | { 0x00000409, 0x0022 }, /* R1033 - Output Volume Ramp */ | 392 | { 0x00000409, 0x0022 }, /* R1033 - Output Volume Ramp */ |
369 | { 0x00000410, 0x4080 }, /* R1040 - Output Path Config 1L */ | 393 | { 0x00000410, 0x6080 }, /* R1040 - Output Path Config 1L */ |
370 | { 0x00000411, 0x0180 }, /* R1041 - DAC Digital Volume 1L */ | 394 | { 0x00000411, 0x0180 }, /* R1041 - DAC Digital Volume 1L */ |
371 | { 0x00000412, 0x0081 }, /* R1042 - DAC Volume Limit 1L */ | 395 | { 0x00000412, 0x0081 }, /* R1042 - DAC Volume Limit 1L */ |
372 | { 0x00000413, 0x0001 }, /* R1043 - Noise Gate Select 1L */ | 396 | { 0x00000413, 0x0001 }, /* R1043 - Noise Gate Select 1L */ |
@@ -374,7 +398,7 @@ static const struct reg_default wm5102_reg_default[] = { | |||
374 | { 0x00000415, 0x0180 }, /* R1045 - DAC Digital Volume 1R */ | 398 | { 0x00000415, 0x0180 }, /* R1045 - DAC Digital Volume 1R */ |
375 | { 0x00000416, 0x0081 }, /* R1046 - DAC Volume Limit 1R */ | 399 | { 0x00000416, 0x0081 }, /* R1046 - DAC Volume Limit 1R */ |
376 | { 0x00000417, 0x0002 }, /* R1047 - Noise Gate Select 1R */ | 400 | { 0x00000417, 0x0002 }, /* R1047 - Noise Gate Select 1R */ |
377 | { 0x00000418, 0x4080 }, /* R1048 - Output Path Config 2L */ | 401 | { 0x00000418, 0xA080 }, /* R1048 - Output Path Config 2L */ |
378 | { 0x00000419, 0x0180 }, /* R1049 - DAC Digital Volume 2L */ | 402 | { 0x00000419, 0x0180 }, /* R1049 - DAC Digital Volume 2L */ |
379 | { 0x0000041A, 0x0081 }, /* R1050 - DAC Volume Limit 2L */ | 403 | { 0x0000041A, 0x0081 }, /* R1050 - DAC Volume Limit 2L */ |
380 | { 0x0000041B, 0x0004 }, /* R1051 - Noise Gate Select 2L */ | 404 | { 0x0000041B, 0x0004 }, /* R1051 - Noise Gate Select 2L */ |
@@ -382,11 +406,11 @@ static const struct reg_default wm5102_reg_default[] = { | |||
382 | { 0x0000041D, 0x0180 }, /* R1053 - DAC Digital Volume 2R */ | 406 | { 0x0000041D, 0x0180 }, /* R1053 - DAC Digital Volume 2R */ |
383 | { 0x0000041E, 0x0081 }, /* R1054 - DAC Volume Limit 2R */ | 407 | { 0x0000041E, 0x0081 }, /* R1054 - DAC Volume Limit 2R */ |
384 | { 0x0000041F, 0x0008 }, /* R1055 - Noise Gate Select 2R */ | 408 | { 0x0000041F, 0x0008 }, /* R1055 - Noise Gate Select 2R */ |
385 | { 0x00000420, 0x4080 }, /* R1056 - Output Path Config 3L */ | 409 | { 0x00000420, 0xA080 }, /* R1056 - Output Path Config 3L */ |
386 | { 0x00000421, 0x0180 }, /* R1057 - DAC Digital Volume 3L */ | 410 | { 0x00000421, 0x0180 }, /* R1057 - DAC Digital Volume 3L */ |
387 | { 0x00000422, 0x0081 }, /* R1058 - DAC Volume Limit 3L */ | 411 | { 0x00000422, 0x0081 }, /* R1058 - DAC Volume Limit 3L */ |
388 | { 0x00000423, 0x0010 }, /* R1059 - Noise Gate Select 3L */ | 412 | { 0x00000423, 0x0010 }, /* R1059 - Noise Gate Select 3L */ |
389 | { 0x00000428, 0xC000 }, /* R1064 - Output Path Config 4L */ | 413 | { 0x00000428, 0xE000 }, /* R1064 - Output Path Config 4L */ |
390 | { 0x00000429, 0x0180 }, /* R1065 - DAC Digital Volume 4L */ | 414 | { 0x00000429, 0x0180 }, /* R1065 - DAC Digital Volume 4L */ |
391 | { 0x0000042A, 0x0081 }, /* R1066 - Out Volume 4L */ | 415 | { 0x0000042A, 0x0081 }, /* R1066 - Out Volume 4L */ |
392 | { 0x0000042B, 0x0040 }, /* R1067 - Noise Gate Select 4L */ | 416 | { 0x0000042B, 0x0040 }, /* R1067 - Noise Gate Select 4L */ |
@@ -401,7 +425,7 @@ static const struct reg_default wm5102_reg_default[] = { | |||
401 | { 0x00000436, 0x0081 }, /* R1078 - DAC Volume Limit 5R */ | 425 | { 0x00000436, 0x0081 }, /* R1078 - DAC Volume Limit 5R */ |
402 | { 0x00000437, 0x0200 }, /* R1079 - Noise Gate Select 5R */ | 426 | { 0x00000437, 0x0200 }, /* R1079 - Noise Gate Select 5R */ |
403 | { 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */ | 427 | { 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */ |
404 | { 0x00000458, 0x0001 }, /* R1112 - Noise Gate Control */ | 428 | { 0x00000458, 0x000B }, /* R1112 - Noise Gate Control */ |
405 | { 0x00000490, 0x0069 }, /* R1168 - PDM SPK1 CTRL 1 */ | 429 | { 0x00000490, 0x0069 }, /* R1168 - PDM SPK1 CTRL 1 */ |
406 | { 0x00000491, 0x0000 }, /* R1169 - PDM SPK1 CTRL 2 */ | 430 | { 0x00000491, 0x0000 }, /* R1169 - PDM SPK1 CTRL 2 */ |
407 | { 0x00000500, 0x000C }, /* R1280 - AIF1 BCLK Ctrl */ | 431 | { 0x00000500, 0x000C }, /* R1280 - AIF1 BCLK Ctrl */ |
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c index 4e70e157a909..e7ed14f661d8 100644 --- a/drivers/mfd/wm831x-spi.c +++ b/drivers/mfd/wm831x-spi.c | |||
@@ -37,7 +37,7 @@ static int wm831x_spi_probe(struct spi_device *spi) | |||
37 | spi->bits_per_word = 16; | 37 | spi->bits_per_word = 16; |
38 | spi->mode = SPI_MODE_0; | 38 | spi->mode = SPI_MODE_0; |
39 | 39 | ||
40 | dev_set_drvdata(&spi->dev, wm831x); | 40 | spi_set_drvdata(spi, wm831x); |
41 | wm831x->dev = &spi->dev; | 41 | wm831x->dev = &spi->dev; |
42 | 42 | ||
43 | wm831x->regmap = devm_regmap_init_spi(spi, &wm831x_regmap_config); | 43 | wm831x->regmap = devm_regmap_init_spi(spi, &wm831x_regmap_config); |
@@ -53,7 +53,7 @@ static int wm831x_spi_probe(struct spi_device *spi) | |||
53 | 53 | ||
54 | static int wm831x_spi_remove(struct spi_device *spi) | 54 | static int wm831x_spi_remove(struct spi_device *spi) |
55 | { | 55 | { |
56 | struct wm831x *wm831x = dev_get_drvdata(&spi->dev); | 56 | struct wm831x *wm831x = spi_get_drvdata(spi); |
57 | 57 | ||
58 | wm831x_device_exit(wm831x); | 58 | wm831x_device_exit(wm831x); |
59 | 59 | ||
@@ -69,7 +69,7 @@ static int wm831x_spi_suspend(struct device *dev) | |||
69 | 69 | ||
70 | static void wm831x_spi_shutdown(struct spi_device *spi) | 70 | static void wm831x_spi_shutdown(struct spi_device *spi) |
71 | { | 71 | { |
72 | struct wm831x *wm831x = dev_get_drvdata(&spi->dev); | 72 | struct wm831x *wm831x = spi_get_drvdata(spi); |
73 | 73 | ||
74 | wm831x_device_shutdown(wm831x); | 74 | wm831x_device_shutdown(wm831x); |
75 | } | 75 | } |
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 803e93fae56a..00e4fe2f3c75 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c | |||
@@ -19,6 +19,9 @@ | |||
19 | #include <linux/err.h> | 19 | #include <linux/err.h> |
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/mfd/core.h> | 21 | #include <linux/mfd/core.h> |
22 | #include <linux/of.h> | ||
23 | #include <linux/of_device.h> | ||
24 | #include <linux/of_gpio.h> | ||
22 | #include <linux/pm_runtime.h> | 25 | #include <linux/pm_runtime.h> |
23 | #include <linux/regmap.h> | 26 | #include <linux/regmap.h> |
24 | #include <linux/regulator/consumer.h> | 27 | #include <linux/regulator/consumer.h> |
@@ -191,7 +194,7 @@ static const char *wm8958_main_supplies[] = { | |||
191 | "SPKVDD2", | 194 | "SPKVDD2", |
192 | }; | 195 | }; |
193 | 196 | ||
194 | #ifdef CONFIG_PM | 197 | #ifdef CONFIG_PM_RUNTIME |
195 | static int wm8994_suspend(struct device *dev) | 198 | static int wm8994_suspend(struct device *dev) |
196 | { | 199 | { |
197 | struct wm8994 *wm8994 = dev_get_drvdata(dev); | 200 | struct wm8994 *wm8994 = dev_get_drvdata(dev); |
@@ -396,6 +399,60 @@ static const struct reg_default wm1811_reva_patch[] = { | |||
396 | { 0x102, 0x0 }, | 399 | { 0x102, 0x0 }, |
397 | }; | 400 | }; |
398 | 401 | ||
402 | #ifdef CONFIG_OF | ||
403 | static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) | ||
404 | { | ||
405 | struct device_node *np = wm8994->dev->of_node; | ||
406 | struct wm8994_pdata *pdata = &wm8994->pdata; | ||
407 | int i; | ||
408 | |||
409 | if (!np) | ||
410 | return 0; | ||
411 | |||
412 | if (of_property_read_u32_array(np, "wlf,gpio-cfg", pdata->gpio_defaults, | ||
413 | ARRAY_SIZE(pdata->gpio_defaults)) >= 0) { | ||
414 | for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { | ||
415 | if (wm8994->pdata.gpio_defaults[i] == 0) | ||
416 | pdata->gpio_defaults[i] | ||
417 | = WM8994_CONFIGURE_GPIO; | ||
418 | } | ||
419 | } | ||
420 | |||
421 | of_property_read_u32_array(np, "wlf,micbias-cfg", pdata->micbias, | ||
422 | ARRAY_SIZE(pdata->micbias)); | ||
423 | |||
424 | pdata->lineout1_diff = true; | ||
425 | pdata->lineout2_diff = true; | ||
426 | if (of_find_property(np, "wlf,lineout1-se", NULL)) | ||
427 | pdata->lineout1_diff = false; | ||
428 | if (of_find_property(np, "wlf,lineout2-se", NULL)) | ||
429 | pdata->lineout2_diff = false; | ||
430 | |||
431 | if (of_find_property(np, "wlf,lineout1-feedback", NULL)) | ||
432 | pdata->lineout1fb = true; | ||
433 | if (of_find_property(np, "wlf,lineout2-feedback", NULL)) | ||
434 | pdata->lineout2fb = true; | ||
435 | |||
436 | if (of_find_property(np, "wlf,ldoena-always-driven", NULL)) | ||
437 | pdata->lineout2fb = true; | ||
438 | |||
439 | pdata->ldo[0].enable = of_get_named_gpio(np, "wlf,ldo1ena", 0); | ||
440 | if (pdata->ldo[0].enable < 0) | ||
441 | pdata->ldo[0].enable = 0; | ||
442 | |||
443 | pdata->ldo[1].enable = of_get_named_gpio(np, "wlf,ldo2ena", 0); | ||
444 | if (pdata->ldo[1].enable < 0) | ||
445 | pdata->ldo[1].enable = 0; | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | #else | ||
450 | static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) | ||
451 | { | ||
452 | return 0; | ||
453 | } | ||
454 | #endif | ||
455 | |||
399 | /* | 456 | /* |
400 | * Instantiate the generic non-control parts of the device. | 457 | * Instantiate the generic non-control parts of the device. |
401 | */ | 458 | */ |
@@ -405,7 +462,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) | |||
405 | struct regmap_config *regmap_config; | 462 | struct regmap_config *regmap_config; |
406 | const struct reg_default *regmap_patch = NULL; | 463 | const struct reg_default *regmap_patch = NULL; |
407 | const char *devname; | 464 | const char *devname; |
408 | int ret, i, patch_regs; | 465 | int ret, i, patch_regs = 0; |
409 | int pulls = 0; | 466 | int pulls = 0; |
410 | 467 | ||
411 | if (dev_get_platdata(wm8994->dev)) { | 468 | if (dev_get_platdata(wm8994->dev)) { |
@@ -414,6 +471,10 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) | |||
414 | } | 471 | } |
415 | pdata = &wm8994->pdata; | 472 | pdata = &wm8994->pdata; |
416 | 473 | ||
474 | ret = wm8994_set_pdata_from_of(wm8994); | ||
475 | if (ret != 0) | ||
476 | return ret; | ||
477 | |||
417 | dev_set_drvdata(wm8994->dev, wm8994); | 478 | dev_set_drvdata(wm8994->dev, wm8994); |
418 | 479 | ||
419 | /* Add the on-chip regulators first for bootstrapping */ | 480 | /* Add the on-chip regulators first for bootstrapping */ |
@@ -673,9 +734,9 @@ static void wm8994_device_exit(struct wm8994 *wm8994) | |||
673 | } | 734 | } |
674 | 735 | ||
675 | static const struct of_device_id wm8994_of_match[] = { | 736 | static const struct of_device_id wm8994_of_match[] = { |
676 | { .compatible = "wlf,wm1811", }, | 737 | { .compatible = "wlf,wm1811", .data = (void *)WM1811 }, |
677 | { .compatible = "wlf,wm8994", }, | 738 | { .compatible = "wlf,wm8994", .data = (void *)WM8994 }, |
678 | { .compatible = "wlf,wm8958", }, | 739 | { .compatible = "wlf,wm8958", .data = (void *)WM8958 }, |
679 | { } | 740 | { } |
680 | }; | 741 | }; |
681 | MODULE_DEVICE_TABLE(of, wm8994_of_match); | 742 | MODULE_DEVICE_TABLE(of, wm8994_of_match); |
@@ -683,6 +744,7 @@ MODULE_DEVICE_TABLE(of, wm8994_of_match); | |||
683 | static int wm8994_i2c_probe(struct i2c_client *i2c, | 744 | static int wm8994_i2c_probe(struct i2c_client *i2c, |
684 | const struct i2c_device_id *id) | 745 | const struct i2c_device_id *id) |
685 | { | 746 | { |
747 | const struct of_device_id *of_id; | ||
686 | struct wm8994 *wm8994; | 748 | struct wm8994 *wm8994; |
687 | int ret; | 749 | int ret; |
688 | 750 | ||
@@ -693,7 +755,14 @@ static int wm8994_i2c_probe(struct i2c_client *i2c, | |||
693 | i2c_set_clientdata(i2c, wm8994); | 755 | i2c_set_clientdata(i2c, wm8994); |
694 | wm8994->dev = &i2c->dev; | 756 | wm8994->dev = &i2c->dev; |
695 | wm8994->irq = i2c->irq; | 757 | wm8994->irq = i2c->irq; |
696 | wm8994->type = id->driver_data; | 758 | |
759 | if (i2c->dev.of_node) { | ||
760 | of_id = of_match_device(wm8994_of_match, &i2c->dev); | ||
761 | if (of_id) | ||
762 | wm8994->type = (int)of_id->data; | ||
763 | } else { | ||
764 | wm8994->type = id->driver_data; | ||
765 | } | ||
697 | 766 | ||
698 | wm8994->regmap = devm_regmap_init_i2c(i2c, &wm8994_base_regmap_config); | 767 | wm8994->regmap = devm_regmap_init_i2c(i2c, &wm8994_base_regmap_config); |
699 | if (IS_ERR(wm8994->regmap)) { | 768 | if (IS_ERR(wm8994->regmap)) { |
@@ -724,15 +793,16 @@ static const struct i2c_device_id wm8994_i2c_id[] = { | |||
724 | }; | 793 | }; |
725 | MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); | 794 | MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); |
726 | 795 | ||
727 | static UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume, | 796 | static const struct dev_pm_ops wm8994_pm_ops = { |
728 | NULL); | 797 | SET_RUNTIME_PM_OPS(wm8994_suspend, wm8994_resume, NULL) |
798 | }; | ||
729 | 799 | ||
730 | static struct i2c_driver wm8994_i2c_driver = { | 800 | static struct i2c_driver wm8994_i2c_driver = { |
731 | .driver = { | 801 | .driver = { |
732 | .name = "wm8994", | 802 | .name = "wm8994", |
733 | .owner = THIS_MODULE, | 803 | .owner = THIS_MODULE, |
734 | .pm = &wm8994_pm_ops, | 804 | .pm = &wm8994_pm_ops, |
735 | .of_match_table = wm8994_of_match, | 805 | .of_match_table = of_match_ptr(wm8994_of_match), |
736 | }, | 806 | }, |
737 | .probe = wm8994_i2c_probe, | 807 | .probe = wm8994_i2c_probe, |
738 | .remove = wm8994_i2c_remove, | 808 | .remove = wm8994_i2c_remove, |