diff options
Diffstat (limited to 'drivers/mfd')
34 files changed, 3308 insertions, 1173 deletions
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 07933f3f7e4c..20895e7a99c9 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c | |||
@@ -158,6 +158,43 @@ static struct mfd_cell onkey_devs[] = { | |||
158 | }, | 158 | }, |
159 | }; | 159 | }; |
160 | 160 | ||
161 | static struct resource codec_resources[] = { | ||
162 | { | ||
163 | /* Headset microphone insertion or removal */ | ||
164 | .name = "micin", | ||
165 | .start = PM8607_IRQ_MICIN, | ||
166 | .end = PM8607_IRQ_MICIN, | ||
167 | .flags = IORESOURCE_IRQ, | ||
168 | }, { | ||
169 | /* Hook-switch press or release */ | ||
170 | .name = "hook", | ||
171 | .start = PM8607_IRQ_HOOK, | ||
172 | .end = PM8607_IRQ_HOOK, | ||
173 | .flags = IORESOURCE_IRQ, | ||
174 | }, { | ||
175 | /* Headset insertion or removal */ | ||
176 | .name = "headset", | ||
177 | .start = PM8607_IRQ_HEADSET, | ||
178 | .end = PM8607_IRQ_HEADSET, | ||
179 | .flags = IORESOURCE_IRQ, | ||
180 | }, { | ||
181 | /* Audio short */ | ||
182 | .name = "audio-short", | ||
183 | .start = PM8607_IRQ_AUDIO_SHORT, | ||
184 | .end = PM8607_IRQ_AUDIO_SHORT, | ||
185 | .flags = IORESOURCE_IRQ, | ||
186 | }, | ||
187 | }; | ||
188 | |||
189 | static struct mfd_cell codec_devs[] = { | ||
190 | { | ||
191 | .name = "88pm860x-codec", | ||
192 | .num_resources = ARRAY_SIZE(codec_resources), | ||
193 | .resources = &codec_resources[0], | ||
194 | .id = -1, | ||
195 | }, | ||
196 | }; | ||
197 | |||
161 | static struct resource regulator_resources[] = { | 198 | static struct resource regulator_resources[] = { |
162 | PM8607_REG_RESOURCE(BUCK1, BUCK1), | 199 | PM8607_REG_RESOURCE(BUCK1, BUCK1), |
163 | PM8607_REG_RESOURCE(BUCK2, BUCK2), | 200 | PM8607_REG_RESOURCE(BUCK2, BUCK2), |
@@ -608,10 +645,13 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, | |||
608 | dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret); | 645 | dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret); |
609 | goto out; | 646 | goto out; |
610 | } | 647 | } |
611 | if ((ret & PM8607_VERSION_MASK) == PM8607_VERSION) | 648 | switch (ret & PM8607_VERSION_MASK) { |
649 | case 0x40: | ||
650 | case 0x50: | ||
612 | dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n", | 651 | dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n", |
613 | ret); | 652 | ret); |
614 | else { | 653 | break; |
654 | default: | ||
615 | dev_err(chip->dev, "Failed to detect Marvell 88PM8607. " | 655 | dev_err(chip->dev, "Failed to detect Marvell 88PM8607. " |
616 | "Chip ID: %02x\n", ret); | 656 | "Chip ID: %02x\n", ret); |
617 | goto out; | 657 | goto out; |
@@ -687,6 +727,13 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, | |||
687 | goto out_dev; | 727 | goto out_dev; |
688 | } | 728 | } |
689 | 729 | ||
730 | ret = mfd_add_devices(chip->dev, 0, &codec_devs[0], | ||
731 | ARRAY_SIZE(codec_devs), | ||
732 | &codec_resources[0], 0); | ||
733 | if (ret < 0) { | ||
734 | dev_err(chip->dev, "Failed to add codec subdev\n"); | ||
735 | goto out_dev; | ||
736 | } | ||
690 | return; | 737 | return; |
691 | out_dev: | 738 | out_dev: |
692 | mfd_remove_devices(chip->dev); | 739 | mfd_remove_devices(chip->dev); |
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index db51ea1c6082..3a1493b8b5e5 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -75,7 +75,7 @@ config MFD_DAVINCI_VOICECODEC | |||
75 | 75 | ||
76 | config MFD_DM355EVM_MSP | 76 | config MFD_DM355EVM_MSP |
77 | bool "DaVinci DM355 EVM microcontroller" | 77 | bool "DaVinci DM355 EVM microcontroller" |
78 | depends on I2C && MACH_DAVINCI_DM355_EVM | 78 | depends on I2C=y && MACH_DAVINCI_DM355_EVM |
79 | help | 79 | help |
80 | This driver supports the MSP430 microcontroller used on these | 80 | This driver supports the MSP430 microcontroller used on these |
81 | boards. MSP430 firmware manages resets and power sequencing, | 81 | boards. MSP430 firmware manages resets and power sequencing, |
@@ -294,14 +294,15 @@ config MFD_MAX8925 | |||
294 | to use the functionality of the device. | 294 | to use the functionality of the device. |
295 | 295 | ||
296 | config MFD_MAX8998 | 296 | config MFD_MAX8998 |
297 | bool "Maxim Semiconductor MAX8998 PMIC Support" | 297 | bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" |
298 | depends on I2C=y | 298 | depends on I2C=y && GENERIC_HARDIRQS |
299 | select MFD_CORE | 299 | select MFD_CORE |
300 | help | 300 | help |
301 | Say yes here to support for Maxim Semiconductor MAX8998. This is | 301 | Say yes here to support for Maxim Semiconductor MAX8998 and |
302 | a Power Management IC. This driver provies common support for | 302 | National Semiconductor LP3974. This is a Power Management IC. |
303 | accessing the device, additional drivers must be enabled in order | 303 | This driver provies common support for accessing the device, |
304 | to use the functionality of the device. | 304 | additional drivers must be enabled in order to use the functionality |
305 | of the device. | ||
305 | 306 | ||
306 | config MFD_WM8400 | 307 | config MFD_WM8400 |
307 | tristate "Support Wolfson Microelectronics WM8400" | 308 | tristate "Support Wolfson Microelectronics WM8400" |
@@ -314,14 +315,30 @@ config MFD_WM8400 | |||
314 | the functionality of the device. | 315 | the functionality of the device. |
315 | 316 | ||
316 | config MFD_WM831X | 317 | config MFD_WM831X |
317 | bool "Support Wolfson Microelectronics WM831x/2x PMICs" | 318 | bool |
319 | depends on GENERIC_HARDIRQS | ||
320 | |||
321 | config MFD_WM831X_I2C | ||
322 | bool "Support Wolfson Microelectronics WM831x/2x PMICs with I2C" | ||
318 | select MFD_CORE | 323 | select MFD_CORE |
324 | select MFD_WM831X | ||
319 | depends on I2C=y && GENERIC_HARDIRQS | 325 | depends on I2C=y && GENERIC_HARDIRQS |
320 | help | 326 | help |
321 | Support for the Wolfson Microelecronics WM831x and WM832x PMICs. | 327 | Support for the Wolfson Microelecronics WM831x and WM832x PMICs |
322 | This driver provides common support for accessing the device, | 328 | when controlled using I2C. This driver provides common support |
323 | additional drivers must be enabled in order to use the | 329 | for accessing the device, additional drivers must be enabled in |
324 | functionality of the device. | 330 | order to use the functionality of the device. |
331 | |||
332 | config MFD_WM831X_SPI | ||
333 | bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI" | ||
334 | select MFD_CORE | ||
335 | select MFD_WM831X | ||
336 | depends on SPI_MASTER && GENERIC_HARDIRQS | ||
337 | help | ||
338 | Support for the Wolfson Microelecronics WM831x and WM832x PMICs | ||
339 | when controlled using SPI. This driver provides common support | ||
340 | for accessing the device, additional drivers must be enabled in | ||
341 | order to use the functionality of the device. | ||
325 | 342 | ||
326 | config MFD_WM8350 | 343 | config MFD_WM8350 |
327 | bool | 344 | bool |
@@ -408,11 +425,16 @@ config MFD_PCF50633 | |||
408 | so that function-specific drivers can bind to them. | 425 | so that function-specific drivers can bind to them. |
409 | 426 | ||
410 | config MFD_MC13783 | 427 | config MFD_MC13783 |
411 | tristate "Support Freescale MC13783" | 428 | tristate |
429 | |||
430 | config MFD_MC13XXX | ||
431 | tristate "Support Freescale MC13783 and MC13892" | ||
412 | depends on SPI_MASTER | 432 | depends on SPI_MASTER |
413 | select MFD_CORE | 433 | select MFD_CORE |
434 | select MFD_MC13783 | ||
414 | help | 435 | help |
415 | Support for the Freescale (Atlas) MC13783 PMIC and audio CODEC. | 436 | Support for the Freescale (Atlas) PMIC and audio CODECs |
437 | MC13783 and MC13892. | ||
416 | This driver provides common support for accessing the device, | 438 | This driver provides common support for accessing the device, |
417 | additional drivers must be enabled in order to use the | 439 | additional drivers must be enabled in order to use the |
418 | functionality of the device. | 440 | functionality of the device. |
@@ -433,7 +455,7 @@ config PCF50633_GPIO | |||
433 | 455 | ||
434 | config ABX500_CORE | 456 | config ABX500_CORE |
435 | bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" | 457 | bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" |
436 | default y if ARCH_U300 | 458 | default y if ARCH_U300 || ARCH_U8500 |
437 | help | 459 | help |
438 | Say yes here if you have the ABX500 Mixed Signal IC family | 460 | Say yes here if you have the ABX500 Mixed Signal IC family |
439 | chips. This core driver expose register access functions. | 461 | chips. This core driver expose register access functions. |
@@ -444,6 +466,7 @@ config ABX500_CORE | |||
444 | config AB3100_CORE | 466 | config AB3100_CORE |
445 | bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" | 467 | bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" |
446 | depends on I2C=y && ABX500_CORE | 468 | depends on I2C=y && ABX500_CORE |
469 | select MFD_CORE | ||
447 | default y if ARCH_U300 | 470 | default y if ARCH_U300 |
448 | help | 471 | help |
449 | Select this to enable the AB3100 Mixed Signal IC core | 472 | Select this to enable the AB3100 Mixed Signal IC core |
@@ -473,14 +496,33 @@ config EZX_PCAP | |||
473 | 496 | ||
474 | config AB8500_CORE | 497 | config AB8500_CORE |
475 | bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" | 498 | bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" |
476 | depends on SPI=y && GENERIC_HARDIRQS | 499 | depends on GENERIC_HARDIRQS && ABX500_CORE && SPI_MASTER && ARCH_U8500 |
477 | select MFD_CORE | 500 | select MFD_CORE |
478 | help | 501 | help |
479 | Select this option to enable access to AB8500 power management | 502 | Select this option to enable access to AB8500 power management |
480 | chip. This connects to U8500 on the SSP/SPI bus and exports | 503 | chip. This connects to U8500 either on the SSP/SPI bus |
481 | read/write functions for the devices to get access to this chip. | 504 | or the I2C bus via PRCMU. It also adds the irq_chip |
505 | parts for handling the Mixed Signal chip events. | ||
482 | This chip embeds various other multimedia funtionalities as well. | 506 | This chip embeds various other multimedia funtionalities as well. |
483 | 507 | ||
508 | config AB8500_I2C_CORE | ||
509 | bool "AB8500 register access via PRCMU I2C" | ||
510 | depends on AB8500_CORE && UX500_SOC_DB8500 | ||
511 | default y | ||
512 | help | ||
513 | This enables register access to the AB8500 chip via PRCMU I2C. | ||
514 | The AB8500 chip can be accessed via SPI or I2C. On DB8500 hardware | ||
515 | the I2C bus is connected to the Power Reset | ||
516 | and Mangagement Unit, PRCMU. | ||
517 | |||
518 | config AB8500_DEBUG | ||
519 | bool "Enable debug info via debugfs" | ||
520 | depends on AB8500_CORE && DEBUG_FS | ||
521 | default y if DEBUG_FS | ||
522 | help | ||
523 | Select this option if you want debug information using the debug | ||
524 | filesystem, debugfs. | ||
525 | |||
484 | config AB3550_CORE | 526 | config AB3550_CORE |
485 | bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions" | 527 | bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions" |
486 | select MFD_CORE | 528 | select MFD_CORE |
@@ -542,8 +584,8 @@ config MFD_JZ4740_ADC | |||
542 | This driver is necessary for jz4740-battery and jz4740-hwmon driver. | 584 | This driver is necessary for jz4740-battery and jz4740-hwmon driver. |
543 | 585 | ||
544 | config MFD_TPS6586X | 586 | config MFD_TPS6586X |
545 | tristate "TPS6586x Power Management chips" | 587 | bool "TPS6586x Power Management chips" |
546 | depends on I2C && GPIOLIB | 588 | depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS |
547 | select MFD_CORE | 589 | select MFD_CORE |
548 | help | 590 | help |
549 | If you say yes here you get support for the TPS6586X series of | 591 | If you say yes here you get support for the TPS6586X series of |
@@ -555,6 +597,15 @@ config MFD_TPS6586X | |||
555 | This driver can also be built as a module. If so, the module | 597 | This driver can also be built as a module. If so, the module |
556 | will be called tps6586x. | 598 | will be called tps6586x. |
557 | 599 | ||
600 | config MFD_VX855 | ||
601 | tristate "Support for VIA VX855/VX875 integrated south bridge" | ||
602 | depends on PCI | ||
603 | select MFD_CORE | ||
604 | help | ||
605 | Say yes here to enable support for various functions of the | ||
606 | VIA VX855/VX875 south bridge. You will need to enable the vx855_spi | ||
607 | and/or vx855_gpio drivers for this to do anything useful. | ||
608 | |||
558 | endif # MFD_SUPPORT | 609 | endif # MFD_SUPPORT |
559 | 610 | ||
560 | menu "Multimedia Capabilities Port drivers" | 611 | menu "Multimedia Capabilities Port drivers" |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index feaeeaeeddb7..f54b3659abbb 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -24,6 +24,8 @@ obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o | |||
24 | obj-$(CONFIG_MFD_WM8400) += wm8400-core.o | 24 | obj-$(CONFIG_MFD_WM8400) += wm8400-core.o |
25 | wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o | 25 | wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o |
26 | obj-$(CONFIG_MFD_WM831X) += wm831x.o | 26 | obj-$(CONFIG_MFD_WM831X) += wm831x.o |
27 | obj-$(CONFIG_MFD_WM831X_I2C) += wm831x-i2c.o | ||
28 | obj-$(CONFIG_MFD_WM831X_SPI) += wm831x-spi.o | ||
27 | wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o | 29 | wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o |
28 | wm8350-objs += wm8350-irq.o | 30 | wm8350-objs += wm8350-irq.o |
29 | obj-$(CONFIG_MFD_WM8350) += wm8350.o | 31 | obj-$(CONFIG_MFD_WM8350) += wm8350.o |
@@ -39,7 +41,7 @@ obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o | |||
39 | obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o | 41 | obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o |
40 | obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o | 42 | obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o |
41 | 43 | ||
42 | obj-$(CONFIG_MFD_MC13783) += mc13783-core.o | 44 | obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o |
43 | 45 | ||
44 | obj-$(CONFIG_MFD_CORE) += mfd-core.o | 46 | obj-$(CONFIG_MFD_CORE) += mfd-core.o |
45 | 47 | ||
@@ -58,7 +60,7 @@ obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o | |||
58 | obj-$(CONFIG_PMIC_DA903X) += da903x.o | 60 | obj-$(CONFIG_PMIC_DA903X) += da903x.o |
59 | max8925-objs := max8925-core.o max8925-i2c.o | 61 | max8925-objs := max8925-core.o max8925-i2c.o |
60 | obj-$(CONFIG_MFD_MAX8925) += max8925.o | 62 | obj-$(CONFIG_MFD_MAX8925) += max8925.o |
61 | obj-$(CONFIG_MFD_MAX8998) += max8998.o | 63 | obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o |
62 | 64 | ||
63 | pcf50633-objs := pcf50633-core.o pcf50633-irq.o | 65 | pcf50633-objs := pcf50633-core.o pcf50633-irq.o |
64 | obj-$(CONFIG_MFD_PCF50633) += pcf50633.o | 66 | obj-$(CONFIG_MFD_PCF50633) += pcf50633.o |
@@ -69,6 +71,8 @@ obj-$(CONFIG_AB3100_CORE) += ab3100-core.o | |||
69 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o | 71 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o |
70 | obj-$(CONFIG_AB3550_CORE) += ab3550-core.o | 72 | obj-$(CONFIG_AB3550_CORE) += ab3550-core.o |
71 | obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o | 73 | obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o |
74 | obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o | ||
75 | obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o | ||
72 | obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o | 76 | obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o |
73 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o | 77 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o |
74 | obj-$(CONFIG_LPC_SCH) += lpc_sch.o | 78 | obj-$(CONFIG_LPC_SCH) += lpc_sch.o |
@@ -76,3 +80,4 @@ obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o | |||
76 | obj-$(CONFIG_MFD_JANZ_CMODIO) += janz-cmodio.o | 80 | obj-$(CONFIG_MFD_JANZ_CMODIO) += janz-cmodio.o |
77 | obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o | 81 | obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o |
78 | obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o | 82 | obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o |
83 | obj-$(CONFIG_MFD_VX855) += vx855.o | ||
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index b048ecc56db9..4193af5f2743 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/debugfs.h> | 19 | #include <linux/debugfs.h> |
20 | #include <linux/seq_file.h> | 20 | #include <linux/seq_file.h> |
21 | #include <linux/uaccess.h> | 21 | #include <linux/uaccess.h> |
22 | #include <linux/mfd/core.h> | ||
22 | #include <linux/mfd/abx500.h> | 23 | #include <linux/mfd/abx500.h> |
23 | 24 | ||
24 | /* These are the only registers inside AB3100 used in this main file */ | 25 | /* These are the only registers inside AB3100 used in this main file */ |
@@ -146,7 +147,7 @@ static int ab3100_set_test_register_interruptible(struct ab3100 *ab3100, | |||
146 | } | 147 | } |
147 | 148 | ||
148 | static int ab3100_get_register_interruptible(struct ab3100 *ab3100, | 149 | static int ab3100_get_register_interruptible(struct ab3100 *ab3100, |
149 | u8 reg, u8 *regval) | 150 | u8 reg, u8 *regval) |
150 | { | 151 | { |
151 | int err; | 152 | int err; |
152 | 153 | ||
@@ -202,7 +203,7 @@ static int ab3100_get_register_interruptible(struct ab3100 *ab3100, | |||
202 | } | 203 | } |
203 | 204 | ||
204 | static int get_register_interruptible(struct device *dev, u8 bank, u8 reg, | 205 | static int get_register_interruptible(struct device *dev, u8 bank, u8 reg, |
205 | u8 *value) | 206 | u8 *value) |
206 | { | 207 | { |
207 | struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); | 208 | struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); |
208 | 209 | ||
@@ -666,7 +667,7 @@ struct ab3100_init_setting { | |||
666 | u8 setting; | 667 | u8 setting; |
667 | }; | 668 | }; |
668 | 669 | ||
669 | static const struct ab3100_init_setting __initconst | 670 | static const struct ab3100_init_setting __devinitconst |
670 | ab3100_init_settings[] = { | 671 | ab3100_init_settings[] = { |
671 | { | 672 | { |
672 | .abreg = AB3100_MCA, | 673 | .abreg = AB3100_MCA, |
@@ -713,7 +714,7 @@ ab3100_init_settings[] = { | |||
713 | }, | 714 | }, |
714 | }; | 715 | }; |
715 | 716 | ||
716 | static int __init ab3100_setup(struct ab3100 *ab3100) | 717 | static int __devinit ab3100_setup(struct ab3100 *ab3100) |
717 | { | 718 | { |
718 | int err = 0; | 719 | int err = 0; |
719 | int i; | 720 | int i; |
@@ -743,52 +744,64 @@ static int __init ab3100_setup(struct ab3100 *ab3100) | |||
743 | return err; | 744 | return err; |
744 | } | 745 | } |
745 | 746 | ||
746 | /* | 747 | /* The subdevices of the AB3100 */ |
747 | * Here we define all the platform devices that appear | 748 | static struct mfd_cell ab3100_devs[] = { |
748 | * as children of the AB3100. These are regular platform | 749 | { |
749 | * devices with the IORESOURCE_IO .start and .end set | 750 | .name = "ab3100-dac", |
750 | * to correspond to the internal AB3100 register range | 751 | .id = -1, |
751 | * mapping to the corresponding subdevice. | 752 | }, |
752 | */ | 753 | { |
753 | 754 | .name = "ab3100-leds", | |
754 | #define AB3100_DEVICE(devname, devid) \ | 755 | .id = -1, |
755 | static struct platform_device ab3100_##devname##_device = { \ | 756 | }, |
756 | .name = devid, \ | 757 | { |
757 | .id = -1, \ | 758 | .name = "ab3100-power", |
758 | } | 759 | .id = -1, |
759 | 760 | }, | |
760 | /* This lists all the subdevices */ | 761 | { |
761 | AB3100_DEVICE(dac, "ab3100-dac"); | 762 | .name = "ab3100-regulators", |
762 | AB3100_DEVICE(leds, "ab3100-leds"); | 763 | .id = -1, |
763 | AB3100_DEVICE(power, "ab3100-power"); | 764 | }, |
764 | AB3100_DEVICE(regulators, "ab3100-regulators"); | 765 | { |
765 | AB3100_DEVICE(sim, "ab3100-sim"); | 766 | .name = "ab3100-sim", |
766 | AB3100_DEVICE(uart, "ab3100-uart"); | 767 | .id = -1, |
767 | AB3100_DEVICE(rtc, "ab3100-rtc"); | 768 | }, |
768 | AB3100_DEVICE(charger, "ab3100-charger"); | 769 | { |
769 | AB3100_DEVICE(boost, "ab3100-boost"); | 770 | .name = "ab3100-uart", |
770 | AB3100_DEVICE(adc, "ab3100-adc"); | 771 | .id = -1, |
771 | AB3100_DEVICE(fuelgauge, "ab3100-fuelgauge"); | 772 | }, |
772 | AB3100_DEVICE(vibrator, "ab3100-vibrator"); | 773 | { |
773 | AB3100_DEVICE(otp, "ab3100-otp"); | 774 | .name = "ab3100-rtc", |
774 | AB3100_DEVICE(codec, "ab3100-codec"); | 775 | .id = -1, |
775 | 776 | }, | |
776 | static struct platform_device * | 777 | { |
777 | ab3100_platform_devs[] = { | 778 | .name = "ab3100-charger", |
778 | &ab3100_dac_device, | 779 | .id = -1, |
779 | &ab3100_leds_device, | 780 | }, |
780 | &ab3100_power_device, | 781 | { |
781 | &ab3100_regulators_device, | 782 | .name = "ab3100-boost", |
782 | &ab3100_sim_device, | 783 | .id = -1, |
783 | &ab3100_uart_device, | 784 | }, |
784 | &ab3100_rtc_device, | 785 | { |
785 | &ab3100_charger_device, | 786 | .name = "ab3100-adc", |
786 | &ab3100_boost_device, | 787 | .id = -1, |
787 | &ab3100_adc_device, | 788 | }, |
788 | &ab3100_fuelgauge_device, | 789 | { |
789 | &ab3100_vibrator_device, | 790 | .name = "ab3100-fuelgauge", |
790 | &ab3100_otp_device, | 791 | .id = -1, |
791 | &ab3100_codec_device, | 792 | }, |
793 | { | ||
794 | .name = "ab3100-vibrator", | ||
795 | .id = -1, | ||
796 | }, | ||
797 | { | ||
798 | .name = "ab3100-otp", | ||
799 | .id = -1, | ||
800 | }, | ||
801 | { | ||
802 | .name = "ab3100-codec", | ||
803 | .id = -1, | ||
804 | }, | ||
792 | }; | 805 | }; |
793 | 806 | ||
794 | struct ab_family_id { | 807 | struct ab_family_id { |
@@ -796,7 +809,7 @@ struct ab_family_id { | |||
796 | char *name; | 809 | char *name; |
797 | }; | 810 | }; |
798 | 811 | ||
799 | static const struct ab_family_id ids[] __initdata = { | 812 | static const struct ab_family_id ids[] __devinitdata = { |
800 | /* AB3100 */ | 813 | /* AB3100 */ |
801 | { | 814 | { |
802 | .id = 0xc0, | 815 | .id = 0xc0, |
@@ -850,8 +863,8 @@ static const struct ab_family_id ids[] __initdata = { | |||
850 | }, | 863 | }, |
851 | }; | 864 | }; |
852 | 865 | ||
853 | static int __init ab3100_probe(struct i2c_client *client, | 866 | static int __devinit ab3100_probe(struct i2c_client *client, |
854 | const struct i2c_device_id *id) | 867 | const struct i2c_device_id *id) |
855 | { | 868 | { |
856 | struct ab3100 *ab3100; | 869 | struct ab3100 *ab3100; |
857 | struct ab3100_platform_data *ab3100_plf_data = | 870 | struct ab3100_platform_data *ab3100_plf_data = |
@@ -935,18 +948,14 @@ static int __init ab3100_probe(struct i2c_client *client, | |||
935 | if (err) | 948 | if (err) |
936 | goto exit_no_ops; | 949 | goto exit_no_ops; |
937 | 950 | ||
938 | /* Set parent and a pointer back to the container in device data */ | 951 | /* Set up and register the platform devices. */ |
939 | for (i = 0; i < ARRAY_SIZE(ab3100_platform_devs); i++) { | 952 | for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) { |
940 | ab3100_platform_devs[i]->dev.parent = | 953 | ab3100_devs[i].platform_data = ab3100_plf_data; |
941 | &client->dev; | 954 | ab3100_devs[i].data_size = sizeof(struct ab3100_platform_data); |
942 | ab3100_platform_devs[i]->dev.platform_data = | ||
943 | ab3100_plf_data; | ||
944 | platform_set_drvdata(ab3100_platform_devs[i], ab3100); | ||
945 | } | 955 | } |
946 | 956 | ||
947 | /* Register the platform devices */ | 957 | err = mfd_add_devices(&client->dev, 0, ab3100_devs, |
948 | platform_add_devices(ab3100_platform_devs, | 958 | ARRAY_SIZE(ab3100_devs), NULL, 0); |
949 | ARRAY_SIZE(ab3100_platform_devs)); | ||
950 | 959 | ||
951 | ab3100_setup_debugfs(ab3100); | 960 | ab3100_setup_debugfs(ab3100); |
952 | 961 | ||
@@ -962,14 +971,12 @@ static int __init ab3100_probe(struct i2c_client *client, | |||
962 | return err; | 971 | return err; |
963 | } | 972 | } |
964 | 973 | ||
965 | static int __exit ab3100_remove(struct i2c_client *client) | 974 | static int __devexit ab3100_remove(struct i2c_client *client) |
966 | { | 975 | { |
967 | struct ab3100 *ab3100 = i2c_get_clientdata(client); | 976 | struct ab3100 *ab3100 = i2c_get_clientdata(client); |
968 | int i; | ||
969 | 977 | ||
970 | /* Unregister subdevices */ | 978 | /* Unregister subdevices */ |
971 | for (i = 0; i < ARRAY_SIZE(ab3100_platform_devs); i++) | 979 | mfd_remove_devices(&client->dev); |
972 | platform_device_unregister(ab3100_platform_devs[i]); | ||
973 | 980 | ||
974 | ab3100_remove_debugfs(); | 981 | ab3100_remove_debugfs(); |
975 | i2c_unregister_device(ab3100->testreg_client); | 982 | i2c_unregister_device(ab3100->testreg_client); |
@@ -996,7 +1003,7 @@ static struct i2c_driver ab3100_driver = { | |||
996 | }, | 1003 | }, |
997 | .id_table = ab3100_id, | 1004 | .id_table = ab3100_id, |
998 | .probe = ab3100_probe, | 1005 | .probe = ab3100_probe, |
999 | .remove = __exit_p(ab3100_remove), | 1006 | .remove = __devexit_p(ab3100_remove), |
1000 | }; | 1007 | }; |
1001 | 1008 | ||
1002 | static int __init ab3100_i2c_init(void) | 1009 | static int __init ab3100_i2c_init(void) |
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index b8c4b80e4c43..dbe1c93c1af3 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * License Terms: GNU General Public License v2 | 4 | * License Terms: GNU General Public License v2 |
5 | * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> | 5 | * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> |
6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> | 6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> |
7 | * Changes: Mattias Wallin <mattias.wallin@stericsson.com> | ||
7 | */ | 8 | */ |
8 | 9 | ||
9 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
@@ -15,6 +16,7 @@ | |||
15 | #include <linux/module.h> | 16 | #include <linux/module.h> |
16 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
17 | #include <linux/mfd/core.h> | 18 | #include <linux/mfd/core.h> |
19 | #include <linux/mfd/abx500.h> | ||
18 | #include <linux/mfd/ab8500.h> | 20 | #include <linux/mfd/ab8500.h> |
19 | #include <linux/regulator/ab8500.h> | 21 | #include <linux/regulator/ab8500.h> |
20 | 22 | ||
@@ -22,71 +24,71 @@ | |||
22 | * Interrupt register offsets | 24 | * Interrupt register offsets |
23 | * Bank : 0x0E | 25 | * Bank : 0x0E |
24 | */ | 26 | */ |
25 | #define AB8500_IT_SOURCE1_REG 0x0E00 | 27 | #define AB8500_IT_SOURCE1_REG 0x00 |
26 | #define AB8500_IT_SOURCE2_REG 0x0E01 | 28 | #define AB8500_IT_SOURCE2_REG 0x01 |
27 | #define AB8500_IT_SOURCE3_REG 0x0E02 | 29 | #define AB8500_IT_SOURCE3_REG 0x02 |
28 | #define AB8500_IT_SOURCE4_REG 0x0E03 | 30 | #define AB8500_IT_SOURCE4_REG 0x03 |
29 | #define AB8500_IT_SOURCE5_REG 0x0E04 | 31 | #define AB8500_IT_SOURCE5_REG 0x04 |
30 | #define AB8500_IT_SOURCE6_REG 0x0E05 | 32 | #define AB8500_IT_SOURCE6_REG 0x05 |
31 | #define AB8500_IT_SOURCE7_REG 0x0E06 | 33 | #define AB8500_IT_SOURCE7_REG 0x06 |
32 | #define AB8500_IT_SOURCE8_REG 0x0E07 | 34 | #define AB8500_IT_SOURCE8_REG 0x07 |
33 | #define AB8500_IT_SOURCE19_REG 0x0E12 | 35 | #define AB8500_IT_SOURCE19_REG 0x12 |
34 | #define AB8500_IT_SOURCE20_REG 0x0E13 | 36 | #define AB8500_IT_SOURCE20_REG 0x13 |
35 | #define AB8500_IT_SOURCE21_REG 0x0E14 | 37 | #define AB8500_IT_SOURCE21_REG 0x14 |
36 | #define AB8500_IT_SOURCE22_REG 0x0E15 | 38 | #define AB8500_IT_SOURCE22_REG 0x15 |
37 | #define AB8500_IT_SOURCE23_REG 0x0E16 | 39 | #define AB8500_IT_SOURCE23_REG 0x16 |
38 | #define AB8500_IT_SOURCE24_REG 0x0E17 | 40 | #define AB8500_IT_SOURCE24_REG 0x17 |
39 | 41 | ||
40 | /* | 42 | /* |
41 | * latch registers | 43 | * latch registers |
42 | */ | 44 | */ |
43 | #define AB8500_IT_LATCH1_REG 0x0E20 | 45 | #define AB8500_IT_LATCH1_REG 0x20 |
44 | #define AB8500_IT_LATCH2_REG 0x0E21 | 46 | #define AB8500_IT_LATCH2_REG 0x21 |
45 | #define AB8500_IT_LATCH3_REG 0x0E22 | 47 | #define AB8500_IT_LATCH3_REG 0x22 |
46 | #define AB8500_IT_LATCH4_REG 0x0E23 | 48 | #define AB8500_IT_LATCH4_REG 0x23 |
47 | #define AB8500_IT_LATCH5_REG 0x0E24 | 49 | #define AB8500_IT_LATCH5_REG 0x24 |
48 | #define AB8500_IT_LATCH6_REG 0x0E25 | 50 | #define AB8500_IT_LATCH6_REG 0x25 |
49 | #define AB8500_IT_LATCH7_REG 0x0E26 | 51 | #define AB8500_IT_LATCH7_REG 0x26 |
50 | #define AB8500_IT_LATCH8_REG 0x0E27 | 52 | #define AB8500_IT_LATCH8_REG 0x27 |
51 | #define AB8500_IT_LATCH9_REG 0x0E28 | 53 | #define AB8500_IT_LATCH9_REG 0x28 |
52 | #define AB8500_IT_LATCH10_REG 0x0E29 | 54 | #define AB8500_IT_LATCH10_REG 0x29 |
53 | #define AB8500_IT_LATCH19_REG 0x0E32 | 55 | #define AB8500_IT_LATCH19_REG 0x32 |
54 | #define AB8500_IT_LATCH20_REG 0x0E33 | 56 | #define AB8500_IT_LATCH20_REG 0x33 |
55 | #define AB8500_IT_LATCH21_REG 0x0E34 | 57 | #define AB8500_IT_LATCH21_REG 0x34 |
56 | #define AB8500_IT_LATCH22_REG 0x0E35 | 58 | #define AB8500_IT_LATCH22_REG 0x35 |
57 | #define AB8500_IT_LATCH23_REG 0x0E36 | 59 | #define AB8500_IT_LATCH23_REG 0x36 |
58 | #define AB8500_IT_LATCH24_REG 0x0E37 | 60 | #define AB8500_IT_LATCH24_REG 0x37 |
59 | 61 | ||
60 | /* | 62 | /* |
61 | * mask registers | 63 | * mask registers |
62 | */ | 64 | */ |
63 | 65 | ||
64 | #define AB8500_IT_MASK1_REG 0x0E40 | 66 | #define AB8500_IT_MASK1_REG 0x40 |
65 | #define AB8500_IT_MASK2_REG 0x0E41 | 67 | #define AB8500_IT_MASK2_REG 0x41 |
66 | #define AB8500_IT_MASK3_REG 0x0E42 | 68 | #define AB8500_IT_MASK3_REG 0x42 |
67 | #define AB8500_IT_MASK4_REG 0x0E43 | 69 | #define AB8500_IT_MASK4_REG 0x43 |
68 | #define AB8500_IT_MASK5_REG 0x0E44 | 70 | #define AB8500_IT_MASK5_REG 0x44 |
69 | #define AB8500_IT_MASK6_REG 0x0E45 | 71 | #define AB8500_IT_MASK6_REG 0x45 |
70 | #define AB8500_IT_MASK7_REG 0x0E46 | 72 | #define AB8500_IT_MASK7_REG 0x46 |
71 | #define AB8500_IT_MASK8_REG 0x0E47 | 73 | #define AB8500_IT_MASK8_REG 0x47 |
72 | #define AB8500_IT_MASK9_REG 0x0E48 | 74 | #define AB8500_IT_MASK9_REG 0x48 |
73 | #define AB8500_IT_MASK10_REG 0x0E49 | 75 | #define AB8500_IT_MASK10_REG 0x49 |
74 | #define AB8500_IT_MASK11_REG 0x0E4A | 76 | #define AB8500_IT_MASK11_REG 0x4A |
75 | #define AB8500_IT_MASK12_REG 0x0E4B | 77 | #define AB8500_IT_MASK12_REG 0x4B |
76 | #define AB8500_IT_MASK13_REG 0x0E4C | 78 | #define AB8500_IT_MASK13_REG 0x4C |
77 | #define AB8500_IT_MASK14_REG 0x0E4D | 79 | #define AB8500_IT_MASK14_REG 0x4D |
78 | #define AB8500_IT_MASK15_REG 0x0E4E | 80 | #define AB8500_IT_MASK15_REG 0x4E |
79 | #define AB8500_IT_MASK16_REG 0x0E4F | 81 | #define AB8500_IT_MASK16_REG 0x4F |
80 | #define AB8500_IT_MASK17_REG 0x0E50 | 82 | #define AB8500_IT_MASK17_REG 0x50 |
81 | #define AB8500_IT_MASK18_REG 0x0E51 | 83 | #define AB8500_IT_MASK18_REG 0x51 |
82 | #define AB8500_IT_MASK19_REG 0x0E52 | 84 | #define AB8500_IT_MASK19_REG 0x52 |
83 | #define AB8500_IT_MASK20_REG 0x0E53 | 85 | #define AB8500_IT_MASK20_REG 0x53 |
84 | #define AB8500_IT_MASK21_REG 0x0E54 | 86 | #define AB8500_IT_MASK21_REG 0x54 |
85 | #define AB8500_IT_MASK22_REG 0x0E55 | 87 | #define AB8500_IT_MASK22_REG 0x55 |
86 | #define AB8500_IT_MASK23_REG 0x0E56 | 88 | #define AB8500_IT_MASK23_REG 0x56 |
87 | #define AB8500_IT_MASK24_REG 0x0E57 | 89 | #define AB8500_IT_MASK24_REG 0x57 |
88 | 90 | ||
89 | #define AB8500_REV_REG 0x1080 | 91 | #define AB8500_REV_REG 0x80 |
90 | 92 | ||
91 | /* | 93 | /* |
92 | * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt | 94 | * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt |
@@ -99,96 +101,132 @@ static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { | |||
99 | 0, 1, 2, 3, 4, 6, 7, 8, 9, 18, 19, 20, 21, | 101 | 0, 1, 2, 3, 4, 6, 7, 8, 9, 18, 19, 20, 21, |
100 | }; | 102 | }; |
101 | 103 | ||
102 | static int __ab8500_write(struct ab8500 *ab8500, u16 addr, u8 data) | 104 | static int ab8500_get_chip_id(struct device *dev) |
105 | { | ||
106 | struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); | ||
107 | return (int)ab8500->chip_id; | ||
108 | } | ||
109 | |||
110 | static int set_register_interruptible(struct ab8500 *ab8500, u8 bank, | ||
111 | u8 reg, u8 data) | ||
103 | { | 112 | { |
104 | int ret; | 113 | int ret; |
114 | /* | ||
115 | * Put the u8 bank and u8 register together into a an u16. | ||
116 | * The bank on higher 8 bits and register in lower 8 bits. | ||
117 | * */ | ||
118 | u16 addr = ((u16)bank) << 8 | reg; | ||
105 | 119 | ||
106 | dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data); | 120 | dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data); |
107 | 121 | ||
122 | ret = mutex_lock_interruptible(&ab8500->lock); | ||
123 | if (ret) | ||
124 | return ret; | ||
125 | |||
108 | ret = ab8500->write(ab8500, addr, data); | 126 | ret = ab8500->write(ab8500, addr, data); |
109 | if (ret < 0) | 127 | if (ret < 0) |
110 | dev_err(ab8500->dev, "failed to write reg %#x: %d\n", | 128 | dev_err(ab8500->dev, "failed to write reg %#x: %d\n", |
111 | addr, ret); | 129 | addr, ret); |
130 | mutex_unlock(&ab8500->lock); | ||
112 | 131 | ||
113 | return ret; | 132 | return ret; |
114 | } | 133 | } |
115 | 134 | ||
116 | /** | 135 | static int ab8500_set_register(struct device *dev, u8 bank, |
117 | * ab8500_write() - write an AB8500 register | 136 | u8 reg, u8 value) |
118 | * @ab8500: device to write to | ||
119 | * @addr: address of the register | ||
120 | * @data: value to write | ||
121 | */ | ||
122 | int ab8500_write(struct ab8500 *ab8500, u16 addr, u8 data) | ||
123 | { | 137 | { |
124 | int ret; | 138 | struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); |
125 | 139 | ||
126 | mutex_lock(&ab8500->lock); | 140 | return set_register_interruptible(ab8500, bank, reg, value); |
127 | ret = __ab8500_write(ab8500, addr, data); | ||
128 | mutex_unlock(&ab8500->lock); | ||
129 | |||
130 | return ret; | ||
131 | } | 141 | } |
132 | EXPORT_SYMBOL_GPL(ab8500_write); | ||
133 | 142 | ||
134 | static int __ab8500_read(struct ab8500 *ab8500, u16 addr) | 143 | static int get_register_interruptible(struct ab8500 *ab8500, u8 bank, |
144 | u8 reg, u8 *value) | ||
135 | { | 145 | { |
136 | int ret; | 146 | int ret; |
147 | /* put the u8 bank and u8 reg together into a an u16. | ||
148 | * bank on higher 8 bits and reg in lower */ | ||
149 | u16 addr = ((u16)bank) << 8 | reg; | ||
150 | |||
151 | ret = mutex_lock_interruptible(&ab8500->lock); | ||
152 | if (ret) | ||
153 | return ret; | ||
137 | 154 | ||
138 | ret = ab8500->read(ab8500, addr); | 155 | ret = ab8500->read(ab8500, addr); |
139 | if (ret < 0) | 156 | if (ret < 0) |
140 | dev_err(ab8500->dev, "failed to read reg %#x: %d\n", | 157 | dev_err(ab8500->dev, "failed to read reg %#x: %d\n", |
141 | addr, ret); | 158 | addr, ret); |
159 | else | ||
160 | *value = ret; | ||
142 | 161 | ||
162 | mutex_unlock(&ab8500->lock); | ||
143 | dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret); | 163 | dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret); |
144 | 164 | ||
145 | return ret; | 165 | return ret; |
146 | } | 166 | } |
147 | 167 | ||
148 | /** | 168 | static int ab8500_get_register(struct device *dev, u8 bank, |
149 | * ab8500_read() - read an AB8500 register | 169 | u8 reg, u8 *value) |
150 | * @ab8500: device to read from | ||
151 | * @addr: address of the register | ||
152 | */ | ||
153 | int ab8500_read(struct ab8500 *ab8500, u16 addr) | ||
154 | { | 170 | { |
155 | int ret; | 171 | struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); |
156 | |||
157 | mutex_lock(&ab8500->lock); | ||
158 | ret = __ab8500_read(ab8500, addr); | ||
159 | mutex_unlock(&ab8500->lock); | ||
160 | 172 | ||
161 | return ret; | 173 | return get_register_interruptible(ab8500, bank, reg, value); |
162 | } | 174 | } |
163 | EXPORT_SYMBOL_GPL(ab8500_read); | 175 | |
164 | 176 | static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank, | |
165 | /** | 177 | u8 reg, u8 bitmask, u8 bitvalues) |
166 | * ab8500_set_bits() - set a bitfield in an AB8500 register | ||
167 | * @ab8500: device to read from | ||
168 | * @addr: address of the register | ||
169 | * @mask: mask of the bitfield to modify | ||
170 | * @data: value to set to the bitfield | ||
171 | */ | ||
172 | int ab8500_set_bits(struct ab8500 *ab8500, u16 addr, u8 mask, u8 data) | ||
173 | { | 178 | { |
174 | int ret; | 179 | int ret; |
180 | u8 data; | ||
181 | /* put the u8 bank and u8 reg together into a an u16. | ||
182 | * bank on higher 8 bits and reg in lower */ | ||
183 | u16 addr = ((u16)bank) << 8 | reg; | ||
175 | 184 | ||
176 | mutex_lock(&ab8500->lock); | 185 | ret = mutex_lock_interruptible(&ab8500->lock); |
186 | if (ret) | ||
187 | return ret; | ||
177 | 188 | ||
178 | ret = __ab8500_read(ab8500, addr); | 189 | ret = ab8500->read(ab8500, addr); |
179 | if (ret < 0) | 190 | if (ret < 0) { |
191 | dev_err(ab8500->dev, "failed to read reg %#x: %d\n", | ||
192 | addr, ret); | ||
180 | goto out; | 193 | goto out; |
194 | } | ||
181 | 195 | ||
182 | ret &= ~mask; | 196 | data = (u8)ret; |
183 | ret |= data; | 197 | data = (~bitmask & data) | (bitmask & bitvalues); |
184 | 198 | ||
185 | ret = __ab8500_write(ab8500, addr, ret); | 199 | ret = ab8500->write(ab8500, addr, data); |
200 | if (ret < 0) | ||
201 | dev_err(ab8500->dev, "failed to write reg %#x: %d\n", | ||
202 | addr, ret); | ||
186 | 203 | ||
204 | dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, data); | ||
187 | out: | 205 | out: |
188 | mutex_unlock(&ab8500->lock); | 206 | mutex_unlock(&ab8500->lock); |
189 | return ret; | 207 | return ret; |
190 | } | 208 | } |
191 | EXPORT_SYMBOL_GPL(ab8500_set_bits); | 209 | |
210 | static int ab8500_mask_and_set_register(struct device *dev, | ||
211 | u8 bank, u8 reg, u8 bitmask, u8 bitvalues) | ||
212 | { | ||
213 | struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); | ||
214 | |||
215 | return mask_and_set_register_interruptible(ab8500, bank, reg, | ||
216 | bitmask, bitvalues); | ||
217 | |||
218 | } | ||
219 | |||
220 | static struct abx500_ops ab8500_ops = { | ||
221 | .get_chip_id = ab8500_get_chip_id, | ||
222 | .get_register = ab8500_get_register, | ||
223 | .set_register = ab8500_set_register, | ||
224 | .get_register_page = NULL, | ||
225 | .set_register_page = NULL, | ||
226 | .mask_and_set_register = ab8500_mask_and_set_register, | ||
227 | .event_registers_startup_state_get = NULL, | ||
228 | .startup_irq_enabled = NULL, | ||
229 | }; | ||
192 | 230 | ||
193 | static void ab8500_irq_lock(unsigned int irq) | 231 | static void ab8500_irq_lock(unsigned int irq) |
194 | { | 232 | { |
@@ -213,7 +251,7 @@ static void ab8500_irq_sync_unlock(unsigned int irq) | |||
213 | ab8500->oldmask[i] = new; | 251 | ab8500->oldmask[i] = new; |
214 | 252 | ||
215 | reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i]; | 253 | reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i]; |
216 | ab8500_write(ab8500, reg, new); | 254 | set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new); |
217 | } | 255 | } |
218 | 256 | ||
219 | mutex_unlock(&ab8500->irq_lock); | 257 | mutex_unlock(&ab8500->irq_lock); |
@@ -257,9 +295,11 @@ static irqreturn_t ab8500_irq(int irq, void *dev) | |||
257 | for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) { | 295 | for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) { |
258 | int regoffset = ab8500_irq_regoffset[i]; | 296 | int regoffset = ab8500_irq_regoffset[i]; |
259 | int status; | 297 | int status; |
298 | u8 value; | ||
260 | 299 | ||
261 | status = ab8500_read(ab8500, AB8500_IT_LATCH1_REG + regoffset); | 300 | status = get_register_interruptible(ab8500, AB8500_INTERRUPT, |
262 | if (status <= 0) | 301 | AB8500_IT_LATCH1_REG + regoffset, &value); |
302 | if (status < 0 || value == 0) | ||
263 | continue; | 303 | continue; |
264 | 304 | ||
265 | do { | 305 | do { |
@@ -267,8 +307,8 @@ static irqreturn_t ab8500_irq(int irq, void *dev) | |||
267 | int line = i * 8 + bit; | 307 | int line = i * 8 + bit; |
268 | 308 | ||
269 | handle_nested_irq(ab8500->irq_base + line); | 309 | handle_nested_irq(ab8500->irq_base + line); |
270 | status &= ~(1 << bit); | 310 | value &= ~(1 << bit); |
271 | } while (status); | 311 | } while (value); |
272 | } | 312 | } |
273 | 313 | ||
274 | return IRQ_HANDLED; | 314 | return IRQ_HANDLED; |
@@ -354,6 +394,11 @@ static struct resource ab8500_poweronkey_db_resources[] = { | |||
354 | }; | 394 | }; |
355 | 395 | ||
356 | static struct mfd_cell ab8500_devs[] = { | 396 | static struct mfd_cell ab8500_devs[] = { |
397 | #ifdef CONFIG_DEBUG_FS | ||
398 | { | ||
399 | .name = "ab8500-debug", | ||
400 | }, | ||
401 | #endif | ||
357 | { | 402 | { |
358 | .name = "ab8500-gpadc", | 403 | .name = "ab8500-gpadc", |
359 | .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), | 404 | .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), |
@@ -364,10 +409,21 @@ static struct mfd_cell ab8500_devs[] = { | |||
364 | .num_resources = ARRAY_SIZE(ab8500_rtc_resources), | 409 | .num_resources = ARRAY_SIZE(ab8500_rtc_resources), |
365 | .resources = ab8500_rtc_resources, | 410 | .resources = ab8500_rtc_resources, |
366 | }, | 411 | }, |
412 | { | ||
413 | .name = "ab8500-pwm", | ||
414 | .id = 1, | ||
415 | }, | ||
416 | { | ||
417 | .name = "ab8500-pwm", | ||
418 | .id = 2, | ||
419 | }, | ||
420 | { | ||
421 | .name = "ab8500-pwm", | ||
422 | .id = 3, | ||
423 | }, | ||
367 | { .name = "ab8500-charger", }, | 424 | { .name = "ab8500-charger", }, |
368 | { .name = "ab8500-audio", }, | 425 | { .name = "ab8500-audio", }, |
369 | { .name = "ab8500-usb", }, | 426 | { .name = "ab8500-usb", }, |
370 | { .name = "ab8500-pwm", }, | ||
371 | { .name = "ab8500-regulator", }, | 427 | { .name = "ab8500-regulator", }, |
372 | { | 428 | { |
373 | .name = "ab8500-poweron-key", | 429 | .name = "ab8500-poweron-key", |
@@ -381,6 +437,7 @@ int __devinit ab8500_init(struct ab8500 *ab8500) | |||
381 | struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev); | 437 | struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev); |
382 | int ret; | 438 | int ret; |
383 | int i; | 439 | int i; |
440 | u8 value; | ||
384 | 441 | ||
385 | if (plat) | 442 | if (plat) |
386 | ab8500->irq_base = plat->irq_base; | 443 | ab8500->irq_base = plat->irq_base; |
@@ -388,7 +445,8 @@ int __devinit ab8500_init(struct ab8500 *ab8500) | |||
388 | mutex_init(&ab8500->lock); | 445 | mutex_init(&ab8500->lock); |
389 | mutex_init(&ab8500->irq_lock); | 446 | mutex_init(&ab8500->irq_lock); |
390 | 447 | ||
391 | ret = ab8500_read(ab8500, AB8500_REV_REG); | 448 | ret = get_register_interruptible(ab8500, AB8500_MISC, |
449 | AB8500_REV_REG, &value); | ||
392 | if (ret < 0) | 450 | if (ret < 0) |
393 | return ret; | 451 | return ret; |
394 | 452 | ||
@@ -397,28 +455,37 @@ int __devinit ab8500_init(struct ab8500 *ab8500) | |||
397 | * 0x10 - Cut 1.0 | 455 | * 0x10 - Cut 1.0 |
398 | * 0x11 - Cut 1.1 | 456 | * 0x11 - Cut 1.1 |
399 | */ | 457 | */ |
400 | if (ret == 0x0 || ret == 0x10 || ret == 0x11) { | 458 | if (value == 0x0 || value == 0x10 || value == 0x11) { |
401 | ab8500->revision = ret; | 459 | ab8500->revision = value; |
402 | dev_info(ab8500->dev, "detected chip, revision: %#x\n", ret); | 460 | dev_info(ab8500->dev, "detected chip, revision: %#x\n", value); |
403 | } else { | 461 | } else { |
404 | dev_err(ab8500->dev, "unknown chip, revision: %#x\n", ret); | 462 | dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value); |
405 | return -EINVAL; | 463 | return -EINVAL; |
406 | } | 464 | } |
465 | ab8500->chip_id = value; | ||
407 | 466 | ||
408 | if (plat && plat->init) | 467 | if (plat && plat->init) |
409 | plat->init(ab8500); | 468 | plat->init(ab8500); |
410 | 469 | ||
411 | /* Clear and mask all interrupts */ | 470 | /* Clear and mask all interrupts */ |
412 | for (i = 0; i < 10; i++) { | 471 | for (i = 0; i < 10; i++) { |
413 | ab8500_read(ab8500, AB8500_IT_LATCH1_REG + i); | 472 | get_register_interruptible(ab8500, AB8500_INTERRUPT, |
414 | ab8500_write(ab8500, AB8500_IT_MASK1_REG + i, 0xff); | 473 | AB8500_IT_LATCH1_REG + i, &value); |
474 | set_register_interruptible(ab8500, AB8500_INTERRUPT, | ||
475 | AB8500_IT_MASK1_REG + i, 0xff); | ||
415 | } | 476 | } |
416 | 477 | ||
417 | for (i = 18; i < 24; i++) { | 478 | for (i = 18; i < 24; i++) { |
418 | ab8500_read(ab8500, AB8500_IT_LATCH1_REG + i); | 479 | get_register_interruptible(ab8500, AB8500_INTERRUPT, |
419 | ab8500_write(ab8500, AB8500_IT_MASK1_REG + i, 0xff); | 480 | AB8500_IT_LATCH1_REG + i, &value); |
481 | set_register_interruptible(ab8500, AB8500_INTERRUPT, | ||
482 | AB8500_IT_MASK1_REG + i, 0xff); | ||
420 | } | 483 | } |
421 | 484 | ||
485 | ret = abx500_register_ops(ab8500->dev, &ab8500_ops); | ||
486 | if (ret) | ||
487 | return ret; | ||
488 | |||
422 | for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) | 489 | for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) |
423 | ab8500->mask[i] = ab8500->oldmask[i] = 0xff; | 490 | ab8500->mask[i] = ab8500->oldmask[i] = 0xff; |
424 | 491 | ||
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c new file mode 100644 index 000000000000..8d1e05a39815 --- /dev/null +++ b/drivers/mfd/ab8500-debugfs.c | |||
@@ -0,0 +1,652 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson. | ||
5 | * License Terms: GNU General Public License v2 | ||
6 | */ | ||
7 | |||
8 | #include <linux/seq_file.h> | ||
9 | #include <linux/uaccess.h> | ||
10 | #include <linux/fs.h> | ||
11 | #include <linux/debugfs.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | |||
14 | #include <linux/mfd/abx500.h> | ||
15 | #include <linux/mfd/ab8500.h> | ||
16 | |||
17 | static u32 debug_bank; | ||
18 | static u32 debug_address; | ||
19 | |||
20 | /** | ||
21 | * struct ab8500_reg_range | ||
22 | * @first: the first address of the range | ||
23 | * @last: the last address of the range | ||
24 | * @perm: access permissions for the range | ||
25 | */ | ||
26 | struct ab8500_reg_range { | ||
27 | u8 first; | ||
28 | u8 last; | ||
29 | u8 perm; | ||
30 | }; | ||
31 | |||
32 | /** | ||
33 | * struct ab8500_i2c_ranges | ||
34 | * @num_ranges: the number of ranges in the list | ||
35 | * @bankid: bank identifier | ||
36 | * @range: the list of register ranges | ||
37 | */ | ||
38 | struct ab8500_i2c_ranges { | ||
39 | u8 num_ranges; | ||
40 | u8 bankid; | ||
41 | const struct ab8500_reg_range *range; | ||
42 | }; | ||
43 | |||
44 | #define AB8500_NAME_STRING "ab8500" | ||
45 | #define AB8500_NUM_BANKS 22 | ||
46 | |||
47 | #define AB8500_REV_REG 0x80 | ||
48 | |||
49 | static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = { | ||
50 | [0x0] = { | ||
51 | .num_ranges = 0, | ||
52 | .range = 0, | ||
53 | }, | ||
54 | [AB8500_SYS_CTRL1_BLOCK] = { | ||
55 | .num_ranges = 3, | ||
56 | .range = (struct ab8500_reg_range[]) { | ||
57 | { | ||
58 | .first = 0x00, | ||
59 | .last = 0x02, | ||
60 | }, | ||
61 | { | ||
62 | .first = 0x42, | ||
63 | .last = 0x42, | ||
64 | }, | ||
65 | { | ||
66 | .first = 0x80, | ||
67 | .last = 0x81, | ||
68 | }, | ||
69 | }, | ||
70 | }, | ||
71 | [AB8500_SYS_CTRL2_BLOCK] = { | ||
72 | .num_ranges = 4, | ||
73 | .range = (struct ab8500_reg_range[]) { | ||
74 | { | ||
75 | .first = 0x00, | ||
76 | .last = 0x0D, | ||
77 | }, | ||
78 | { | ||
79 | .first = 0x0F, | ||
80 | .last = 0x17, | ||
81 | }, | ||
82 | { | ||
83 | .first = 0x30, | ||
84 | .last = 0x30, | ||
85 | }, | ||
86 | { | ||
87 | .first = 0x32, | ||
88 | .last = 0x33, | ||
89 | }, | ||
90 | }, | ||
91 | }, | ||
92 | [AB8500_REGU_CTRL1] = { | ||
93 | .num_ranges = 3, | ||
94 | .range = (struct ab8500_reg_range[]) { | ||
95 | { | ||
96 | .first = 0x00, | ||
97 | .last = 0x00, | ||
98 | }, | ||
99 | { | ||
100 | .first = 0x03, | ||
101 | .last = 0x10, | ||
102 | }, | ||
103 | { | ||
104 | .first = 0x80, | ||
105 | .last = 0x84, | ||
106 | }, | ||
107 | }, | ||
108 | }, | ||
109 | [AB8500_REGU_CTRL2] = { | ||
110 | .num_ranges = 5, | ||
111 | .range = (struct ab8500_reg_range[]) { | ||
112 | { | ||
113 | .first = 0x00, | ||
114 | .last = 0x15, | ||
115 | }, | ||
116 | { | ||
117 | .first = 0x17, | ||
118 | .last = 0x19, | ||
119 | }, | ||
120 | { | ||
121 | .first = 0x1B, | ||
122 | .last = 0x1D, | ||
123 | }, | ||
124 | { | ||
125 | .first = 0x1F, | ||
126 | .last = 0x22, | ||
127 | }, | ||
128 | { | ||
129 | .first = 0x40, | ||
130 | .last = 0x44, | ||
131 | }, | ||
132 | /* 0x80-0x8B is SIM registers and should | ||
133 | * not be accessed from here */ | ||
134 | }, | ||
135 | }, | ||
136 | [AB8500_USB] = { | ||
137 | .num_ranges = 2, | ||
138 | .range = (struct ab8500_reg_range[]) { | ||
139 | { | ||
140 | .first = 0x80, | ||
141 | .last = 0x83, | ||
142 | }, | ||
143 | { | ||
144 | .first = 0x87, | ||
145 | .last = 0x8A, | ||
146 | }, | ||
147 | }, | ||
148 | }, | ||
149 | [AB8500_TVOUT] = { | ||
150 | .num_ranges = 9, | ||
151 | .range = (struct ab8500_reg_range[]) { | ||
152 | { | ||
153 | .first = 0x00, | ||
154 | .last = 0x12, | ||
155 | }, | ||
156 | { | ||
157 | .first = 0x15, | ||
158 | .last = 0x17, | ||
159 | }, | ||
160 | { | ||
161 | .first = 0x19, | ||
162 | .last = 0x21, | ||
163 | }, | ||
164 | { | ||
165 | .first = 0x27, | ||
166 | .last = 0x2C, | ||
167 | }, | ||
168 | { | ||
169 | .first = 0x41, | ||
170 | .last = 0x41, | ||
171 | }, | ||
172 | { | ||
173 | .first = 0x45, | ||
174 | .last = 0x5B, | ||
175 | }, | ||
176 | { | ||
177 | .first = 0x5D, | ||
178 | .last = 0x5D, | ||
179 | }, | ||
180 | { | ||
181 | .first = 0x69, | ||
182 | .last = 0x69, | ||
183 | }, | ||
184 | { | ||
185 | .first = 0x80, | ||
186 | .last = 0x81, | ||
187 | }, | ||
188 | }, | ||
189 | }, | ||
190 | [AB8500_DBI] = { | ||
191 | .num_ranges = 0, | ||
192 | .range = 0, | ||
193 | }, | ||
194 | [AB8500_ECI_AV_ACC] = { | ||
195 | .num_ranges = 1, | ||
196 | .range = (struct ab8500_reg_range[]) { | ||
197 | { | ||
198 | .first = 0x80, | ||
199 | .last = 0x82, | ||
200 | }, | ||
201 | }, | ||
202 | }, | ||
203 | [0x9] = { | ||
204 | .num_ranges = 0, | ||
205 | .range = 0, | ||
206 | }, | ||
207 | [AB8500_GPADC] = { | ||
208 | .num_ranges = 1, | ||
209 | .range = (struct ab8500_reg_range[]) { | ||
210 | { | ||
211 | .first = 0x00, | ||
212 | .last = 0x08, | ||
213 | }, | ||
214 | }, | ||
215 | }, | ||
216 | [AB8500_CHARGER] = { | ||
217 | .num_ranges = 8, | ||
218 | .range = (struct ab8500_reg_range[]) { | ||
219 | { | ||
220 | .first = 0x00, | ||
221 | .last = 0x03, | ||
222 | }, | ||
223 | { | ||
224 | .first = 0x05, | ||
225 | .last = 0x05, | ||
226 | }, | ||
227 | { | ||
228 | .first = 0x40, | ||
229 | .last = 0x40, | ||
230 | }, | ||
231 | { | ||
232 | .first = 0x42, | ||
233 | .last = 0x42, | ||
234 | }, | ||
235 | { | ||
236 | .first = 0x44, | ||
237 | .last = 0x44, | ||
238 | }, | ||
239 | { | ||
240 | .first = 0x50, | ||
241 | .last = 0x55, | ||
242 | }, | ||
243 | { | ||
244 | .first = 0x80, | ||
245 | .last = 0x82, | ||
246 | }, | ||
247 | { | ||
248 | .first = 0xC0, | ||
249 | .last = 0xC2, | ||
250 | }, | ||
251 | }, | ||
252 | }, | ||
253 | [AB8500_GAS_GAUGE] = { | ||
254 | .num_ranges = 3, | ||
255 | .range = (struct ab8500_reg_range[]) { | ||
256 | { | ||
257 | .first = 0x00, | ||
258 | .last = 0x00, | ||
259 | }, | ||
260 | { | ||
261 | .first = 0x07, | ||
262 | .last = 0x0A, | ||
263 | }, | ||
264 | { | ||
265 | .first = 0x10, | ||
266 | .last = 0x14, | ||
267 | }, | ||
268 | }, | ||
269 | }, | ||
270 | [AB8500_AUDIO] = { | ||
271 | .num_ranges = 1, | ||
272 | .range = (struct ab8500_reg_range[]) { | ||
273 | { | ||
274 | .first = 0x00, | ||
275 | .last = 0x6F, | ||
276 | }, | ||
277 | }, | ||
278 | }, | ||
279 | [AB8500_INTERRUPT] = { | ||
280 | .num_ranges = 0, | ||
281 | .range = 0, | ||
282 | }, | ||
283 | [AB8500_RTC] = { | ||
284 | .num_ranges = 1, | ||
285 | .range = (struct ab8500_reg_range[]) { | ||
286 | { | ||
287 | .first = 0x00, | ||
288 | .last = 0x0F, | ||
289 | }, | ||
290 | }, | ||
291 | }, | ||
292 | [AB8500_MISC] = { | ||
293 | .num_ranges = 8, | ||
294 | .range = (struct ab8500_reg_range[]) { | ||
295 | { | ||
296 | .first = 0x00, | ||
297 | .last = 0x05, | ||
298 | }, | ||
299 | { | ||
300 | .first = 0x10, | ||
301 | .last = 0x15, | ||
302 | }, | ||
303 | { | ||
304 | .first = 0x20, | ||
305 | .last = 0x25, | ||
306 | }, | ||
307 | { | ||
308 | .first = 0x30, | ||
309 | .last = 0x35, | ||
310 | }, | ||
311 | { | ||
312 | .first = 0x40, | ||
313 | .last = 0x45, | ||
314 | }, | ||
315 | { | ||
316 | .first = 0x50, | ||
317 | .last = 0x50, | ||
318 | }, | ||
319 | { | ||
320 | .first = 0x60, | ||
321 | .last = 0x67, | ||
322 | }, | ||
323 | { | ||
324 | .first = 0x80, | ||
325 | .last = 0x80, | ||
326 | }, | ||
327 | }, | ||
328 | }, | ||
329 | [0x11] = { | ||
330 | .num_ranges = 0, | ||
331 | .range = 0, | ||
332 | }, | ||
333 | [0x12] = { | ||
334 | .num_ranges = 0, | ||
335 | .range = 0, | ||
336 | }, | ||
337 | [0x13] = { | ||
338 | .num_ranges = 0, | ||
339 | .range = 0, | ||
340 | }, | ||
341 | [0x14] = { | ||
342 | .num_ranges = 0, | ||
343 | .range = 0, | ||
344 | }, | ||
345 | [AB8500_OTP_EMUL] = { | ||
346 | .num_ranges = 1, | ||
347 | .range = (struct ab8500_reg_range[]) { | ||
348 | { | ||
349 | .first = 0x01, | ||
350 | .last = 0x0F, | ||
351 | }, | ||
352 | }, | ||
353 | }, | ||
354 | }; | ||
355 | |||
356 | static int ab8500_registers_print(struct seq_file *s, void *p) | ||
357 | { | ||
358 | struct device *dev = s->private; | ||
359 | unsigned int i; | ||
360 | u32 bank = debug_bank; | ||
361 | |||
362 | seq_printf(s, AB8500_NAME_STRING " register values:\n"); | ||
363 | |||
364 | seq_printf(s, " bank %u:\n", bank); | ||
365 | for (i = 0; i < debug_ranges[bank].num_ranges; i++) { | ||
366 | u32 reg; | ||
367 | |||
368 | for (reg = debug_ranges[bank].range[i].first; | ||
369 | reg <= debug_ranges[bank].range[i].last; | ||
370 | reg++) { | ||
371 | u8 value; | ||
372 | int err; | ||
373 | |||
374 | err = abx500_get_register_interruptible(dev, | ||
375 | (u8)bank, (u8)reg, &value); | ||
376 | if (err < 0) { | ||
377 | dev_err(dev, "ab->read fail %d\n", err); | ||
378 | return err; | ||
379 | } | ||
380 | |||
381 | err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank, | ||
382 | reg, value); | ||
383 | if (err < 0) { | ||
384 | dev_err(dev, "seq_printf overflow\n"); | ||
385 | /* Error is not returned here since | ||
386 | * the output is wanted in any case */ | ||
387 | return 0; | ||
388 | } | ||
389 | } | ||
390 | } | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int ab8500_registers_open(struct inode *inode, struct file *file) | ||
395 | { | ||
396 | return single_open(file, ab8500_registers_print, inode->i_private); | ||
397 | } | ||
398 | |||
399 | static const struct file_operations ab8500_registers_fops = { | ||
400 | .open = ab8500_registers_open, | ||
401 | .read = seq_read, | ||
402 | .llseek = seq_lseek, | ||
403 | .release = single_release, | ||
404 | .owner = THIS_MODULE, | ||
405 | }; | ||
406 | |||
407 | static int ab8500_bank_print(struct seq_file *s, void *p) | ||
408 | { | ||
409 | return seq_printf(s, "%d\n", debug_bank); | ||
410 | } | ||
411 | |||
412 | static int ab8500_bank_open(struct inode *inode, struct file *file) | ||
413 | { | ||
414 | return single_open(file, ab8500_bank_print, inode->i_private); | ||
415 | } | ||
416 | |||
417 | static ssize_t ab8500_bank_write(struct file *file, | ||
418 | const char __user *user_buf, | ||
419 | size_t count, loff_t *ppos) | ||
420 | { | ||
421 | struct device *dev = ((struct seq_file *)(file->private_data))->private; | ||
422 | char buf[32]; | ||
423 | int buf_size; | ||
424 | unsigned long user_bank; | ||
425 | int err; | ||
426 | |||
427 | /* Get userspace string and assure termination */ | ||
428 | buf_size = min(count, (sizeof(buf) - 1)); | ||
429 | if (copy_from_user(buf, user_buf, buf_size)) | ||
430 | return -EFAULT; | ||
431 | buf[buf_size] = 0; | ||
432 | |||
433 | err = strict_strtoul(buf, 0, &user_bank); | ||
434 | if (err) | ||
435 | return -EINVAL; | ||
436 | |||
437 | if (user_bank >= AB8500_NUM_BANKS) { | ||
438 | dev_err(dev, "debugfs error input > number of banks\n"); | ||
439 | return -EINVAL; | ||
440 | } | ||
441 | |||
442 | debug_bank = user_bank; | ||
443 | |||
444 | return buf_size; | ||
445 | } | ||
446 | |||
447 | static int ab8500_address_print(struct seq_file *s, void *p) | ||
448 | { | ||
449 | return seq_printf(s, "0x%02X\n", debug_address); | ||
450 | } | ||
451 | |||
452 | static int ab8500_address_open(struct inode *inode, struct file *file) | ||
453 | { | ||
454 | return single_open(file, ab8500_address_print, inode->i_private); | ||
455 | } | ||
456 | |||
457 | static ssize_t ab8500_address_write(struct file *file, | ||
458 | const char __user *user_buf, | ||
459 | size_t count, loff_t *ppos) | ||
460 | { | ||
461 | struct device *dev = ((struct seq_file *)(file->private_data))->private; | ||
462 | char buf[32]; | ||
463 | int buf_size; | ||
464 | unsigned long user_address; | ||
465 | int err; | ||
466 | |||
467 | /* Get userspace string and assure termination */ | ||
468 | buf_size = min(count, (sizeof(buf) - 1)); | ||
469 | if (copy_from_user(buf, user_buf, buf_size)) | ||
470 | return -EFAULT; | ||
471 | buf[buf_size] = 0; | ||
472 | |||
473 | err = strict_strtoul(buf, 0, &user_address); | ||
474 | if (err) | ||
475 | return -EINVAL; | ||
476 | if (user_address > 0xff) { | ||
477 | dev_err(dev, "debugfs error input > 0xff\n"); | ||
478 | return -EINVAL; | ||
479 | } | ||
480 | debug_address = user_address; | ||
481 | return buf_size; | ||
482 | } | ||
483 | |||
484 | static int ab8500_val_print(struct seq_file *s, void *p) | ||
485 | { | ||
486 | struct device *dev = s->private; | ||
487 | int ret; | ||
488 | u8 regvalue; | ||
489 | |||
490 | ret = abx500_get_register_interruptible(dev, | ||
491 | (u8)debug_bank, (u8)debug_address, ®value); | ||
492 | if (ret < 0) { | ||
493 | dev_err(dev, "abx500_get_reg fail %d, %d\n", | ||
494 | ret, __LINE__); | ||
495 | return -EINVAL; | ||
496 | } | ||
497 | seq_printf(s, "0x%02X\n", regvalue); | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int ab8500_val_open(struct inode *inode, struct file *file) | ||
503 | { | ||
504 | return single_open(file, ab8500_val_print, inode->i_private); | ||
505 | } | ||
506 | |||
507 | static ssize_t ab8500_val_write(struct file *file, | ||
508 | const char __user *user_buf, | ||
509 | size_t count, loff_t *ppos) | ||
510 | { | ||
511 | struct device *dev = ((struct seq_file *)(file->private_data))->private; | ||
512 | char buf[32]; | ||
513 | int buf_size; | ||
514 | unsigned long user_val; | ||
515 | int err; | ||
516 | |||
517 | /* Get userspace string and assure termination */ | ||
518 | buf_size = min(count, (sizeof(buf)-1)); | ||
519 | if (copy_from_user(buf, user_buf, buf_size)) | ||
520 | return -EFAULT; | ||
521 | buf[buf_size] = 0; | ||
522 | |||
523 | err = strict_strtoul(buf, 0, &user_val); | ||
524 | if (err) | ||
525 | return -EINVAL; | ||
526 | if (user_val > 0xff) { | ||
527 | dev_err(dev, "debugfs error input > 0xff\n"); | ||
528 | return -EINVAL; | ||
529 | } | ||
530 | err = abx500_set_register_interruptible(dev, | ||
531 | (u8)debug_bank, debug_address, (u8)user_val); | ||
532 | if (err < 0) { | ||
533 | printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__); | ||
534 | return -EINVAL; | ||
535 | } | ||
536 | |||
537 | return buf_size; | ||
538 | } | ||
539 | |||
540 | static const struct file_operations ab8500_bank_fops = { | ||
541 | .open = ab8500_bank_open, | ||
542 | .write = ab8500_bank_write, | ||
543 | .read = seq_read, | ||
544 | .llseek = seq_lseek, | ||
545 | .release = single_release, | ||
546 | .owner = THIS_MODULE, | ||
547 | }; | ||
548 | |||
549 | static const struct file_operations ab8500_address_fops = { | ||
550 | .open = ab8500_address_open, | ||
551 | .write = ab8500_address_write, | ||
552 | .read = seq_read, | ||
553 | .llseek = seq_lseek, | ||
554 | .release = single_release, | ||
555 | .owner = THIS_MODULE, | ||
556 | }; | ||
557 | |||
558 | static const struct file_operations ab8500_val_fops = { | ||
559 | .open = ab8500_val_open, | ||
560 | .write = ab8500_val_write, | ||
561 | .read = seq_read, | ||
562 | .llseek = seq_lseek, | ||
563 | .release = single_release, | ||
564 | .owner = THIS_MODULE, | ||
565 | }; | ||
566 | |||
567 | static struct dentry *ab8500_dir; | ||
568 | static struct dentry *ab8500_reg_file; | ||
569 | static struct dentry *ab8500_bank_file; | ||
570 | static struct dentry *ab8500_address_file; | ||
571 | static struct dentry *ab8500_val_file; | ||
572 | |||
573 | static int __devinit ab8500_debug_probe(struct platform_device *plf) | ||
574 | { | ||
575 | debug_bank = AB8500_MISC; | ||
576 | debug_address = AB8500_REV_REG & 0x00FF; | ||
577 | |||
578 | ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL); | ||
579 | if (!ab8500_dir) | ||
580 | goto exit_no_debugfs; | ||
581 | |||
582 | ab8500_reg_file = debugfs_create_file("all-bank-registers", | ||
583 | S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops); | ||
584 | if (!ab8500_reg_file) | ||
585 | goto exit_destroy_dir; | ||
586 | |||
587 | ab8500_bank_file = debugfs_create_file("register-bank", | ||
588 | (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops); | ||
589 | if (!ab8500_bank_file) | ||
590 | goto exit_destroy_reg; | ||
591 | |||
592 | ab8500_address_file = debugfs_create_file("register-address", | ||
593 | (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, | ||
594 | &ab8500_address_fops); | ||
595 | if (!ab8500_address_file) | ||
596 | goto exit_destroy_bank; | ||
597 | |||
598 | ab8500_val_file = debugfs_create_file("register-value", | ||
599 | (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops); | ||
600 | if (!ab8500_val_file) | ||
601 | goto exit_destroy_address; | ||
602 | |||
603 | return 0; | ||
604 | |||
605 | exit_destroy_address: | ||
606 | debugfs_remove(ab8500_address_file); | ||
607 | exit_destroy_bank: | ||
608 | debugfs_remove(ab8500_bank_file); | ||
609 | exit_destroy_reg: | ||
610 | debugfs_remove(ab8500_reg_file); | ||
611 | exit_destroy_dir: | ||
612 | debugfs_remove(ab8500_dir); | ||
613 | exit_no_debugfs: | ||
614 | dev_err(&plf->dev, "failed to create debugfs entries.\n"); | ||
615 | return -ENOMEM; | ||
616 | } | ||
617 | |||
618 | static int __devexit ab8500_debug_remove(struct platform_device *plf) | ||
619 | { | ||
620 | debugfs_remove(ab8500_val_file); | ||
621 | debugfs_remove(ab8500_address_file); | ||
622 | debugfs_remove(ab8500_bank_file); | ||
623 | debugfs_remove(ab8500_reg_file); | ||
624 | debugfs_remove(ab8500_dir); | ||
625 | |||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | static struct platform_driver ab8500_debug_driver = { | ||
630 | .driver = { | ||
631 | .name = "ab8500-debug", | ||
632 | .owner = THIS_MODULE, | ||
633 | }, | ||
634 | .probe = ab8500_debug_probe, | ||
635 | .remove = __devexit_p(ab8500_debug_remove) | ||
636 | }; | ||
637 | |||
638 | static int __init ab8500_debug_init(void) | ||
639 | { | ||
640 | return platform_driver_register(&ab8500_debug_driver); | ||
641 | } | ||
642 | |||
643 | static void __exit ab8500_debug_exit(void) | ||
644 | { | ||
645 | platform_driver_unregister(&ab8500_debug_driver); | ||
646 | } | ||
647 | subsys_initcall(ab8500_debug_init); | ||
648 | module_exit(ab8500_debug_exit); | ||
649 | |||
650 | MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com"); | ||
651 | MODULE_DESCRIPTION("AB8500 DEBUG"); | ||
652 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/ab8500-i2c.c b/drivers/mfd/ab8500-i2c.c new file mode 100644 index 000000000000..6820327adf4a --- /dev/null +++ b/drivers/mfd/ab8500-i2c.c | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson. | ||
4 | * License Terms: GNU General Public License v2 | ||
5 | * This file was based on drivers/mfd/ab8500-spi.c | ||
6 | */ | ||
7 | |||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/slab.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/mfd/ab8500.h> | ||
14 | |||
15 | #include <mach/prcmu.h> | ||
16 | |||
17 | static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data) | ||
18 | { | ||
19 | int ret; | ||
20 | |||
21 | ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); | ||
22 | if (ret < 0) | ||
23 | dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); | ||
24 | return ret; | ||
25 | } | ||
26 | |||
27 | static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr) | ||
28 | { | ||
29 | int ret; | ||
30 | u8 data; | ||
31 | |||
32 | ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); | ||
33 | if (ret < 0) { | ||
34 | dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); | ||
35 | return ret; | ||
36 | } | ||
37 | return (int)data; | ||
38 | } | ||
39 | |||
40 | static int __devinit ab8500_i2c_probe(struct platform_device *plf) | ||
41 | { | ||
42 | struct ab8500 *ab8500; | ||
43 | struct resource *resource; | ||
44 | int ret; | ||
45 | |||
46 | ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL); | ||
47 | if (!ab8500) | ||
48 | return -ENOMEM; | ||
49 | |||
50 | ab8500->dev = &plf->dev; | ||
51 | |||
52 | resource = platform_get_resource(plf, IORESOURCE_IRQ, 0); | ||
53 | if (!resource) { | ||
54 | kfree(ab8500); | ||
55 | return -ENODEV; | ||
56 | } | ||
57 | |||
58 | ab8500->irq = resource->start; | ||
59 | |||
60 | ab8500->read = ab8500_i2c_read; | ||
61 | ab8500->write = ab8500_i2c_write; | ||
62 | |||
63 | platform_set_drvdata(plf, ab8500); | ||
64 | |||
65 | ret = ab8500_init(ab8500); | ||
66 | if (ret) | ||
67 | kfree(ab8500); | ||
68 | |||
69 | return ret; | ||
70 | } | ||
71 | |||
72 | static int __devexit ab8500_i2c_remove(struct platform_device *plf) | ||
73 | { | ||
74 | struct ab8500 *ab8500 = platform_get_drvdata(plf); | ||
75 | |||
76 | ab8500_exit(ab8500); | ||
77 | kfree(ab8500); | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static struct platform_driver ab8500_i2c_driver = { | ||
83 | .driver = { | ||
84 | .name = "ab8500-i2c", | ||
85 | .owner = THIS_MODULE, | ||
86 | }, | ||
87 | .probe = ab8500_i2c_probe, | ||
88 | .remove = __devexit_p(ab8500_i2c_remove) | ||
89 | }; | ||
90 | |||
91 | static int __init ab8500_i2c_init(void) | ||
92 | { | ||
93 | return platform_driver_register(&ab8500_i2c_driver); | ||
94 | } | ||
95 | |||
96 | static void __exit ab8500_i2c_exit(void) | ||
97 | { | ||
98 | platform_driver_unregister(&ab8500_i2c_driver); | ||
99 | } | ||
100 | subsys_initcall(ab8500_i2c_init); | ||
101 | module_exit(ab8500_i2c_exit); | ||
102 | |||
103 | MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com"); | ||
104 | MODULE_DESCRIPTION("AB8500 Core access via PRCMU I2C"); | ||
105 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/ab8500-spi.c b/drivers/mfd/ab8500-spi.c index 01b6d584442c..b1653421edb5 100644 --- a/drivers/mfd/ab8500-spi.c +++ b/drivers/mfd/ab8500-spi.c | |||
@@ -119,7 +119,7 @@ static int __devexit ab8500_spi_remove(struct spi_device *spi) | |||
119 | 119 | ||
120 | static struct spi_driver ab8500_spi_driver = { | 120 | static struct spi_driver ab8500_spi_driver = { |
121 | .driver = { | 121 | .driver = { |
122 | .name = "ab8500", | 122 | .name = "ab8500-spi", |
123 | .owner = THIS_MODULE, | 123 | .owner = THIS_MODULE, |
124 | }, | 124 | }, |
125 | .probe = ab8500_spi_probe, | 125 | .probe = ab8500_spi_probe, |
diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index c07aece900fb..2fadbaeb1cb1 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c | |||
@@ -470,13 +470,19 @@ static int __devinit da903x_add_subdevs(struct da903x_chip *chip, | |||
470 | subdev = &pdata->subdevs[i]; | 470 | subdev = &pdata->subdevs[i]; |
471 | 471 | ||
472 | pdev = platform_device_alloc(subdev->name, subdev->id); | 472 | pdev = platform_device_alloc(subdev->name, subdev->id); |
473 | if (!pdev) { | ||
474 | ret = -ENOMEM; | ||
475 | goto failed; | ||
476 | } | ||
473 | 477 | ||
474 | pdev->dev.parent = chip->dev; | 478 | pdev->dev.parent = chip->dev; |
475 | pdev->dev.platform_data = subdev->platform_data; | 479 | pdev->dev.platform_data = subdev->platform_data; |
476 | 480 | ||
477 | ret = platform_device_add(pdev); | 481 | ret = platform_device_add(pdev); |
478 | if (ret) | 482 | if (ret) { |
483 | platform_device_put(pdev); | ||
479 | goto failed; | 484 | goto failed; |
485 | } | ||
480 | } | 486 | } |
481 | return 0; | 487 | return 0; |
482 | 488 | ||
diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 134c69aa4790..c2b698d69a93 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c | |||
@@ -384,12 +384,20 @@ static int __devinit pcap_add_subdev(struct pcap_chip *pcap, | |||
384 | struct pcap_subdev *subdev) | 384 | struct pcap_subdev *subdev) |
385 | { | 385 | { |
386 | struct platform_device *pdev; | 386 | struct platform_device *pdev; |
387 | int ret; | ||
387 | 388 | ||
388 | pdev = platform_device_alloc(subdev->name, subdev->id); | 389 | pdev = platform_device_alloc(subdev->name, subdev->id); |
390 | if (!pdev) | ||
391 | return -ENOMEM; | ||
392 | |||
389 | pdev->dev.parent = &pcap->spi->dev; | 393 | pdev->dev.parent = &pcap->spi->dev; |
390 | pdev->dev.platform_data = subdev->platform_data; | 394 | pdev->dev.platform_data = subdev->platform_data; |
391 | 395 | ||
392 | return platform_device_add(pdev); | 396 | ret = platform_device_add(pdev); |
397 | if (ret) | ||
398 | platform_device_put(pdev); | ||
399 | |||
400 | return ret; | ||
393 | } | 401 | } |
394 | 402 | ||
395 | static int __devexit ezx_pcap_remove(struct spi_device *spi) | 403 | static int __devexit ezx_pcap_remove(struct spi_device *spi) |
@@ -457,6 +465,7 @@ static int __devinit ezx_pcap_probe(struct spi_device *spi) | |||
457 | pcap->irq_base = pdata->irq_base; | 465 | pcap->irq_base = pdata->irq_base; |
458 | pcap->workqueue = create_singlethread_workqueue("pcapd"); | 466 | pcap->workqueue = create_singlethread_workqueue("pcapd"); |
459 | if (!pcap->workqueue) { | 467 | if (!pcap->workqueue) { |
468 | ret = -ENOMEM; | ||
460 | dev_err(&spi->dev, "cant create pcap thread\n"); | 469 | dev_err(&spi->dev, "cant create pcap thread\n"); |
461 | goto free_pcap; | 470 | goto free_pcap; |
462 | } | 471 | } |
diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index f04300e05fd6..7bc752272dc1 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c | |||
@@ -138,13 +138,6 @@ static int __init pasic3_probe(struct platform_device *pdev) | |||
138 | irq = r->start; | 138 | irq = r->start; |
139 | } | 139 | } |
140 | 140 | ||
141 | r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
142 | if (r) { | ||
143 | ds1wm_resources[1].flags = IORESOURCE_IRQ | (r->flags & | ||
144 | (IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE)); | ||
145 | irq = r->start; | ||
146 | } | ||
147 | |||
148 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 141 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
149 | if (!r) | 142 | if (!r) |
150 | return -ENXIO; | 143 | return -ENXIO; |
diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index 3ad492cb6c41..9dd1b33f2275 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c | |||
@@ -153,7 +153,7 @@ static inline void jz4740_adc_set_enabled(struct jz4740_adc *adc, int engine, | |||
153 | if (enabled) | 153 | if (enabled) |
154 | val |= BIT(engine); | 154 | val |= BIT(engine); |
155 | else | 155 | else |
156 | val &= BIT(engine); | 156 | val &= ~BIT(engine); |
157 | writeb(val, adc->base + JZ_REG_ADC_ENABLE); | 157 | writeb(val, adc->base + JZ_REG_ADC_ENABLE); |
158 | 158 | ||
159 | spin_unlock_irqrestore(&adc->lock, flags); | 159 | spin_unlock_irqrestore(&adc->lock, flags); |
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 428377a5a6f5..44695f5a1800 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c | |||
@@ -93,8 +93,13 @@ static struct mfd_cell rtc_devs[] = { | |||
93 | static struct resource onkey_resources[] = { | 93 | static struct resource onkey_resources[] = { |
94 | { | 94 | { |
95 | .name = "max8925-onkey", | 95 | .name = "max8925-onkey", |
96 | .start = MAX8925_IRQ_GPM_SW_3SEC, | 96 | .start = MAX8925_IRQ_GPM_SW_R, |
97 | .end = MAX8925_IRQ_GPM_SW_3SEC, | 97 | .end = MAX8925_IRQ_GPM_SW_R, |
98 | .flags = IORESOURCE_IRQ, | ||
99 | }, { | ||
100 | .name = "max8925-onkey", | ||
101 | .start = MAX8925_IRQ_GPM_SW_F, | ||
102 | .end = MAX8925_IRQ_GPM_SW_F, | ||
98 | .flags = IORESOURCE_IRQ, | 103 | .flags = IORESOURCE_IRQ, |
99 | }, | 104 | }, |
100 | }; | 105 | }; |
@@ -102,7 +107,7 @@ static struct resource onkey_resources[] = { | |||
102 | static struct mfd_cell onkey_devs[] = { | 107 | static struct mfd_cell onkey_devs[] = { |
103 | { | 108 | { |
104 | .name = "max8925-onkey", | 109 | .name = "max8925-onkey", |
105 | .num_resources = 1, | 110 | .num_resources = 2, |
106 | .resources = &onkey_resources[0], | 111 | .resources = &onkey_resources[0], |
107 | .id = -1, | 112 | .id = -1, |
108 | }, | 113 | }, |
diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c new file mode 100644 index 000000000000..45bfe77b639b --- /dev/null +++ b/drivers/mfd/max8998-irq.c | |||
@@ -0,0 +1,258 @@ | |||
1 | /* | ||
2 | * Interrupt controller support for MAX8998 | ||
3 | * | ||
4 | * Copyright (C) 2010 Samsung Electronics Co.Ltd | ||
5 | * Author: Joonyoung Shim <jy0922.shim@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/device.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/mfd/max8998-private.h> | ||
18 | |||
19 | struct max8998_irq_data { | ||
20 | int reg; | ||
21 | int mask; | ||
22 | }; | ||
23 | |||
24 | static struct max8998_irq_data max8998_irqs[] = { | ||
25 | [MAX8998_IRQ_DCINF] = { | ||
26 | .reg = 1, | ||
27 | .mask = MAX8998_IRQ_DCINF_MASK, | ||
28 | }, | ||
29 | [MAX8998_IRQ_DCINR] = { | ||
30 | .reg = 1, | ||
31 | .mask = MAX8998_IRQ_DCINR_MASK, | ||
32 | }, | ||
33 | [MAX8998_IRQ_JIGF] = { | ||
34 | .reg = 1, | ||
35 | .mask = MAX8998_IRQ_JIGF_MASK, | ||
36 | }, | ||
37 | [MAX8998_IRQ_JIGR] = { | ||
38 | .reg = 1, | ||
39 | .mask = MAX8998_IRQ_JIGR_MASK, | ||
40 | }, | ||
41 | [MAX8998_IRQ_PWRONF] = { | ||
42 | .reg = 1, | ||
43 | .mask = MAX8998_IRQ_PWRONF_MASK, | ||
44 | }, | ||
45 | [MAX8998_IRQ_PWRONR] = { | ||
46 | .reg = 1, | ||
47 | .mask = MAX8998_IRQ_PWRONR_MASK, | ||
48 | }, | ||
49 | [MAX8998_IRQ_WTSREVNT] = { | ||
50 | .reg = 2, | ||
51 | .mask = MAX8998_IRQ_WTSREVNT_MASK, | ||
52 | }, | ||
53 | [MAX8998_IRQ_SMPLEVNT] = { | ||
54 | .reg = 2, | ||
55 | .mask = MAX8998_IRQ_SMPLEVNT_MASK, | ||
56 | }, | ||
57 | [MAX8998_IRQ_ALARM1] = { | ||
58 | .reg = 2, | ||
59 | .mask = MAX8998_IRQ_ALARM1_MASK, | ||
60 | }, | ||
61 | [MAX8998_IRQ_ALARM0] = { | ||
62 | .reg = 2, | ||
63 | .mask = MAX8998_IRQ_ALARM0_MASK, | ||
64 | }, | ||
65 | [MAX8998_IRQ_ONKEY1S] = { | ||
66 | .reg = 3, | ||
67 | .mask = MAX8998_IRQ_ONKEY1S_MASK, | ||
68 | }, | ||
69 | [MAX8998_IRQ_TOPOFFR] = { | ||
70 | .reg = 3, | ||
71 | .mask = MAX8998_IRQ_TOPOFFR_MASK, | ||
72 | }, | ||
73 | [MAX8998_IRQ_DCINOVPR] = { | ||
74 | .reg = 3, | ||
75 | .mask = MAX8998_IRQ_DCINOVPR_MASK, | ||
76 | }, | ||
77 | [MAX8998_IRQ_CHGRSTF] = { | ||
78 | .reg = 3, | ||
79 | .mask = MAX8998_IRQ_CHGRSTF_MASK, | ||
80 | }, | ||
81 | [MAX8998_IRQ_DONER] = { | ||
82 | .reg = 3, | ||
83 | .mask = MAX8998_IRQ_DONER_MASK, | ||
84 | }, | ||
85 | [MAX8998_IRQ_CHGFAULT] = { | ||
86 | .reg = 3, | ||
87 | .mask = MAX8998_IRQ_CHGFAULT_MASK, | ||
88 | }, | ||
89 | [MAX8998_IRQ_LOBAT1] = { | ||
90 | .reg = 4, | ||
91 | .mask = MAX8998_IRQ_LOBAT1_MASK, | ||
92 | }, | ||
93 | [MAX8998_IRQ_LOBAT2] = { | ||
94 | .reg = 4, | ||
95 | .mask = MAX8998_IRQ_LOBAT2_MASK, | ||
96 | }, | ||
97 | }; | ||
98 | |||
99 | static inline struct max8998_irq_data * | ||
100 | irq_to_max8998_irq(struct max8998_dev *max8998, int irq) | ||
101 | { | ||
102 | return &max8998_irqs[irq - max8998->irq_base]; | ||
103 | } | ||
104 | |||
105 | static void max8998_irq_lock(unsigned int irq) | ||
106 | { | ||
107 | struct max8998_dev *max8998 = get_irq_chip_data(irq); | ||
108 | |||
109 | mutex_lock(&max8998->irqlock); | ||
110 | } | ||
111 | |||
112 | static void max8998_irq_sync_unlock(unsigned int irq) | ||
113 | { | ||
114 | struct max8998_dev *max8998 = get_irq_chip_data(irq); | ||
115 | int i; | ||
116 | |||
117 | for (i = 0; i < ARRAY_SIZE(max8998->irq_masks_cur); i++) { | ||
118 | /* | ||
119 | * If there's been a change in the mask write it back | ||
120 | * to the hardware. | ||
121 | */ | ||
122 | if (max8998->irq_masks_cur[i] != max8998->irq_masks_cache[i]) { | ||
123 | max8998->irq_masks_cache[i] = max8998->irq_masks_cur[i]; | ||
124 | max8998_write_reg(max8998->i2c, MAX8998_REG_IRQM1 + i, | ||
125 | max8998->irq_masks_cur[i]); | ||
126 | } | ||
127 | } | ||
128 | |||
129 | mutex_unlock(&max8998->irqlock); | ||
130 | } | ||
131 | |||
132 | static void max8998_irq_unmask(unsigned int irq) | ||
133 | { | ||
134 | struct max8998_dev *max8998 = get_irq_chip_data(irq); | ||
135 | struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq); | ||
136 | |||
137 | max8998->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; | ||
138 | } | ||
139 | |||
140 | static void max8998_irq_mask(unsigned int irq) | ||
141 | { | ||
142 | struct max8998_dev *max8998 = get_irq_chip_data(irq); | ||
143 | struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq); | ||
144 | |||
145 | max8998->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; | ||
146 | } | ||
147 | |||
148 | static struct irq_chip max8998_irq_chip = { | ||
149 | .name = "max8998", | ||
150 | .bus_lock = max8998_irq_lock, | ||
151 | .bus_sync_unlock = max8998_irq_sync_unlock, | ||
152 | .mask = max8998_irq_mask, | ||
153 | .unmask = max8998_irq_unmask, | ||
154 | }; | ||
155 | |||
156 | static irqreturn_t max8998_irq_thread(int irq, void *data) | ||
157 | { | ||
158 | struct max8998_dev *max8998 = data; | ||
159 | u8 irq_reg[MAX8998_NUM_IRQ_REGS]; | ||
160 | int ret; | ||
161 | int i; | ||
162 | |||
163 | ret = max8998_bulk_read(max8998->i2c, MAX8998_REG_IRQ1, | ||
164 | MAX8998_NUM_IRQ_REGS, irq_reg); | ||
165 | if (ret < 0) { | ||
166 | dev_err(max8998->dev, "Failed to read interrupt register: %d\n", | ||
167 | ret); | ||
168 | return IRQ_NONE; | ||
169 | } | ||
170 | |||
171 | /* Apply masking */ | ||
172 | for (i = 0; i < MAX8998_NUM_IRQ_REGS; i++) | ||
173 | irq_reg[i] &= ~max8998->irq_masks_cur[i]; | ||
174 | |||
175 | /* Report */ | ||
176 | for (i = 0; i < MAX8998_IRQ_NR; i++) { | ||
177 | if (irq_reg[max8998_irqs[i].reg - 1] & max8998_irqs[i].mask) | ||
178 | handle_nested_irq(max8998->irq_base + i); | ||
179 | } | ||
180 | |||
181 | return IRQ_HANDLED; | ||
182 | } | ||
183 | |||
184 | int max8998_irq_init(struct max8998_dev *max8998) | ||
185 | { | ||
186 | int i; | ||
187 | int cur_irq; | ||
188 | int ret; | ||
189 | |||
190 | if (!max8998->irq) { | ||
191 | dev_warn(max8998->dev, | ||
192 | "No interrupt specified, no interrupts\n"); | ||
193 | max8998->irq_base = 0; | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | if (!max8998->irq_base) { | ||
198 | dev_err(max8998->dev, | ||
199 | "No interrupt base specified, no interrupts\n"); | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | mutex_init(&max8998->irqlock); | ||
204 | |||
205 | /* Mask the individual interrupt sources */ | ||
206 | for (i = 0; i < MAX8998_NUM_IRQ_REGS; i++) { | ||
207 | max8998->irq_masks_cur[i] = 0xff; | ||
208 | max8998->irq_masks_cache[i] = 0xff; | ||
209 | max8998_write_reg(max8998->i2c, MAX8998_REG_IRQM1 + i, 0xff); | ||
210 | } | ||
211 | |||
212 | max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM1, 0xff); | ||
213 | max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM2, 0xff); | ||
214 | |||
215 | /* register with genirq */ | ||
216 | for (i = 0; i < MAX8998_IRQ_NR; i++) { | ||
217 | cur_irq = i + max8998->irq_base; | ||
218 | set_irq_chip_data(cur_irq, max8998); | ||
219 | set_irq_chip_and_handler(cur_irq, &max8998_irq_chip, | ||
220 | handle_edge_irq); | ||
221 | set_irq_nested_thread(cur_irq, 1); | ||
222 | #ifdef CONFIG_ARM | ||
223 | set_irq_flags(cur_irq, IRQF_VALID); | ||
224 | #else | ||
225 | set_irq_noprobe(cur_irq); | ||
226 | #endif | ||
227 | } | ||
228 | |||
229 | ret = request_threaded_irq(max8998->irq, NULL, max8998_irq_thread, | ||
230 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
231 | "max8998-irq", max8998); | ||
232 | if (ret) { | ||
233 | dev_err(max8998->dev, "Failed to request IRQ %d: %d\n", | ||
234 | max8998->irq, ret); | ||
235 | return ret; | ||
236 | } | ||
237 | |||
238 | if (!max8998->ono) | ||
239 | return 0; | ||
240 | |||
241 | ret = request_threaded_irq(max8998->ono, NULL, max8998_irq_thread, | ||
242 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | | ||
243 | IRQF_ONESHOT, "max8998-ono", max8998); | ||
244 | if (ret) | ||
245 | dev_err(max8998->dev, "Failed to request IRQ %d: %d\n", | ||
246 | max8998->ono, ret); | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | void max8998_irq_exit(struct max8998_dev *max8998) | ||
252 | { | ||
253 | if (max8998->ono) | ||
254 | free_irq(max8998->ono, max8998); | ||
255 | |||
256 | if (max8998->irq) | ||
257 | free_irq(max8998->irq, max8998); | ||
258 | } | ||
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index 73e6f5c4efc9..bb9977bebe78 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * max8698.c - mfd core driver for the Maxim 8998 | 2 | * max8998.c - mfd core driver for the Maxim 8998 |
3 | * | 3 | * |
4 | * Copyright (C) 2009-2010 Samsung Electronics | 4 | * Copyright (C) 2009-2010 Samsung Electronics |
5 | * Kyungmin Park <kyungmin.park@samsung.com> | 5 | * Kyungmin Park <kyungmin.park@samsung.com> |
@@ -30,19 +30,23 @@ | |||
30 | #include <linux/mfd/max8998.h> | 30 | #include <linux/mfd/max8998.h> |
31 | #include <linux/mfd/max8998-private.h> | 31 | #include <linux/mfd/max8998-private.h> |
32 | 32 | ||
33 | #define RTC_I2C_ADDR (0x0c >> 1) | ||
34 | |||
33 | static struct mfd_cell max8998_devs[] = { | 35 | static struct mfd_cell max8998_devs[] = { |
34 | { | 36 | { |
35 | .name = "max8998-pmic", | 37 | .name = "max8998-pmic", |
36 | } | 38 | }, { |
39 | .name = "max8998-rtc", | ||
40 | }, | ||
37 | }; | 41 | }; |
38 | 42 | ||
39 | static int max8998_i2c_device_read(struct max8998_dev *max8998, u8 reg, u8 *dest) | 43 | int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest) |
40 | { | 44 | { |
41 | struct i2c_client *client = max8998->i2c_client; | 45 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); |
42 | int ret; | 46 | int ret; |
43 | 47 | ||
44 | mutex_lock(&max8998->iolock); | 48 | mutex_lock(&max8998->iolock); |
45 | ret = i2c_smbus_read_byte_data(client, reg); | 49 | ret = i2c_smbus_read_byte_data(i2c, reg); |
46 | mutex_unlock(&max8998->iolock); | 50 | mutex_unlock(&max8998->iolock); |
47 | if (ret < 0) | 51 | if (ret < 0) |
48 | return ret; | 52 | return ret; |
@@ -51,40 +55,71 @@ static int max8998_i2c_device_read(struct max8998_dev *max8998, u8 reg, u8 *dest | |||
51 | *dest = ret; | 55 | *dest = ret; |
52 | return 0; | 56 | return 0; |
53 | } | 57 | } |
58 | EXPORT_SYMBOL(max8998_read_reg); | ||
54 | 59 | ||
55 | static int max8998_i2c_device_write(struct max8998_dev *max8998, u8 reg, u8 value) | 60 | int max8998_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf) |
56 | { | 61 | { |
57 | struct i2c_client *client = max8998->i2c_client; | 62 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); |
63 | int ret; | ||
64 | |||
65 | mutex_lock(&max8998->iolock); | ||
66 | ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf); | ||
67 | mutex_unlock(&max8998->iolock); | ||
68 | if (ret < 0) | ||
69 | return ret; | ||
70 | |||
71 | return 0; | ||
72 | } | ||
73 | EXPORT_SYMBOL(max8998_bulk_read); | ||
74 | |||
75 | int max8998_write_reg(struct i2c_client *i2c, u8 reg, u8 value) | ||
76 | { | ||
77 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); | ||
58 | int ret; | 78 | int ret; |
59 | 79 | ||
60 | mutex_lock(&max8998->iolock); | 80 | mutex_lock(&max8998->iolock); |
61 | ret = i2c_smbus_write_byte_data(client, reg, value); | 81 | ret = i2c_smbus_write_byte_data(i2c, reg, value); |
62 | mutex_unlock(&max8998->iolock); | 82 | mutex_unlock(&max8998->iolock); |
63 | return ret; | 83 | return ret; |
64 | } | 84 | } |
85 | EXPORT_SYMBOL(max8998_write_reg); | ||
65 | 86 | ||
66 | static int max8998_i2c_device_update(struct max8998_dev *max8998, u8 reg, | 87 | int max8998_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf) |
67 | u8 val, u8 mask) | ||
68 | { | 88 | { |
69 | struct i2c_client *client = max8998->i2c_client; | 89 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); |
90 | int ret; | ||
91 | |||
92 | mutex_lock(&max8998->iolock); | ||
93 | ret = i2c_smbus_write_i2c_block_data(i2c, reg, count, buf); | ||
94 | mutex_unlock(&max8998->iolock); | ||
95 | if (ret < 0) | ||
96 | return ret; | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | EXPORT_SYMBOL(max8998_bulk_write); | ||
101 | |||
102 | int max8998_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask) | ||
103 | { | ||
104 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); | ||
70 | int ret; | 105 | int ret; |
71 | 106 | ||
72 | mutex_lock(&max8998->iolock); | 107 | mutex_lock(&max8998->iolock); |
73 | ret = i2c_smbus_read_byte_data(client, reg); | 108 | ret = i2c_smbus_read_byte_data(i2c, reg); |
74 | if (ret >= 0) { | 109 | if (ret >= 0) { |
75 | u8 old_val = ret & 0xff; | 110 | u8 old_val = ret & 0xff; |
76 | u8 new_val = (val & mask) | (old_val & (~mask)); | 111 | u8 new_val = (val & mask) | (old_val & (~mask)); |
77 | ret = i2c_smbus_write_byte_data(client, reg, new_val); | 112 | ret = i2c_smbus_write_byte_data(i2c, reg, new_val); |
78 | if (ret >= 0) | ||
79 | ret = 0; | ||
80 | } | 113 | } |
81 | mutex_unlock(&max8998->iolock); | 114 | mutex_unlock(&max8998->iolock); |
82 | return ret; | 115 | return ret; |
83 | } | 116 | } |
117 | EXPORT_SYMBOL(max8998_update_reg); | ||
84 | 118 | ||
85 | static int max8998_i2c_probe(struct i2c_client *i2c, | 119 | static int max8998_i2c_probe(struct i2c_client *i2c, |
86 | const struct i2c_device_id *id) | 120 | const struct i2c_device_id *id) |
87 | { | 121 | { |
122 | struct max8998_platform_data *pdata = i2c->dev.platform_data; | ||
88 | struct max8998_dev *max8998; | 123 | struct max8998_dev *max8998; |
89 | int ret = 0; | 124 | int ret = 0; |
90 | 125 | ||
@@ -94,12 +129,20 @@ static int max8998_i2c_probe(struct i2c_client *i2c, | |||
94 | 129 | ||
95 | i2c_set_clientdata(i2c, max8998); | 130 | i2c_set_clientdata(i2c, max8998); |
96 | max8998->dev = &i2c->dev; | 131 | max8998->dev = &i2c->dev; |
97 | max8998->i2c_client = i2c; | 132 | max8998->i2c = i2c; |
98 | max8998->dev_read = max8998_i2c_device_read; | 133 | max8998->irq = i2c->irq; |
99 | max8998->dev_write = max8998_i2c_device_write; | 134 | max8998->type = id->driver_data; |
100 | max8998->dev_update = max8998_i2c_device_update; | 135 | if (pdata) { |
136 | max8998->ono = pdata->ono; | ||
137 | max8998->irq_base = pdata->irq_base; | ||
138 | } | ||
101 | mutex_init(&max8998->iolock); | 139 | mutex_init(&max8998->iolock); |
102 | 140 | ||
141 | max8998->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR); | ||
142 | i2c_set_clientdata(max8998->rtc, max8998); | ||
143 | |||
144 | max8998_irq_init(max8998); | ||
145 | |||
103 | ret = mfd_add_devices(max8998->dev, -1, | 146 | ret = mfd_add_devices(max8998->dev, -1, |
104 | max8998_devs, ARRAY_SIZE(max8998_devs), | 147 | max8998_devs, ARRAY_SIZE(max8998_devs), |
105 | NULL, 0); | 148 | NULL, 0); |
@@ -110,6 +153,8 @@ static int max8998_i2c_probe(struct i2c_client *i2c, | |||
110 | 153 | ||
111 | err: | 154 | err: |
112 | mfd_remove_devices(max8998->dev); | 155 | mfd_remove_devices(max8998->dev); |
156 | max8998_irq_exit(max8998); | ||
157 | i2c_unregister_device(max8998->rtc); | ||
113 | kfree(max8998); | 158 | kfree(max8998); |
114 | return ret; | 159 | return ret; |
115 | } | 160 | } |
@@ -119,14 +164,17 @@ static int max8998_i2c_remove(struct i2c_client *i2c) | |||
119 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); | 164 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); |
120 | 165 | ||
121 | mfd_remove_devices(max8998->dev); | 166 | mfd_remove_devices(max8998->dev); |
167 | max8998_irq_exit(max8998); | ||
168 | i2c_unregister_device(max8998->rtc); | ||
122 | kfree(max8998); | 169 | kfree(max8998); |
123 | 170 | ||
124 | return 0; | 171 | return 0; |
125 | } | 172 | } |
126 | 173 | ||
127 | static const struct i2c_device_id max8998_i2c_id[] = { | 174 | static const struct i2c_device_id max8998_i2c_id[] = { |
128 | { "max8998", 0 }, | 175 | { "max8998", TYPE_MAX8998 }, |
129 | { } | 176 | { "lp3974", TYPE_LP3974}, |
177 | { } | ||
130 | }; | 178 | }; |
131 | MODULE_DEVICE_TABLE(i2c, max8998_i2c_id); | 179 | MODULE_DEVICE_TABLE(i2c, max8998_i2c_id); |
132 | 180 | ||
diff --git a/drivers/mfd/mc13783-core.c b/drivers/mfd/mc13783-core.c deleted file mode 100644 index 6df34989c1f6..000000000000 --- a/drivers/mfd/mc13783-core.c +++ /dev/null | |||
@@ -1,752 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2009 Pengutronix | ||
3 | * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> | ||
4 | * | ||
5 | * loosely based on an earlier driver that has | ||
6 | * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it under | ||
9 | * the terms of the GNU General Public License version 2 as published by the | ||
10 | * Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/mutex.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/spi/spi.h> | ||
18 | #include <linux/mfd/core.h> | ||
19 | #include <linux/mfd/mc13783.h> | ||
20 | |||
21 | struct mc13783 { | ||
22 | struct spi_device *spidev; | ||
23 | struct mutex lock; | ||
24 | int irq; | ||
25 | int flags; | ||
26 | |||
27 | irq_handler_t irqhandler[MC13783_NUM_IRQ]; | ||
28 | void *irqdata[MC13783_NUM_IRQ]; | ||
29 | |||
30 | /* XXX these should go as platformdata to the regulator subdevice */ | ||
31 | struct mc13783_regulator_init_data *regulators; | ||
32 | int num_regulators; | ||
33 | }; | ||
34 | |||
35 | #define MC13783_REG_REVISION 7 | ||
36 | #define MC13783_REG_ADC_0 43 | ||
37 | #define MC13783_REG_ADC_1 44 | ||
38 | #define MC13783_REG_ADC_2 45 | ||
39 | |||
40 | #define MC13783_IRQSTAT0 0 | ||
41 | #define MC13783_IRQSTAT0_ADCDONEI (1 << 0) | ||
42 | #define MC13783_IRQSTAT0_ADCBISDONEI (1 << 1) | ||
43 | #define MC13783_IRQSTAT0_TSI (1 << 2) | ||
44 | #define MC13783_IRQSTAT0_WHIGHI (1 << 3) | ||
45 | #define MC13783_IRQSTAT0_WLOWI (1 << 4) | ||
46 | #define MC13783_IRQSTAT0_CHGDETI (1 << 6) | ||
47 | #define MC13783_IRQSTAT0_CHGOVI (1 << 7) | ||
48 | #define MC13783_IRQSTAT0_CHGREVI (1 << 8) | ||
49 | #define MC13783_IRQSTAT0_CHGSHORTI (1 << 9) | ||
50 | #define MC13783_IRQSTAT0_CCCVI (1 << 10) | ||
51 | #define MC13783_IRQSTAT0_CHGCURRI (1 << 11) | ||
52 | #define MC13783_IRQSTAT0_BPONI (1 << 12) | ||
53 | #define MC13783_IRQSTAT0_LOBATLI (1 << 13) | ||
54 | #define MC13783_IRQSTAT0_LOBATHI (1 << 14) | ||
55 | #define MC13783_IRQSTAT0_UDPI (1 << 15) | ||
56 | #define MC13783_IRQSTAT0_USBI (1 << 16) | ||
57 | #define MC13783_IRQSTAT0_IDI (1 << 19) | ||
58 | #define MC13783_IRQSTAT0_SE1I (1 << 21) | ||
59 | #define MC13783_IRQSTAT0_CKDETI (1 << 22) | ||
60 | #define MC13783_IRQSTAT0_UDMI (1 << 23) | ||
61 | |||
62 | #define MC13783_IRQMASK0 1 | ||
63 | #define MC13783_IRQMASK0_ADCDONEM MC13783_IRQSTAT0_ADCDONEI | ||
64 | #define MC13783_IRQMASK0_ADCBISDONEM MC13783_IRQSTAT0_ADCBISDONEI | ||
65 | #define MC13783_IRQMASK0_TSM MC13783_IRQSTAT0_TSI | ||
66 | #define MC13783_IRQMASK0_WHIGHM MC13783_IRQSTAT0_WHIGHI | ||
67 | #define MC13783_IRQMASK0_WLOWM MC13783_IRQSTAT0_WLOWI | ||
68 | #define MC13783_IRQMASK0_CHGDETM MC13783_IRQSTAT0_CHGDETI | ||
69 | #define MC13783_IRQMASK0_CHGOVM MC13783_IRQSTAT0_CHGOVI | ||
70 | #define MC13783_IRQMASK0_CHGREVM MC13783_IRQSTAT0_CHGREVI | ||
71 | #define MC13783_IRQMASK0_CHGSHORTM MC13783_IRQSTAT0_CHGSHORTI | ||
72 | #define MC13783_IRQMASK0_CCCVM MC13783_IRQSTAT0_CCCVI | ||
73 | #define MC13783_IRQMASK0_CHGCURRM MC13783_IRQSTAT0_CHGCURRI | ||
74 | #define MC13783_IRQMASK0_BPONM MC13783_IRQSTAT0_BPONI | ||
75 | #define MC13783_IRQMASK0_LOBATLM MC13783_IRQSTAT0_LOBATLI | ||
76 | #define MC13783_IRQMASK0_LOBATHM MC13783_IRQSTAT0_LOBATHI | ||
77 | #define MC13783_IRQMASK0_UDPM MC13783_IRQSTAT0_UDPI | ||
78 | #define MC13783_IRQMASK0_USBM MC13783_IRQSTAT0_USBI | ||
79 | #define MC13783_IRQMASK0_IDM MC13783_IRQSTAT0_IDI | ||
80 | #define MC13783_IRQMASK0_SE1M MC13783_IRQSTAT0_SE1I | ||
81 | #define MC13783_IRQMASK0_CKDETM MC13783_IRQSTAT0_CKDETI | ||
82 | #define MC13783_IRQMASK0_UDMM MC13783_IRQSTAT0_UDMI | ||
83 | |||
84 | #define MC13783_IRQSTAT1 3 | ||
85 | #define MC13783_IRQSTAT1_1HZI (1 << 0) | ||
86 | #define MC13783_IRQSTAT1_TODAI (1 << 1) | ||
87 | #define MC13783_IRQSTAT1_ONOFD1I (1 << 3) | ||
88 | #define MC13783_IRQSTAT1_ONOFD2I (1 << 4) | ||
89 | #define MC13783_IRQSTAT1_ONOFD3I (1 << 5) | ||
90 | #define MC13783_IRQSTAT1_SYSRSTI (1 << 6) | ||
91 | #define MC13783_IRQSTAT1_RTCRSTI (1 << 7) | ||
92 | #define MC13783_IRQSTAT1_PCI (1 << 8) | ||
93 | #define MC13783_IRQSTAT1_WARMI (1 << 9) | ||
94 | #define MC13783_IRQSTAT1_MEMHLDI (1 << 10) | ||
95 | #define MC13783_IRQSTAT1_PWRRDYI (1 << 11) | ||
96 | #define MC13783_IRQSTAT1_THWARNLI (1 << 12) | ||
97 | #define MC13783_IRQSTAT1_THWARNHI (1 << 13) | ||
98 | #define MC13783_IRQSTAT1_CLKI (1 << 14) | ||
99 | #define MC13783_IRQSTAT1_SEMAFI (1 << 15) | ||
100 | #define MC13783_IRQSTAT1_MC2BI (1 << 17) | ||
101 | #define MC13783_IRQSTAT1_HSDETI (1 << 18) | ||
102 | #define MC13783_IRQSTAT1_HSLI (1 << 19) | ||
103 | #define MC13783_IRQSTAT1_ALSPTHI (1 << 20) | ||
104 | #define MC13783_IRQSTAT1_AHSSHORTI (1 << 21) | ||
105 | |||
106 | #define MC13783_IRQMASK1 4 | ||
107 | #define MC13783_IRQMASK1_1HZM MC13783_IRQSTAT1_1HZI | ||
108 | #define MC13783_IRQMASK1_TODAM MC13783_IRQSTAT1_TODAI | ||
109 | #define MC13783_IRQMASK1_ONOFD1M MC13783_IRQSTAT1_ONOFD1I | ||
110 | #define MC13783_IRQMASK1_ONOFD2M MC13783_IRQSTAT1_ONOFD2I | ||
111 | #define MC13783_IRQMASK1_ONOFD3M MC13783_IRQSTAT1_ONOFD3I | ||
112 | #define MC13783_IRQMASK1_SYSRSTM MC13783_IRQSTAT1_SYSRSTI | ||
113 | #define MC13783_IRQMASK1_RTCRSTM MC13783_IRQSTAT1_RTCRSTI | ||
114 | #define MC13783_IRQMASK1_PCM MC13783_IRQSTAT1_PCI | ||
115 | #define MC13783_IRQMASK1_WARMM MC13783_IRQSTAT1_WARMI | ||
116 | #define MC13783_IRQMASK1_MEMHLDM MC13783_IRQSTAT1_MEMHLDI | ||
117 | #define MC13783_IRQMASK1_PWRRDYM MC13783_IRQSTAT1_PWRRDYI | ||
118 | #define MC13783_IRQMASK1_THWARNLM MC13783_IRQSTAT1_THWARNLI | ||
119 | #define MC13783_IRQMASK1_THWARNHM MC13783_IRQSTAT1_THWARNHI | ||
120 | #define MC13783_IRQMASK1_CLKM MC13783_IRQSTAT1_CLKI | ||
121 | #define MC13783_IRQMASK1_SEMAFM MC13783_IRQSTAT1_SEMAFI | ||
122 | #define MC13783_IRQMASK1_MC2BM MC13783_IRQSTAT1_MC2BI | ||
123 | #define MC13783_IRQMASK1_HSDETM MC13783_IRQSTAT1_HSDETI | ||
124 | #define MC13783_IRQMASK1_HSLM MC13783_IRQSTAT1_HSLI | ||
125 | #define MC13783_IRQMASK1_ALSPTHM MC13783_IRQSTAT1_ALSPTHI | ||
126 | #define MC13783_IRQMASK1_AHSSHORTM MC13783_IRQSTAT1_AHSSHORTI | ||
127 | |||
128 | #define MC13783_ADC1 44 | ||
129 | #define MC13783_ADC1_ADEN (1 << 0) | ||
130 | #define MC13783_ADC1_RAND (1 << 1) | ||
131 | #define MC13783_ADC1_ADSEL (1 << 3) | ||
132 | #define MC13783_ADC1_ASC (1 << 20) | ||
133 | #define MC13783_ADC1_ADTRIGIGN (1 << 21) | ||
134 | |||
135 | #define MC13783_NUMREGS 0x3f | ||
136 | |||
137 | void mc13783_lock(struct mc13783 *mc13783) | ||
138 | { | ||
139 | if (!mutex_trylock(&mc13783->lock)) { | ||
140 | dev_dbg(&mc13783->spidev->dev, "wait for %s from %pf\n", | ||
141 | __func__, __builtin_return_address(0)); | ||
142 | |||
143 | mutex_lock(&mc13783->lock); | ||
144 | } | ||
145 | dev_dbg(&mc13783->spidev->dev, "%s from %pf\n", | ||
146 | __func__, __builtin_return_address(0)); | ||
147 | } | ||
148 | EXPORT_SYMBOL(mc13783_lock); | ||
149 | |||
150 | void mc13783_unlock(struct mc13783 *mc13783) | ||
151 | { | ||
152 | dev_dbg(&mc13783->spidev->dev, "%s from %pf\n", | ||
153 | __func__, __builtin_return_address(0)); | ||
154 | mutex_unlock(&mc13783->lock); | ||
155 | } | ||
156 | EXPORT_SYMBOL(mc13783_unlock); | ||
157 | |||
158 | #define MC13783_REGOFFSET_SHIFT 25 | ||
159 | int mc13783_reg_read(struct mc13783 *mc13783, unsigned int offset, u32 *val) | ||
160 | { | ||
161 | struct spi_transfer t; | ||
162 | struct spi_message m; | ||
163 | int ret; | ||
164 | |||
165 | BUG_ON(!mutex_is_locked(&mc13783->lock)); | ||
166 | |||
167 | if (offset > MC13783_NUMREGS) | ||
168 | return -EINVAL; | ||
169 | |||
170 | *val = offset << MC13783_REGOFFSET_SHIFT; | ||
171 | |||
172 | memset(&t, 0, sizeof(t)); | ||
173 | |||
174 | t.tx_buf = val; | ||
175 | t.rx_buf = val; | ||
176 | t.len = sizeof(u32); | ||
177 | |||
178 | spi_message_init(&m); | ||
179 | spi_message_add_tail(&t, &m); | ||
180 | |||
181 | ret = spi_sync(mc13783->spidev, &m); | ||
182 | |||
183 | /* error in message.status implies error return from spi_sync */ | ||
184 | BUG_ON(!ret && m.status); | ||
185 | |||
186 | if (ret) | ||
187 | return ret; | ||
188 | |||
189 | *val &= 0xffffff; | ||
190 | |||
191 | dev_vdbg(&mc13783->spidev->dev, "[0x%02x] -> 0x%06x\n", offset, *val); | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | EXPORT_SYMBOL(mc13783_reg_read); | ||
196 | |||
197 | int mc13783_reg_write(struct mc13783 *mc13783, unsigned int offset, u32 val) | ||
198 | { | ||
199 | u32 buf; | ||
200 | struct spi_transfer t; | ||
201 | struct spi_message m; | ||
202 | int ret; | ||
203 | |||
204 | BUG_ON(!mutex_is_locked(&mc13783->lock)); | ||
205 | |||
206 | dev_vdbg(&mc13783->spidev->dev, "[0x%02x] <- 0x%06x\n", offset, val); | ||
207 | |||
208 | if (offset > MC13783_NUMREGS || val > 0xffffff) | ||
209 | return -EINVAL; | ||
210 | |||
211 | buf = 1 << 31 | offset << MC13783_REGOFFSET_SHIFT | val; | ||
212 | |||
213 | memset(&t, 0, sizeof(t)); | ||
214 | |||
215 | t.tx_buf = &buf; | ||
216 | t.rx_buf = &buf; | ||
217 | t.len = sizeof(u32); | ||
218 | |||
219 | spi_message_init(&m); | ||
220 | spi_message_add_tail(&t, &m); | ||
221 | |||
222 | ret = spi_sync(mc13783->spidev, &m); | ||
223 | |||
224 | BUG_ON(!ret && m.status); | ||
225 | |||
226 | if (ret) | ||
227 | return ret; | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | EXPORT_SYMBOL(mc13783_reg_write); | ||
232 | |||
233 | int mc13783_reg_rmw(struct mc13783 *mc13783, unsigned int offset, | ||
234 | u32 mask, u32 val) | ||
235 | { | ||
236 | int ret; | ||
237 | u32 valread; | ||
238 | |||
239 | BUG_ON(val & ~mask); | ||
240 | |||
241 | ret = mc13783_reg_read(mc13783, offset, &valread); | ||
242 | if (ret) | ||
243 | return ret; | ||
244 | |||
245 | valread = (valread & ~mask) | val; | ||
246 | |||
247 | return mc13783_reg_write(mc13783, offset, valread); | ||
248 | } | ||
249 | EXPORT_SYMBOL(mc13783_reg_rmw); | ||
250 | |||
251 | int mc13783_get_flags(struct mc13783 *mc13783) | ||
252 | { | ||
253 | return mc13783->flags; | ||
254 | } | ||
255 | EXPORT_SYMBOL(mc13783_get_flags); | ||
256 | |||
257 | int mc13783_irq_mask(struct mc13783 *mc13783, int irq) | ||
258 | { | ||
259 | int ret; | ||
260 | unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1; | ||
261 | u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | ||
262 | u32 mask; | ||
263 | |||
264 | if (irq < 0 || irq >= MC13783_NUM_IRQ) | ||
265 | return -EINVAL; | ||
266 | |||
267 | ret = mc13783_reg_read(mc13783, offmask, &mask); | ||
268 | if (ret) | ||
269 | return ret; | ||
270 | |||
271 | if (mask & irqbit) | ||
272 | /* already masked */ | ||
273 | return 0; | ||
274 | |||
275 | return mc13783_reg_write(mc13783, offmask, mask | irqbit); | ||
276 | } | ||
277 | EXPORT_SYMBOL(mc13783_irq_mask); | ||
278 | |||
279 | int mc13783_irq_unmask(struct mc13783 *mc13783, int irq) | ||
280 | { | ||
281 | int ret; | ||
282 | unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1; | ||
283 | u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | ||
284 | u32 mask; | ||
285 | |||
286 | if (irq < 0 || irq >= MC13783_NUM_IRQ) | ||
287 | return -EINVAL; | ||
288 | |||
289 | ret = mc13783_reg_read(mc13783, offmask, &mask); | ||
290 | if (ret) | ||
291 | return ret; | ||
292 | |||
293 | if (!(mask & irqbit)) | ||
294 | /* already unmasked */ | ||
295 | return 0; | ||
296 | |||
297 | return mc13783_reg_write(mc13783, offmask, mask & ~irqbit); | ||
298 | } | ||
299 | EXPORT_SYMBOL(mc13783_irq_unmask); | ||
300 | |||
301 | int mc13783_irq_status(struct mc13783 *mc13783, int irq, | ||
302 | int *enabled, int *pending) | ||
303 | { | ||
304 | int ret; | ||
305 | unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1; | ||
306 | unsigned int offstat = irq < 24 ? MC13783_IRQSTAT0 : MC13783_IRQSTAT1; | ||
307 | u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | ||
308 | |||
309 | if (irq < 0 || irq >= MC13783_NUM_IRQ) | ||
310 | return -EINVAL; | ||
311 | |||
312 | if (enabled) { | ||
313 | u32 mask; | ||
314 | |||
315 | ret = mc13783_reg_read(mc13783, offmask, &mask); | ||
316 | if (ret) | ||
317 | return ret; | ||
318 | |||
319 | *enabled = mask & irqbit; | ||
320 | } | ||
321 | |||
322 | if (pending) { | ||
323 | u32 stat; | ||
324 | |||
325 | ret = mc13783_reg_read(mc13783, offstat, &stat); | ||
326 | if (ret) | ||
327 | return ret; | ||
328 | |||
329 | *pending = stat & irqbit; | ||
330 | } | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | EXPORT_SYMBOL(mc13783_irq_status); | ||
335 | |||
336 | int mc13783_irq_ack(struct mc13783 *mc13783, int irq) | ||
337 | { | ||
338 | unsigned int offstat = irq < 24 ? MC13783_IRQSTAT0 : MC13783_IRQSTAT1; | ||
339 | unsigned int val = 1 << (irq < 24 ? irq : irq - 24); | ||
340 | |||
341 | BUG_ON(irq < 0 || irq >= MC13783_NUM_IRQ); | ||
342 | |||
343 | return mc13783_reg_write(mc13783, offstat, val); | ||
344 | } | ||
345 | EXPORT_SYMBOL(mc13783_irq_ack); | ||
346 | |||
347 | int mc13783_irq_request_nounmask(struct mc13783 *mc13783, int irq, | ||
348 | irq_handler_t handler, const char *name, void *dev) | ||
349 | { | ||
350 | BUG_ON(!mutex_is_locked(&mc13783->lock)); | ||
351 | BUG_ON(!handler); | ||
352 | |||
353 | if (irq < 0 || irq >= MC13783_NUM_IRQ) | ||
354 | return -EINVAL; | ||
355 | |||
356 | if (mc13783->irqhandler[irq]) | ||
357 | return -EBUSY; | ||
358 | |||
359 | mc13783->irqhandler[irq] = handler; | ||
360 | mc13783->irqdata[irq] = dev; | ||
361 | |||
362 | return 0; | ||
363 | } | ||
364 | EXPORT_SYMBOL(mc13783_irq_request_nounmask); | ||
365 | |||
366 | int mc13783_irq_request(struct mc13783 *mc13783, int irq, | ||
367 | irq_handler_t handler, const char *name, void *dev) | ||
368 | { | ||
369 | int ret; | ||
370 | |||
371 | ret = mc13783_irq_request_nounmask(mc13783, irq, handler, name, dev); | ||
372 | if (ret) | ||
373 | return ret; | ||
374 | |||
375 | ret = mc13783_irq_unmask(mc13783, irq); | ||
376 | if (ret) { | ||
377 | mc13783->irqhandler[irq] = NULL; | ||
378 | mc13783->irqdata[irq] = NULL; | ||
379 | return ret; | ||
380 | } | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | EXPORT_SYMBOL(mc13783_irq_request); | ||
385 | |||
386 | int mc13783_irq_free(struct mc13783 *mc13783, int irq, void *dev) | ||
387 | { | ||
388 | int ret; | ||
389 | BUG_ON(!mutex_is_locked(&mc13783->lock)); | ||
390 | |||
391 | if (irq < 0 || irq >= MC13783_NUM_IRQ || !mc13783->irqhandler[irq] || | ||
392 | mc13783->irqdata[irq] != dev) | ||
393 | return -EINVAL; | ||
394 | |||
395 | ret = mc13783_irq_mask(mc13783, irq); | ||
396 | if (ret) | ||
397 | return ret; | ||
398 | |||
399 | mc13783->irqhandler[irq] = NULL; | ||
400 | mc13783->irqdata[irq] = NULL; | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | EXPORT_SYMBOL(mc13783_irq_free); | ||
405 | |||
406 | static inline irqreturn_t mc13783_irqhandler(struct mc13783 *mc13783, int irq) | ||
407 | { | ||
408 | return mc13783->irqhandler[irq](irq, mc13783->irqdata[irq]); | ||
409 | } | ||
410 | |||
411 | /* | ||
412 | * returns: number of handled irqs or negative error | ||
413 | * locking: holds mc13783->lock | ||
414 | */ | ||
415 | static int mc13783_irq_handle(struct mc13783 *mc13783, | ||
416 | unsigned int offstat, unsigned int offmask, int baseirq) | ||
417 | { | ||
418 | u32 stat, mask; | ||
419 | int ret = mc13783_reg_read(mc13783, offstat, &stat); | ||
420 | int num_handled = 0; | ||
421 | |||
422 | if (ret) | ||
423 | return ret; | ||
424 | |||
425 | ret = mc13783_reg_read(mc13783, offmask, &mask); | ||
426 | if (ret) | ||
427 | return ret; | ||
428 | |||
429 | while (stat & ~mask) { | ||
430 | int irq = __ffs(stat & ~mask); | ||
431 | |||
432 | stat &= ~(1 << irq); | ||
433 | |||
434 | if (likely(mc13783->irqhandler[baseirq + irq])) { | ||
435 | irqreturn_t handled; | ||
436 | |||
437 | handled = mc13783_irqhandler(mc13783, baseirq + irq); | ||
438 | if (handled == IRQ_HANDLED) | ||
439 | num_handled++; | ||
440 | } else { | ||
441 | dev_err(&mc13783->spidev->dev, | ||
442 | "BUG: irq %u but no handler\n", | ||
443 | baseirq + irq); | ||
444 | |||
445 | mask |= 1 << irq; | ||
446 | |||
447 | ret = mc13783_reg_write(mc13783, offmask, mask); | ||
448 | } | ||
449 | } | ||
450 | |||
451 | return num_handled; | ||
452 | } | ||
453 | |||
454 | static irqreturn_t mc13783_irq_thread(int irq, void *data) | ||
455 | { | ||
456 | struct mc13783 *mc13783 = data; | ||
457 | irqreturn_t ret; | ||
458 | int handled = 0; | ||
459 | |||
460 | mc13783_lock(mc13783); | ||
461 | |||
462 | ret = mc13783_irq_handle(mc13783, MC13783_IRQSTAT0, | ||
463 | MC13783_IRQMASK0, MC13783_IRQ_ADCDONE); | ||
464 | if (ret > 0) | ||
465 | handled = 1; | ||
466 | |||
467 | ret = mc13783_irq_handle(mc13783, MC13783_IRQSTAT1, | ||
468 | MC13783_IRQMASK1, MC13783_IRQ_1HZ); | ||
469 | if (ret > 0) | ||
470 | handled = 1; | ||
471 | |||
472 | mc13783_unlock(mc13783); | ||
473 | |||
474 | return IRQ_RETVAL(handled); | ||
475 | } | ||
476 | |||
477 | #define MC13783_ADC1_CHAN0_SHIFT 5 | ||
478 | #define MC13783_ADC1_CHAN1_SHIFT 8 | ||
479 | |||
480 | struct mc13783_adcdone_data { | ||
481 | struct mc13783 *mc13783; | ||
482 | struct completion done; | ||
483 | }; | ||
484 | |||
485 | static irqreturn_t mc13783_handler_adcdone(int irq, void *data) | ||
486 | { | ||
487 | struct mc13783_adcdone_data *adcdone_data = data; | ||
488 | |||
489 | mc13783_irq_ack(adcdone_data->mc13783, irq); | ||
490 | |||
491 | complete_all(&adcdone_data->done); | ||
492 | |||
493 | return IRQ_HANDLED; | ||
494 | } | ||
495 | |||
496 | #define MC13783_ADC_WORKING (1 << 16) | ||
497 | |||
498 | int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, | ||
499 | unsigned int channel, unsigned int *sample) | ||
500 | { | ||
501 | u32 adc0, adc1, old_adc0; | ||
502 | int i, ret; | ||
503 | struct mc13783_adcdone_data adcdone_data = { | ||
504 | .mc13783 = mc13783, | ||
505 | }; | ||
506 | init_completion(&adcdone_data.done); | ||
507 | |||
508 | dev_dbg(&mc13783->spidev->dev, "%s\n", __func__); | ||
509 | |||
510 | mc13783_lock(mc13783); | ||
511 | |||
512 | if (mc13783->flags & MC13783_ADC_WORKING) { | ||
513 | ret = -EBUSY; | ||
514 | goto out; | ||
515 | } | ||
516 | |||
517 | mc13783->flags |= MC13783_ADC_WORKING; | ||
518 | |||
519 | mc13783_reg_read(mc13783, MC13783_ADC0, &old_adc0); | ||
520 | |||
521 | adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2; | ||
522 | adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN | MC13783_ADC1_ASC; | ||
523 | |||
524 | if (channel > 7) | ||
525 | adc1 |= MC13783_ADC1_ADSEL; | ||
526 | |||
527 | switch (mode) { | ||
528 | case MC13783_ADC_MODE_TS: | ||
529 | adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_TSMOD0 | | ||
530 | MC13783_ADC0_TSMOD1; | ||
531 | adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | ||
532 | break; | ||
533 | |||
534 | case MC13783_ADC_MODE_SINGLE_CHAN: | ||
535 | adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; | ||
536 | adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT; | ||
537 | adc1 |= MC13783_ADC1_RAND; | ||
538 | break; | ||
539 | |||
540 | case MC13783_ADC_MODE_MULT_CHAN: | ||
541 | adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; | ||
542 | adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | ||
543 | break; | ||
544 | |||
545 | default: | ||
546 | mc13783_unlock(mc13783); | ||
547 | return -EINVAL; | ||
548 | } | ||
549 | |||
550 | dev_dbg(&mc13783->spidev->dev, "%s: request irq\n", __func__); | ||
551 | mc13783_irq_request(mc13783, MC13783_IRQ_ADCDONE, | ||
552 | mc13783_handler_adcdone, __func__, &adcdone_data); | ||
553 | mc13783_irq_ack(mc13783, MC13783_IRQ_ADCDONE); | ||
554 | |||
555 | mc13783_reg_write(mc13783, MC13783_REG_ADC_0, adc0); | ||
556 | mc13783_reg_write(mc13783, MC13783_REG_ADC_1, adc1); | ||
557 | |||
558 | mc13783_unlock(mc13783); | ||
559 | |||
560 | ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ); | ||
561 | |||
562 | if (!ret) | ||
563 | ret = -ETIMEDOUT; | ||
564 | |||
565 | mc13783_lock(mc13783); | ||
566 | |||
567 | mc13783_irq_free(mc13783, MC13783_IRQ_ADCDONE, &adcdone_data); | ||
568 | |||
569 | if (ret > 0) | ||
570 | for (i = 0; i < 4; ++i) { | ||
571 | ret = mc13783_reg_read(mc13783, | ||
572 | MC13783_REG_ADC_2, &sample[i]); | ||
573 | if (ret) | ||
574 | break; | ||
575 | } | ||
576 | |||
577 | if (mode == MC13783_ADC_MODE_TS) | ||
578 | /* restore TSMOD */ | ||
579 | mc13783_reg_write(mc13783, MC13783_REG_ADC_0, old_adc0); | ||
580 | |||
581 | mc13783->flags &= ~MC13783_ADC_WORKING; | ||
582 | out: | ||
583 | mc13783_unlock(mc13783); | ||
584 | |||
585 | return ret; | ||
586 | } | ||
587 | EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); | ||
588 | |||
589 | static int mc13783_add_subdevice_pdata(struct mc13783 *mc13783, | ||
590 | const char *name, void *pdata, size_t pdata_size) | ||
591 | { | ||
592 | struct mfd_cell cell = { | ||
593 | .name = name, | ||
594 | .platform_data = pdata, | ||
595 | .data_size = pdata_size, | ||
596 | }; | ||
597 | |||
598 | return mfd_add_devices(&mc13783->spidev->dev, -1, &cell, 1, NULL, 0); | ||
599 | } | ||
600 | |||
601 | static int mc13783_add_subdevice(struct mc13783 *mc13783, const char *name) | ||
602 | { | ||
603 | return mc13783_add_subdevice_pdata(mc13783, name, NULL, 0); | ||
604 | } | ||
605 | |||
606 | static int mc13783_check_revision(struct mc13783 *mc13783) | ||
607 | { | ||
608 | u32 rev_id, rev1, rev2, finid, icid; | ||
609 | |||
610 | mc13783_reg_read(mc13783, MC13783_REG_REVISION, &rev_id); | ||
611 | |||
612 | rev1 = (rev_id & 0x018) >> 3; | ||
613 | rev2 = (rev_id & 0x007); | ||
614 | icid = (rev_id & 0x01C0) >> 6; | ||
615 | finid = (rev_id & 0x01E00) >> 9; | ||
616 | |||
617 | /* Ver 0.2 is actually 3.2a. Report as 3.2 */ | ||
618 | if ((rev1 == 0) && (rev2 == 2)) | ||
619 | rev1 = 3; | ||
620 | |||
621 | if (rev1 == 0 || icid != 2) { | ||
622 | dev_err(&mc13783->spidev->dev, "No MC13783 detected.\n"); | ||
623 | return -ENODEV; | ||
624 | } | ||
625 | |||
626 | dev_info(&mc13783->spidev->dev, | ||
627 | "MC13783 Rev %d.%d FinVer %x detected\n", | ||
628 | rev1, rev2, finid); | ||
629 | |||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | static int mc13783_probe(struct spi_device *spi) | ||
634 | { | ||
635 | struct mc13783 *mc13783; | ||
636 | struct mc13783_platform_data *pdata = dev_get_platdata(&spi->dev); | ||
637 | int ret; | ||
638 | |||
639 | mc13783 = kzalloc(sizeof(*mc13783), GFP_KERNEL); | ||
640 | if (!mc13783) | ||
641 | return -ENOMEM; | ||
642 | |||
643 | dev_set_drvdata(&spi->dev, mc13783); | ||
644 | spi->mode = SPI_MODE_0 | SPI_CS_HIGH; | ||
645 | spi->bits_per_word = 32; | ||
646 | spi_setup(spi); | ||
647 | |||
648 | mc13783->spidev = spi; | ||
649 | |||
650 | mutex_init(&mc13783->lock); | ||
651 | mc13783_lock(mc13783); | ||
652 | |||
653 | ret = mc13783_check_revision(mc13783); | ||
654 | if (ret) | ||
655 | goto err_revision; | ||
656 | |||
657 | /* mask all irqs */ | ||
658 | ret = mc13783_reg_write(mc13783, MC13783_IRQMASK0, 0x00ffffff); | ||
659 | if (ret) | ||
660 | goto err_mask; | ||
661 | |||
662 | ret = mc13783_reg_write(mc13783, MC13783_IRQMASK1, 0x00ffffff); | ||
663 | if (ret) | ||
664 | goto err_mask; | ||
665 | |||
666 | ret = request_threaded_irq(spi->irq, NULL, mc13783_irq_thread, | ||
667 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13783", mc13783); | ||
668 | |||
669 | if (ret) { | ||
670 | err_mask: | ||
671 | err_revision: | ||
672 | mutex_unlock(&mc13783->lock); | ||
673 | dev_set_drvdata(&spi->dev, NULL); | ||
674 | kfree(mc13783); | ||
675 | return ret; | ||
676 | } | ||
677 | |||
678 | /* This should go away (BEGIN) */ | ||
679 | if (pdata) { | ||
680 | mc13783->flags = pdata->flags; | ||
681 | mc13783->regulators = pdata->regulators; | ||
682 | mc13783->num_regulators = pdata->num_regulators; | ||
683 | } | ||
684 | /* This should go away (END) */ | ||
685 | |||
686 | mc13783_unlock(mc13783); | ||
687 | |||
688 | if (pdata->flags & MC13783_USE_ADC) | ||
689 | mc13783_add_subdevice(mc13783, "mc13783-adc"); | ||
690 | |||
691 | if (pdata->flags & MC13783_USE_CODEC) | ||
692 | mc13783_add_subdevice(mc13783, "mc13783-codec"); | ||
693 | |||
694 | if (pdata->flags & MC13783_USE_REGULATOR) { | ||
695 | struct mc13783_regulator_platform_data regulator_pdata = { | ||
696 | .num_regulators = pdata->num_regulators, | ||
697 | .regulators = pdata->regulators, | ||
698 | }; | ||
699 | |||
700 | mc13783_add_subdevice_pdata(mc13783, "mc13783-regulator", | ||
701 | ®ulator_pdata, sizeof(regulator_pdata)); | ||
702 | } | ||
703 | |||
704 | if (pdata->flags & MC13783_USE_RTC) | ||
705 | mc13783_add_subdevice(mc13783, "mc13783-rtc"); | ||
706 | |||
707 | if (pdata->flags & MC13783_USE_TOUCHSCREEN) | ||
708 | mc13783_add_subdevice(mc13783, "mc13783-ts"); | ||
709 | |||
710 | if (pdata->flags & MC13783_USE_LED) | ||
711 | mc13783_add_subdevice_pdata(mc13783, "mc13783-led", | ||
712 | pdata->leds, sizeof(*pdata->leds)); | ||
713 | |||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | static int __devexit mc13783_remove(struct spi_device *spi) | ||
718 | { | ||
719 | struct mc13783 *mc13783 = dev_get_drvdata(&spi->dev); | ||
720 | |||
721 | free_irq(mc13783->spidev->irq, mc13783); | ||
722 | |||
723 | mfd_remove_devices(&spi->dev); | ||
724 | |||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | static struct spi_driver mc13783_driver = { | ||
729 | .driver = { | ||
730 | .name = "mc13783", | ||
731 | .bus = &spi_bus_type, | ||
732 | .owner = THIS_MODULE, | ||
733 | }, | ||
734 | .probe = mc13783_probe, | ||
735 | .remove = __devexit_p(mc13783_remove), | ||
736 | }; | ||
737 | |||
738 | static int __init mc13783_init(void) | ||
739 | { | ||
740 | return spi_register_driver(&mc13783_driver); | ||
741 | } | ||
742 | subsys_initcall(mc13783_init); | ||
743 | |||
744 | static void __exit mc13783_exit(void) | ||
745 | { | ||
746 | spi_unregister_driver(&mc13783_driver); | ||
747 | } | ||
748 | module_exit(mc13783_exit); | ||
749 | |||
750 | MODULE_DESCRIPTION("Core driver for Freescale MC13783 PMIC"); | ||
751 | MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); | ||
752 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c new file mode 100644 index 000000000000..a2ac2ed6d64c --- /dev/null +++ b/drivers/mfd/mc13xxx-core.c | |||
@@ -0,0 +1,840 @@ | |||
1 | /* | ||
2 | * Copyright 2009-2010 Pengutronix | ||
3 | * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> | ||
4 | * | ||
5 | * loosely based on an earlier driver that has | ||
6 | * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it under | ||
9 | * the terms of the GNU General Public License version 2 as published by the | ||
10 | * Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/slab.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/mutex.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/spi/spi.h> | ||
19 | #include <linux/mfd/core.h> | ||
20 | #include <linux/mfd/mc13xxx.h> | ||
21 | |||
22 | struct mc13xxx { | ||
23 | struct spi_device *spidev; | ||
24 | struct mutex lock; | ||
25 | int irq; | ||
26 | |||
27 | irq_handler_t irqhandler[MC13XXX_NUM_IRQ]; | ||
28 | void *irqdata[MC13XXX_NUM_IRQ]; | ||
29 | }; | ||
30 | |||
31 | struct mc13783 { | ||
32 | struct mc13xxx mc13xxx; | ||
33 | |||
34 | int adcflags; | ||
35 | }; | ||
36 | |||
37 | struct mc13xxx *mc13783_to_mc13xxx(struct mc13783 *mc13783) | ||
38 | { | ||
39 | return &mc13783->mc13xxx; | ||
40 | } | ||
41 | EXPORT_SYMBOL(mc13783_to_mc13xxx); | ||
42 | |||
43 | #define MC13XXX_IRQSTAT0 0 | ||
44 | #define MC13XXX_IRQSTAT0_ADCDONEI (1 << 0) | ||
45 | #define MC13XXX_IRQSTAT0_ADCBISDONEI (1 << 1) | ||
46 | #define MC13XXX_IRQSTAT0_TSI (1 << 2) | ||
47 | #define MC13783_IRQSTAT0_WHIGHI (1 << 3) | ||
48 | #define MC13783_IRQSTAT0_WLOWI (1 << 4) | ||
49 | #define MC13XXX_IRQSTAT0_CHGDETI (1 << 6) | ||
50 | #define MC13783_IRQSTAT0_CHGOVI (1 << 7) | ||
51 | #define MC13XXX_IRQSTAT0_CHGREVI (1 << 8) | ||
52 | #define MC13XXX_IRQSTAT0_CHGSHORTI (1 << 9) | ||
53 | #define MC13XXX_IRQSTAT0_CCCVI (1 << 10) | ||
54 | #define MC13XXX_IRQSTAT0_CHGCURRI (1 << 11) | ||
55 | #define MC13XXX_IRQSTAT0_BPONI (1 << 12) | ||
56 | #define MC13XXX_IRQSTAT0_LOBATLI (1 << 13) | ||
57 | #define MC13XXX_IRQSTAT0_LOBATHI (1 << 14) | ||
58 | #define MC13783_IRQSTAT0_UDPI (1 << 15) | ||
59 | #define MC13783_IRQSTAT0_USBI (1 << 16) | ||
60 | #define MC13783_IRQSTAT0_IDI (1 << 19) | ||
61 | #define MC13783_IRQSTAT0_SE1I (1 << 21) | ||
62 | #define MC13783_IRQSTAT0_CKDETI (1 << 22) | ||
63 | #define MC13783_IRQSTAT0_UDMI (1 << 23) | ||
64 | |||
65 | #define MC13XXX_IRQMASK0 1 | ||
66 | #define MC13XXX_IRQMASK0_ADCDONEM MC13XXX_IRQSTAT0_ADCDONEI | ||
67 | #define MC13XXX_IRQMASK0_ADCBISDONEM MC13XXX_IRQSTAT0_ADCBISDONEI | ||
68 | #define MC13XXX_IRQMASK0_TSM MC13XXX_IRQSTAT0_TSI | ||
69 | #define MC13783_IRQMASK0_WHIGHM MC13783_IRQSTAT0_WHIGHI | ||
70 | #define MC13783_IRQMASK0_WLOWM MC13783_IRQSTAT0_WLOWI | ||
71 | #define MC13XXX_IRQMASK0_CHGDETM MC13XXX_IRQSTAT0_CHGDETI | ||
72 | #define MC13783_IRQMASK0_CHGOVM MC13783_IRQSTAT0_CHGOVI | ||
73 | #define MC13XXX_IRQMASK0_CHGREVM MC13XXX_IRQSTAT0_CHGREVI | ||
74 | #define MC13XXX_IRQMASK0_CHGSHORTM MC13XXX_IRQSTAT0_CHGSHORTI | ||
75 | #define MC13XXX_IRQMASK0_CCCVM MC13XXX_IRQSTAT0_CCCVI | ||
76 | #define MC13XXX_IRQMASK0_CHGCURRM MC13XXX_IRQSTAT0_CHGCURRI | ||
77 | #define MC13XXX_IRQMASK0_BPONM MC13XXX_IRQSTAT0_BPONI | ||
78 | #define MC13XXX_IRQMASK0_LOBATLM MC13XXX_IRQSTAT0_LOBATLI | ||
79 | #define MC13XXX_IRQMASK0_LOBATHM MC13XXX_IRQSTAT0_LOBATHI | ||
80 | #define MC13783_IRQMASK0_UDPM MC13783_IRQSTAT0_UDPI | ||
81 | #define MC13783_IRQMASK0_USBM MC13783_IRQSTAT0_USBI | ||
82 | #define MC13783_IRQMASK0_IDM MC13783_IRQSTAT0_IDI | ||
83 | #define MC13783_IRQMASK0_SE1M MC13783_IRQSTAT0_SE1I | ||
84 | #define MC13783_IRQMASK0_CKDETM MC13783_IRQSTAT0_CKDETI | ||
85 | #define MC13783_IRQMASK0_UDMM MC13783_IRQSTAT0_UDMI | ||
86 | |||
87 | #define MC13XXX_IRQSTAT1 3 | ||
88 | #define MC13XXX_IRQSTAT1_1HZI (1 << 0) | ||
89 | #define MC13XXX_IRQSTAT1_TODAI (1 << 1) | ||
90 | #define MC13783_IRQSTAT1_ONOFD1I (1 << 3) | ||
91 | #define MC13783_IRQSTAT1_ONOFD2I (1 << 4) | ||
92 | #define MC13783_IRQSTAT1_ONOFD3I (1 << 5) | ||
93 | #define MC13XXX_IRQSTAT1_SYSRSTI (1 << 6) | ||
94 | #define MC13XXX_IRQSTAT1_RTCRSTI (1 << 7) | ||
95 | #define MC13XXX_IRQSTAT1_PCI (1 << 8) | ||
96 | #define MC13XXX_IRQSTAT1_WARMI (1 << 9) | ||
97 | #define MC13XXX_IRQSTAT1_MEMHLDI (1 << 10) | ||
98 | #define MC13783_IRQSTAT1_PWRRDYI (1 << 11) | ||
99 | #define MC13XXX_IRQSTAT1_THWARNLI (1 << 12) | ||
100 | #define MC13XXX_IRQSTAT1_THWARNHI (1 << 13) | ||
101 | #define MC13XXX_IRQSTAT1_CLKI (1 << 14) | ||
102 | #define MC13783_IRQSTAT1_SEMAFI (1 << 15) | ||
103 | #define MC13783_IRQSTAT1_MC2BI (1 << 17) | ||
104 | #define MC13783_IRQSTAT1_HSDETI (1 << 18) | ||
105 | #define MC13783_IRQSTAT1_HSLI (1 << 19) | ||
106 | #define MC13783_IRQSTAT1_ALSPTHI (1 << 20) | ||
107 | #define MC13783_IRQSTAT1_AHSSHORTI (1 << 21) | ||
108 | |||
109 | #define MC13XXX_IRQMASK1 4 | ||
110 | #define MC13XXX_IRQMASK1_1HZM MC13XXX_IRQSTAT1_1HZI | ||
111 | #define MC13XXX_IRQMASK1_TODAM MC13XXX_IRQSTAT1_TODAI | ||
112 | #define MC13783_IRQMASK1_ONOFD1M MC13783_IRQSTAT1_ONOFD1I | ||
113 | #define MC13783_IRQMASK1_ONOFD2M MC13783_IRQSTAT1_ONOFD2I | ||
114 | #define MC13783_IRQMASK1_ONOFD3M MC13783_IRQSTAT1_ONOFD3I | ||
115 | #define MC13XXX_IRQMASK1_SYSRSTM MC13XXX_IRQSTAT1_SYSRSTI | ||
116 | #define MC13XXX_IRQMASK1_RTCRSTM MC13XXX_IRQSTAT1_RTCRSTI | ||
117 | #define MC13XXX_IRQMASK1_PCM MC13XXX_IRQSTAT1_PCI | ||
118 | #define MC13XXX_IRQMASK1_WARMM MC13XXX_IRQSTAT1_WARMI | ||
119 | #define MC13XXX_IRQMASK1_MEMHLDM MC13XXX_IRQSTAT1_MEMHLDI | ||
120 | #define MC13783_IRQMASK1_PWRRDYM MC13783_IRQSTAT1_PWRRDYI | ||
121 | #define MC13XXX_IRQMASK1_THWARNLM MC13XXX_IRQSTAT1_THWARNLI | ||
122 | #define MC13XXX_IRQMASK1_THWARNHM MC13XXX_IRQSTAT1_THWARNHI | ||
123 | #define MC13XXX_IRQMASK1_CLKM MC13XXX_IRQSTAT1_CLKI | ||
124 | #define MC13783_IRQMASK1_SEMAFM MC13783_IRQSTAT1_SEMAFI | ||
125 | #define MC13783_IRQMASK1_MC2BM MC13783_IRQSTAT1_MC2BI | ||
126 | #define MC13783_IRQMASK1_HSDETM MC13783_IRQSTAT1_HSDETI | ||
127 | #define MC13783_IRQMASK1_HSLM MC13783_IRQSTAT1_HSLI | ||
128 | #define MC13783_IRQMASK1_ALSPTHM MC13783_IRQSTAT1_ALSPTHI | ||
129 | #define MC13783_IRQMASK1_AHSSHORTM MC13783_IRQSTAT1_AHSSHORTI | ||
130 | |||
131 | #define MC13XXX_REVISION 7 | ||
132 | #define MC13XXX_REVISION_REVMETAL (0x07 << 0) | ||
133 | #define MC13XXX_REVISION_REVFULL (0x03 << 3) | ||
134 | #define MC13XXX_REVISION_ICID (0x07 << 6) | ||
135 | #define MC13XXX_REVISION_FIN (0x03 << 9) | ||
136 | #define MC13XXX_REVISION_FAB (0x03 << 11) | ||
137 | #define MC13XXX_REVISION_ICIDCODE (0x3f << 13) | ||
138 | |||
139 | #define MC13783_ADC1 44 | ||
140 | #define MC13783_ADC1_ADEN (1 << 0) | ||
141 | #define MC13783_ADC1_RAND (1 << 1) | ||
142 | #define MC13783_ADC1_ADSEL (1 << 3) | ||
143 | #define MC13783_ADC1_ASC (1 << 20) | ||
144 | #define MC13783_ADC1_ADTRIGIGN (1 << 21) | ||
145 | |||
146 | #define MC13783_ADC2 45 | ||
147 | |||
148 | #define MC13XXX_NUMREGS 0x3f | ||
149 | |||
150 | void mc13xxx_lock(struct mc13xxx *mc13xxx) | ||
151 | { | ||
152 | if (!mutex_trylock(&mc13xxx->lock)) { | ||
153 | dev_dbg(&mc13xxx->spidev->dev, "wait for %s from %pf\n", | ||
154 | __func__, __builtin_return_address(0)); | ||
155 | |||
156 | mutex_lock(&mc13xxx->lock); | ||
157 | } | ||
158 | dev_dbg(&mc13xxx->spidev->dev, "%s from %pf\n", | ||
159 | __func__, __builtin_return_address(0)); | ||
160 | } | ||
161 | EXPORT_SYMBOL(mc13xxx_lock); | ||
162 | |||
163 | void mc13xxx_unlock(struct mc13xxx *mc13xxx) | ||
164 | { | ||
165 | dev_dbg(&mc13xxx->spidev->dev, "%s from %pf\n", | ||
166 | __func__, __builtin_return_address(0)); | ||
167 | mutex_unlock(&mc13xxx->lock); | ||
168 | } | ||
169 | EXPORT_SYMBOL(mc13xxx_unlock); | ||
170 | |||
171 | #define MC13XXX_REGOFFSET_SHIFT 25 | ||
172 | int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val) | ||
173 | { | ||
174 | struct spi_transfer t; | ||
175 | struct spi_message m; | ||
176 | int ret; | ||
177 | |||
178 | BUG_ON(!mutex_is_locked(&mc13xxx->lock)); | ||
179 | |||
180 | if (offset > MC13XXX_NUMREGS) | ||
181 | return -EINVAL; | ||
182 | |||
183 | *val = offset << MC13XXX_REGOFFSET_SHIFT; | ||
184 | |||
185 | memset(&t, 0, sizeof(t)); | ||
186 | |||
187 | t.tx_buf = val; | ||
188 | t.rx_buf = val; | ||
189 | t.len = sizeof(u32); | ||
190 | |||
191 | spi_message_init(&m); | ||
192 | spi_message_add_tail(&t, &m); | ||
193 | |||
194 | ret = spi_sync(mc13xxx->spidev, &m); | ||
195 | |||
196 | /* error in message.status implies error return from spi_sync */ | ||
197 | BUG_ON(!ret && m.status); | ||
198 | |||
199 | if (ret) | ||
200 | return ret; | ||
201 | |||
202 | *val &= 0xffffff; | ||
203 | |||
204 | dev_vdbg(&mc13xxx->spidev->dev, "[0x%02x] -> 0x%06x\n", offset, *val); | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | EXPORT_SYMBOL(mc13xxx_reg_read); | ||
209 | |||
210 | int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val) | ||
211 | { | ||
212 | u32 buf; | ||
213 | struct spi_transfer t; | ||
214 | struct spi_message m; | ||
215 | int ret; | ||
216 | |||
217 | BUG_ON(!mutex_is_locked(&mc13xxx->lock)); | ||
218 | |||
219 | dev_vdbg(&mc13xxx->spidev->dev, "[0x%02x] <- 0x%06x\n", offset, val); | ||
220 | |||
221 | if (offset > MC13XXX_NUMREGS || val > 0xffffff) | ||
222 | return -EINVAL; | ||
223 | |||
224 | buf = 1 << 31 | offset << MC13XXX_REGOFFSET_SHIFT | val; | ||
225 | |||
226 | memset(&t, 0, sizeof(t)); | ||
227 | |||
228 | t.tx_buf = &buf; | ||
229 | t.rx_buf = &buf; | ||
230 | t.len = sizeof(u32); | ||
231 | |||
232 | spi_message_init(&m); | ||
233 | spi_message_add_tail(&t, &m); | ||
234 | |||
235 | ret = spi_sync(mc13xxx->spidev, &m); | ||
236 | |||
237 | BUG_ON(!ret && m.status); | ||
238 | |||
239 | if (ret) | ||
240 | return ret; | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | EXPORT_SYMBOL(mc13xxx_reg_write); | ||
245 | |||
246 | int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset, | ||
247 | u32 mask, u32 val) | ||
248 | { | ||
249 | int ret; | ||
250 | u32 valread; | ||
251 | |||
252 | BUG_ON(val & ~mask); | ||
253 | |||
254 | ret = mc13xxx_reg_read(mc13xxx, offset, &valread); | ||
255 | if (ret) | ||
256 | return ret; | ||
257 | |||
258 | valread = (valread & ~mask) | val; | ||
259 | |||
260 | return mc13xxx_reg_write(mc13xxx, offset, valread); | ||
261 | } | ||
262 | EXPORT_SYMBOL(mc13xxx_reg_rmw); | ||
263 | |||
264 | int mc13xxx_irq_mask(struct mc13xxx *mc13xxx, int irq) | ||
265 | { | ||
266 | int ret; | ||
267 | unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1; | ||
268 | u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | ||
269 | u32 mask; | ||
270 | |||
271 | if (irq < 0 || irq >= MC13XXX_NUM_IRQ) | ||
272 | return -EINVAL; | ||
273 | |||
274 | ret = mc13xxx_reg_read(mc13xxx, offmask, &mask); | ||
275 | if (ret) | ||
276 | return ret; | ||
277 | |||
278 | if (mask & irqbit) | ||
279 | /* already masked */ | ||
280 | return 0; | ||
281 | |||
282 | return mc13xxx_reg_write(mc13xxx, offmask, mask | irqbit); | ||
283 | } | ||
284 | EXPORT_SYMBOL(mc13xxx_irq_mask); | ||
285 | |||
286 | int mc13xxx_irq_unmask(struct mc13xxx *mc13xxx, int irq) | ||
287 | { | ||
288 | int ret; | ||
289 | unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1; | ||
290 | u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | ||
291 | u32 mask; | ||
292 | |||
293 | if (irq < 0 || irq >= MC13XXX_NUM_IRQ) | ||
294 | return -EINVAL; | ||
295 | |||
296 | ret = mc13xxx_reg_read(mc13xxx, offmask, &mask); | ||
297 | if (ret) | ||
298 | return ret; | ||
299 | |||
300 | if (!(mask & irqbit)) | ||
301 | /* already unmasked */ | ||
302 | return 0; | ||
303 | |||
304 | return mc13xxx_reg_write(mc13xxx, offmask, mask & ~irqbit); | ||
305 | } | ||
306 | EXPORT_SYMBOL(mc13xxx_irq_unmask); | ||
307 | |||
308 | int mc13xxx_irq_status(struct mc13xxx *mc13xxx, int irq, | ||
309 | int *enabled, int *pending) | ||
310 | { | ||
311 | int ret; | ||
312 | unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1; | ||
313 | unsigned int offstat = irq < 24 ? MC13XXX_IRQSTAT0 : MC13XXX_IRQSTAT1; | ||
314 | u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | ||
315 | |||
316 | if (irq < 0 || irq >= MC13XXX_NUM_IRQ) | ||
317 | return -EINVAL; | ||
318 | |||
319 | if (enabled) { | ||
320 | u32 mask; | ||
321 | |||
322 | ret = mc13xxx_reg_read(mc13xxx, offmask, &mask); | ||
323 | if (ret) | ||
324 | return ret; | ||
325 | |||
326 | *enabled = mask & irqbit; | ||
327 | } | ||
328 | |||
329 | if (pending) { | ||
330 | u32 stat; | ||
331 | |||
332 | ret = mc13xxx_reg_read(mc13xxx, offstat, &stat); | ||
333 | if (ret) | ||
334 | return ret; | ||
335 | |||
336 | *pending = stat & irqbit; | ||
337 | } | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | EXPORT_SYMBOL(mc13xxx_irq_status); | ||
342 | |||
343 | int mc13xxx_irq_ack(struct mc13xxx *mc13xxx, int irq) | ||
344 | { | ||
345 | unsigned int offstat = irq < 24 ? MC13XXX_IRQSTAT0 : MC13XXX_IRQSTAT1; | ||
346 | unsigned int val = 1 << (irq < 24 ? irq : irq - 24); | ||
347 | |||
348 | BUG_ON(irq < 0 || irq >= MC13XXX_NUM_IRQ); | ||
349 | |||
350 | return mc13xxx_reg_write(mc13xxx, offstat, val); | ||
351 | } | ||
352 | EXPORT_SYMBOL(mc13xxx_irq_ack); | ||
353 | |||
354 | int mc13xxx_irq_request_nounmask(struct mc13xxx *mc13xxx, int irq, | ||
355 | irq_handler_t handler, const char *name, void *dev) | ||
356 | { | ||
357 | BUG_ON(!mutex_is_locked(&mc13xxx->lock)); | ||
358 | BUG_ON(!handler); | ||
359 | |||
360 | if (irq < 0 || irq >= MC13XXX_NUM_IRQ) | ||
361 | return -EINVAL; | ||
362 | |||
363 | if (mc13xxx->irqhandler[irq]) | ||
364 | return -EBUSY; | ||
365 | |||
366 | mc13xxx->irqhandler[irq] = handler; | ||
367 | mc13xxx->irqdata[irq] = dev; | ||
368 | |||
369 | return 0; | ||
370 | } | ||
371 | EXPORT_SYMBOL(mc13xxx_irq_request_nounmask); | ||
372 | |||
373 | int mc13xxx_irq_request(struct mc13xxx *mc13xxx, int irq, | ||
374 | irq_handler_t handler, const char *name, void *dev) | ||
375 | { | ||
376 | int ret; | ||
377 | |||
378 | ret = mc13xxx_irq_request_nounmask(mc13xxx, irq, handler, name, dev); | ||
379 | if (ret) | ||
380 | return ret; | ||
381 | |||
382 | ret = mc13xxx_irq_unmask(mc13xxx, irq); | ||
383 | if (ret) { | ||
384 | mc13xxx->irqhandler[irq] = NULL; | ||
385 | mc13xxx->irqdata[irq] = NULL; | ||
386 | return ret; | ||
387 | } | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | EXPORT_SYMBOL(mc13xxx_irq_request); | ||
392 | |||
393 | int mc13xxx_irq_free(struct mc13xxx *mc13xxx, int irq, void *dev) | ||
394 | { | ||
395 | int ret; | ||
396 | BUG_ON(!mutex_is_locked(&mc13xxx->lock)); | ||
397 | |||
398 | if (irq < 0 || irq >= MC13XXX_NUM_IRQ || !mc13xxx->irqhandler[irq] || | ||
399 | mc13xxx->irqdata[irq] != dev) | ||
400 | return -EINVAL; | ||
401 | |||
402 | ret = mc13xxx_irq_mask(mc13xxx, irq); | ||
403 | if (ret) | ||
404 | return ret; | ||
405 | |||
406 | mc13xxx->irqhandler[irq] = NULL; | ||
407 | mc13xxx->irqdata[irq] = NULL; | ||
408 | |||
409 | return 0; | ||
410 | } | ||
411 | EXPORT_SYMBOL(mc13xxx_irq_free); | ||
412 | |||
413 | static inline irqreturn_t mc13xxx_irqhandler(struct mc13xxx *mc13xxx, int irq) | ||
414 | { | ||
415 | return mc13xxx->irqhandler[irq](irq, mc13xxx->irqdata[irq]); | ||
416 | } | ||
417 | |||
418 | /* | ||
419 | * returns: number of handled irqs or negative error | ||
420 | * locking: holds mc13xxx->lock | ||
421 | */ | ||
422 | static int mc13xxx_irq_handle(struct mc13xxx *mc13xxx, | ||
423 | unsigned int offstat, unsigned int offmask, int baseirq) | ||
424 | { | ||
425 | u32 stat, mask; | ||
426 | int ret = mc13xxx_reg_read(mc13xxx, offstat, &stat); | ||
427 | int num_handled = 0; | ||
428 | |||
429 | if (ret) | ||
430 | return ret; | ||
431 | |||
432 | ret = mc13xxx_reg_read(mc13xxx, offmask, &mask); | ||
433 | if (ret) | ||
434 | return ret; | ||
435 | |||
436 | while (stat & ~mask) { | ||
437 | int irq = __ffs(stat & ~mask); | ||
438 | |||
439 | stat &= ~(1 << irq); | ||
440 | |||
441 | if (likely(mc13xxx->irqhandler[baseirq + irq])) { | ||
442 | irqreturn_t handled; | ||
443 | |||
444 | handled = mc13xxx_irqhandler(mc13xxx, baseirq + irq); | ||
445 | if (handled == IRQ_HANDLED) | ||
446 | num_handled++; | ||
447 | } else { | ||
448 | dev_err(&mc13xxx->spidev->dev, | ||
449 | "BUG: irq %u but no handler\n", | ||
450 | baseirq + irq); | ||
451 | |||
452 | mask |= 1 << irq; | ||
453 | |||
454 | ret = mc13xxx_reg_write(mc13xxx, offmask, mask); | ||
455 | } | ||
456 | } | ||
457 | |||
458 | return num_handled; | ||
459 | } | ||
460 | |||
461 | static irqreturn_t mc13xxx_irq_thread(int irq, void *data) | ||
462 | { | ||
463 | struct mc13xxx *mc13xxx = data; | ||
464 | irqreturn_t ret; | ||
465 | int handled = 0; | ||
466 | |||
467 | mc13xxx_lock(mc13xxx); | ||
468 | |||
469 | ret = mc13xxx_irq_handle(mc13xxx, MC13XXX_IRQSTAT0, | ||
470 | MC13XXX_IRQMASK0, 0); | ||
471 | if (ret > 0) | ||
472 | handled = 1; | ||
473 | |||
474 | ret = mc13xxx_irq_handle(mc13xxx, MC13XXX_IRQSTAT1, | ||
475 | MC13XXX_IRQMASK1, 24); | ||
476 | if (ret > 0) | ||
477 | handled = 1; | ||
478 | |||
479 | mc13xxx_unlock(mc13xxx); | ||
480 | |||
481 | return IRQ_RETVAL(handled); | ||
482 | } | ||
483 | |||
484 | enum mc13xxx_id { | ||
485 | MC13XXX_ID_MC13783, | ||
486 | MC13XXX_ID_MC13892, | ||
487 | MC13XXX_ID_INVALID, | ||
488 | }; | ||
489 | |||
490 | const char *mc13xxx_chipname[] = { | ||
491 | [MC13XXX_ID_MC13783] = "mc13783", | ||
492 | [MC13XXX_ID_MC13892] = "mc13892", | ||
493 | }; | ||
494 | |||
495 | #define maskval(reg, mask) (((reg) & (mask)) >> __ffs(mask)) | ||
496 | static int mc13xxx_identify(struct mc13xxx *mc13xxx, enum mc13xxx_id *id) | ||
497 | { | ||
498 | u32 icid; | ||
499 | u32 revision; | ||
500 | const char *name; | ||
501 | int ret; | ||
502 | |||
503 | ret = mc13xxx_reg_read(mc13xxx, 46, &icid); | ||
504 | if (ret) | ||
505 | return ret; | ||
506 | |||
507 | icid = (icid >> 6) & 0x7; | ||
508 | |||
509 | switch (icid) { | ||
510 | case 2: | ||
511 | *id = MC13XXX_ID_MC13783; | ||
512 | name = "mc13783"; | ||
513 | break; | ||
514 | case 7: | ||
515 | *id = MC13XXX_ID_MC13892; | ||
516 | name = "mc13892"; | ||
517 | break; | ||
518 | default: | ||
519 | *id = MC13XXX_ID_INVALID; | ||
520 | break; | ||
521 | } | ||
522 | |||
523 | if (*id == MC13XXX_ID_MC13783 || *id == MC13XXX_ID_MC13892) { | ||
524 | ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision); | ||
525 | if (ret) | ||
526 | return ret; | ||
527 | |||
528 | dev_info(&mc13xxx->spidev->dev, "%s: rev: %d.%d, " | ||
529 | "fin: %d, fab: %d, icid: %d/%d\n", | ||
530 | mc13xxx_chipname[*id], | ||
531 | maskval(revision, MC13XXX_REVISION_REVFULL), | ||
532 | maskval(revision, MC13XXX_REVISION_REVMETAL), | ||
533 | maskval(revision, MC13XXX_REVISION_FIN), | ||
534 | maskval(revision, MC13XXX_REVISION_FAB), | ||
535 | maskval(revision, MC13XXX_REVISION_ICID), | ||
536 | maskval(revision, MC13XXX_REVISION_ICIDCODE)); | ||
537 | } | ||
538 | |||
539 | if (*id != MC13XXX_ID_INVALID) { | ||
540 | const struct spi_device_id *devid = | ||
541 | spi_get_device_id(mc13xxx->spidev); | ||
542 | if (!devid || devid->driver_data != *id) | ||
543 | dev_warn(&mc13xxx->spidev->dev, "device id doesn't " | ||
544 | "match auto detection!\n"); | ||
545 | } | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx) | ||
551 | { | ||
552 | const struct spi_device_id *devid = | ||
553 | spi_get_device_id(mc13xxx->spidev); | ||
554 | |||
555 | if (!devid) | ||
556 | return NULL; | ||
557 | |||
558 | return mc13xxx_chipname[devid->driver_data]; | ||
559 | } | ||
560 | |||
561 | #include <linux/mfd/mc13783.h> | ||
562 | |||
563 | int mc13xxx_get_flags(struct mc13xxx *mc13xxx) | ||
564 | { | ||
565 | struct mc13xxx_platform_data *pdata = | ||
566 | dev_get_platdata(&mc13xxx->spidev->dev); | ||
567 | |||
568 | return pdata->flags; | ||
569 | } | ||
570 | EXPORT_SYMBOL(mc13xxx_get_flags); | ||
571 | |||
572 | #define MC13783_ADC1_CHAN0_SHIFT 5 | ||
573 | #define MC13783_ADC1_CHAN1_SHIFT 8 | ||
574 | |||
575 | struct mc13xxx_adcdone_data { | ||
576 | struct mc13xxx *mc13xxx; | ||
577 | struct completion done; | ||
578 | }; | ||
579 | |||
580 | static irqreturn_t mc13783_handler_adcdone(int irq, void *data) | ||
581 | { | ||
582 | struct mc13xxx_adcdone_data *adcdone_data = data; | ||
583 | |||
584 | mc13xxx_irq_ack(adcdone_data->mc13xxx, irq); | ||
585 | |||
586 | complete_all(&adcdone_data->done); | ||
587 | |||
588 | return IRQ_HANDLED; | ||
589 | } | ||
590 | |||
591 | #define MC13783_ADC_WORKING (1 << 0) | ||
592 | |||
593 | int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, | ||
594 | unsigned int channel, unsigned int *sample) | ||
595 | { | ||
596 | struct mc13xxx *mc13xxx = &mc13783->mc13xxx; | ||
597 | u32 adc0, adc1, old_adc0; | ||
598 | int i, ret; | ||
599 | struct mc13xxx_adcdone_data adcdone_data = { | ||
600 | .mc13xxx = mc13xxx, | ||
601 | }; | ||
602 | init_completion(&adcdone_data.done); | ||
603 | |||
604 | dev_dbg(&mc13xxx->spidev->dev, "%s\n", __func__); | ||
605 | |||
606 | mc13xxx_lock(mc13xxx); | ||
607 | |||
608 | if (mc13783->adcflags & MC13783_ADC_WORKING) { | ||
609 | ret = -EBUSY; | ||
610 | goto out; | ||
611 | } | ||
612 | |||
613 | mc13783->adcflags |= MC13783_ADC_WORKING; | ||
614 | |||
615 | mc13xxx_reg_read(mc13xxx, MC13783_ADC0, &old_adc0); | ||
616 | |||
617 | adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2; | ||
618 | adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN | MC13783_ADC1_ASC; | ||
619 | |||
620 | if (channel > 7) | ||
621 | adc1 |= MC13783_ADC1_ADSEL; | ||
622 | |||
623 | switch (mode) { | ||
624 | case MC13783_ADC_MODE_TS: | ||
625 | adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_TSMOD0 | | ||
626 | MC13783_ADC0_TSMOD1; | ||
627 | adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | ||
628 | break; | ||
629 | |||
630 | case MC13783_ADC_MODE_SINGLE_CHAN: | ||
631 | adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; | ||
632 | adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT; | ||
633 | adc1 |= MC13783_ADC1_RAND; | ||
634 | break; | ||
635 | |||
636 | case MC13783_ADC_MODE_MULT_CHAN: | ||
637 | adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; | ||
638 | adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | ||
639 | break; | ||
640 | |||
641 | default: | ||
642 | mc13783_unlock(mc13783); | ||
643 | return -EINVAL; | ||
644 | } | ||
645 | |||
646 | dev_dbg(&mc13783->mc13xxx.spidev->dev, "%s: request irq\n", __func__); | ||
647 | mc13xxx_irq_request(mc13xxx, MC13783_IRQ_ADCDONE, | ||
648 | mc13783_handler_adcdone, __func__, &adcdone_data); | ||
649 | mc13xxx_irq_ack(mc13xxx, MC13783_IRQ_ADCDONE); | ||
650 | |||
651 | mc13xxx_reg_write(mc13xxx, MC13783_ADC0, adc0); | ||
652 | mc13xxx_reg_write(mc13xxx, MC13783_ADC1, adc1); | ||
653 | |||
654 | mc13xxx_unlock(mc13xxx); | ||
655 | |||
656 | ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ); | ||
657 | |||
658 | if (!ret) | ||
659 | ret = -ETIMEDOUT; | ||
660 | |||
661 | mc13xxx_lock(mc13xxx); | ||
662 | |||
663 | mc13xxx_irq_free(mc13xxx, MC13783_IRQ_ADCDONE, &adcdone_data); | ||
664 | |||
665 | if (ret > 0) | ||
666 | for (i = 0; i < 4; ++i) { | ||
667 | ret = mc13xxx_reg_read(mc13xxx, | ||
668 | MC13783_ADC2, &sample[i]); | ||
669 | if (ret) | ||
670 | break; | ||
671 | } | ||
672 | |||
673 | if (mode == MC13783_ADC_MODE_TS) | ||
674 | /* restore TSMOD */ | ||
675 | mc13xxx_reg_write(mc13xxx, MC13783_ADC0, old_adc0); | ||
676 | |||
677 | mc13783->adcflags &= ~MC13783_ADC_WORKING; | ||
678 | out: | ||
679 | mc13xxx_unlock(mc13xxx); | ||
680 | |||
681 | return ret; | ||
682 | } | ||
683 | EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); | ||
684 | |||
685 | static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, | ||
686 | const char *format, void *pdata, size_t pdata_size) | ||
687 | { | ||
688 | char buf[30]; | ||
689 | const char *name = mc13xxx_get_chipname(mc13xxx); | ||
690 | |||
691 | struct mfd_cell cell = { | ||
692 | .platform_data = pdata, | ||
693 | .data_size = pdata_size, | ||
694 | }; | ||
695 | |||
696 | /* there is no asnprintf in the kernel :-( */ | ||
697 | if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf)) | ||
698 | return -E2BIG; | ||
699 | |||
700 | cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL); | ||
701 | if (!cell.name) | ||
702 | return -ENOMEM; | ||
703 | |||
704 | return mfd_add_devices(&mc13xxx->spidev->dev, -1, &cell, 1, NULL, 0); | ||
705 | } | ||
706 | |||
707 | static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) | ||
708 | { | ||
709 | return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0); | ||
710 | } | ||
711 | |||
712 | static int mc13xxx_probe(struct spi_device *spi) | ||
713 | { | ||
714 | struct mc13xxx *mc13xxx; | ||
715 | struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev); | ||
716 | enum mc13xxx_id id; | ||
717 | int ret; | ||
718 | |||
719 | mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL); | ||
720 | if (!mc13xxx) | ||
721 | return -ENOMEM; | ||
722 | |||
723 | dev_set_drvdata(&spi->dev, mc13xxx); | ||
724 | spi->mode = SPI_MODE_0 | SPI_CS_HIGH; | ||
725 | spi->bits_per_word = 32; | ||
726 | spi_setup(spi); | ||
727 | |||
728 | mc13xxx->spidev = spi; | ||
729 | |||
730 | mutex_init(&mc13xxx->lock); | ||
731 | mc13xxx_lock(mc13xxx); | ||
732 | |||
733 | ret = mc13xxx_identify(mc13xxx, &id); | ||
734 | if (ret || id == MC13XXX_ID_INVALID) | ||
735 | goto err_revision; | ||
736 | |||
737 | /* mask all irqs */ | ||
738 | ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK0, 0x00ffffff); | ||
739 | if (ret) | ||
740 | goto err_mask; | ||
741 | |||
742 | ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK1, 0x00ffffff); | ||
743 | if (ret) | ||
744 | goto err_mask; | ||
745 | |||
746 | ret = request_threaded_irq(spi->irq, NULL, mc13xxx_irq_thread, | ||
747 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx); | ||
748 | |||
749 | if (ret) { | ||
750 | err_mask: | ||
751 | err_revision: | ||
752 | mutex_unlock(&mc13xxx->lock); | ||
753 | dev_set_drvdata(&spi->dev, NULL); | ||
754 | kfree(mc13xxx); | ||
755 | return ret; | ||
756 | } | ||
757 | |||
758 | mc13xxx_unlock(mc13xxx); | ||
759 | |||
760 | if (pdata->flags & MC13XXX_USE_ADC) | ||
761 | mc13xxx_add_subdevice(mc13xxx, "%s-adc"); | ||
762 | |||
763 | if (pdata->flags & MC13XXX_USE_CODEC) | ||
764 | mc13xxx_add_subdevice(mc13xxx, "%s-codec"); | ||
765 | |||
766 | if (pdata->flags & MC13XXX_USE_REGULATOR) { | ||
767 | struct mc13xxx_regulator_platform_data regulator_pdata = { | ||
768 | .num_regulators = pdata->num_regulators, | ||
769 | .regulators = pdata->regulators, | ||
770 | }; | ||
771 | |||
772 | mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", | ||
773 | ®ulator_pdata, sizeof(regulator_pdata)); | ||
774 | } | ||
775 | |||
776 | if (pdata->flags & MC13XXX_USE_RTC) | ||
777 | mc13xxx_add_subdevice(mc13xxx, "%s-rtc"); | ||
778 | |||
779 | if (pdata->flags & MC13XXX_USE_TOUCHSCREEN) | ||
780 | mc13xxx_add_subdevice(mc13xxx, "%s-ts"); | ||
781 | |||
782 | if (pdata->flags & MC13XXX_USE_LED) { | ||
783 | mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", | ||
784 | pdata->leds, sizeof(*pdata->leds)); | ||
785 | } | ||
786 | |||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | static int __devexit mc13xxx_remove(struct spi_device *spi) | ||
791 | { | ||
792 | struct mc13xxx *mc13xxx = dev_get_drvdata(&spi->dev); | ||
793 | |||
794 | free_irq(mc13xxx->spidev->irq, mc13xxx); | ||
795 | |||
796 | mfd_remove_devices(&spi->dev); | ||
797 | |||
798 | kfree(mc13xxx); | ||
799 | |||
800 | return 0; | ||
801 | } | ||
802 | |||
803 | static const struct spi_device_id mc13xxx_device_id[] = { | ||
804 | { | ||
805 | .name = "mc13783", | ||
806 | .driver_data = MC13XXX_ID_MC13783, | ||
807 | }, { | ||
808 | .name = "mc13892", | ||
809 | .driver_data = MC13XXX_ID_MC13892, | ||
810 | }, { | ||
811 | /* sentinel */ | ||
812 | } | ||
813 | }; | ||
814 | |||
815 | static struct spi_driver mc13xxx_driver = { | ||
816 | .id_table = mc13xxx_device_id, | ||
817 | .driver = { | ||
818 | .name = "mc13xxx", | ||
819 | .bus = &spi_bus_type, | ||
820 | .owner = THIS_MODULE, | ||
821 | }, | ||
822 | .probe = mc13xxx_probe, | ||
823 | .remove = __devexit_p(mc13xxx_remove), | ||
824 | }; | ||
825 | |||
826 | static int __init mc13xxx_init(void) | ||
827 | { | ||
828 | return spi_register_driver(&mc13xxx_driver); | ||
829 | } | ||
830 | subsys_initcall(mc13xxx_init); | ||
831 | |||
832 | static void __exit mc13xxx_exit(void) | ||
833 | { | ||
834 | spi_unregister_driver(&mc13xxx_driver); | ||
835 | } | ||
836 | module_exit(mc13xxx_exit); | ||
837 | |||
838 | MODULE_DESCRIPTION("Core driver for Freescale MC13XXX PMIC"); | ||
839 | MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); | ||
840 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 1823a57b7d8f..ec99f681e773 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c | |||
@@ -38,10 +38,12 @@ static int mfd_add_device(struct device *parent, int id, | |||
38 | pdev->dev.parent = parent; | 38 | pdev->dev.parent = parent; |
39 | platform_set_drvdata(pdev, cell->driver_data); | 39 | platform_set_drvdata(pdev, cell->driver_data); |
40 | 40 | ||
41 | ret = platform_device_add_data(pdev, | 41 | if (cell->data_size) { |
42 | cell->platform_data, cell->data_size); | 42 | ret = platform_device_add_data(pdev, |
43 | if (ret) | 43 | cell->platform_data, cell->data_size); |
44 | goto fail_res; | 44 | if (ret) |
45 | goto fail_res; | ||
46 | } | ||
45 | 47 | ||
46 | for (r = 0; r < cell->num_resources; r++) { | 48 | for (r = 0; r < cell->num_resources; r++) { |
47 | res[r].name = cell->resources[r].name; | 49 | res[r].name = cell->resources[r].name; |
@@ -65,9 +67,11 @@ static int mfd_add_device(struct device *parent, int id, | |||
65 | res[r].end = cell->resources[r].end; | 67 | res[r].end = cell->resources[r].end; |
66 | } | 68 | } |
67 | 69 | ||
68 | ret = acpi_check_resource_conflict(res); | 70 | if (!cell->ignore_resource_conflicts) { |
69 | if (ret) | 71 | ret = acpi_check_resource_conflict(res); |
70 | goto fail_res; | 72 | if (ret) |
73 | goto fail_res; | ||
74 | } | ||
71 | } | 75 | } |
72 | 76 | ||
73 | ret = platform_device_add_resources(pdev, res, cell->num_resources); | 77 | ret = platform_device_add_resources(pdev, res, cell->num_resources); |
diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index 23e585527285..501ce13b693e 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c | |||
@@ -25,13 +25,6 @@ | |||
25 | 25 | ||
26 | #include <linux/mfd/pcf50633/core.h> | 26 | #include <linux/mfd/pcf50633/core.h> |
27 | 27 | ||
28 | int pcf50633_irq_init(struct pcf50633 *pcf, int irq); | ||
29 | void pcf50633_irq_free(struct pcf50633 *pcf); | ||
30 | #ifdef CONFIG_PM | ||
31 | int pcf50633_irq_suspend(struct pcf50633 *pcf); | ||
32 | int pcf50633_irq_resume(struct pcf50633 *pcf); | ||
33 | #endif | ||
34 | |||
35 | static int __pcf50633_read(struct pcf50633 *pcf, u8 reg, int num, u8 *data) | 28 | static int __pcf50633_read(struct pcf50633 *pcf, u8 reg, int num, u8 *data) |
36 | { | 29 | { |
37 | int ret; | 30 | int ret; |
@@ -346,12 +339,14 @@ static int __devexit pcf50633_remove(struct i2c_client *client) | |||
346 | struct pcf50633 *pcf = i2c_get_clientdata(client); | 339 | struct pcf50633 *pcf = i2c_get_clientdata(client); |
347 | int i; | 340 | int i; |
348 | 341 | ||
342 | sysfs_remove_group(&client->dev.kobj, &pcf_attr_group); | ||
349 | pcf50633_irq_free(pcf); | 343 | pcf50633_irq_free(pcf); |
350 | 344 | ||
351 | platform_device_unregister(pcf->input_pdev); | 345 | platform_device_unregister(pcf->input_pdev); |
352 | platform_device_unregister(pcf->rtc_pdev); | 346 | platform_device_unregister(pcf->rtc_pdev); |
353 | platform_device_unregister(pcf->mbc_pdev); | 347 | platform_device_unregister(pcf->mbc_pdev); |
354 | platform_device_unregister(pcf->adc_pdev); | 348 | platform_device_unregister(pcf->adc_pdev); |
349 | platform_device_unregister(pcf->bl_pdev); | ||
355 | 350 | ||
356 | for (i = 0; i < PCF50633_NUM_REGULATORS; i++) | 351 | for (i = 0; i < PCF50633_NUM_REGULATORS; i++) |
357 | platform_device_unregister(pcf->regulator_pdev[i]); | 352 | platform_device_unregister(pcf->regulator_pdev[i]); |
diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c index 49b4d069cbf9..f1714f93af9d 100644 --- a/drivers/mfd/sh_mobile_sdhi.c +++ b/drivers/mfd/sh_mobile_sdhi.c | |||
@@ -65,6 +65,17 @@ static void sh_mobile_sdhi_set_pwr(struct platform_device *tmio, int state) | |||
65 | p->set_pwr(pdev, state); | 65 | p->set_pwr(pdev, state); |
66 | } | 66 | } |
67 | 67 | ||
68 | static int sh_mobile_sdhi_get_cd(struct platform_device *tmio) | ||
69 | { | ||
70 | struct platform_device *pdev = to_platform_device(tmio->dev.parent); | ||
71 | struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; | ||
72 | |||
73 | if (p && p->get_cd) | ||
74 | return p->get_cd(pdev); | ||
75 | else | ||
76 | return -ENOSYS; | ||
77 | } | ||
78 | |||
68 | static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) | 79 | static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) |
69 | { | 80 | { |
70 | struct sh_mobile_sdhi *priv; | 81 | struct sh_mobile_sdhi *priv; |
@@ -106,12 +117,20 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) | |||
106 | 117 | ||
107 | mmc_data->hclk = clk_get_rate(priv->clk); | 118 | mmc_data->hclk = clk_get_rate(priv->clk); |
108 | mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; | 119 | mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; |
120 | mmc_data->get_cd = sh_mobile_sdhi_get_cd; | ||
109 | mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; | 121 | mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; |
110 | if (p) { | 122 | if (p) { |
111 | mmc_data->flags = p->tmio_flags; | 123 | mmc_data->flags = p->tmio_flags; |
112 | mmc_data->ocr_mask = p->tmio_ocr_mask; | 124 | mmc_data->ocr_mask = p->tmio_ocr_mask; |
125 | mmc_data->capabilities |= p->tmio_caps; | ||
113 | } | 126 | } |
114 | 127 | ||
128 | /* | ||
129 | * All SDHI blocks support 2-byte and larger block sizes in 4-bit | ||
130 | * bus width mode. | ||
131 | */ | ||
132 | mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES; | ||
133 | |||
115 | if (p && p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) { | 134 | if (p && p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) { |
116 | priv->param_tx.slave_id = p->dma_slave_tx; | 135 | priv->param_tx.slave_id = p->dma_slave_tx; |
117 | priv->param_rx.slave_id = p->dma_slave_rx; | 136 | priv->param_rx.slave_id = p->dma_slave_rx; |
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 0754c5e91995..b11487f1e1cb 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c | |||
@@ -873,6 +873,28 @@ static int __devinit stmpe_devices_init(struct stmpe *stmpe) | |||
873 | return ret; | 873 | return ret; |
874 | } | 874 | } |
875 | 875 | ||
876 | #ifdef CONFIG_PM | ||
877 | static int stmpe_suspend(struct device *dev) | ||
878 | { | ||
879 | struct i2c_client *i2c = to_i2c_client(dev); | ||
880 | |||
881 | if (device_may_wakeup(&i2c->dev)) | ||
882 | enable_irq_wake(i2c->irq); | ||
883 | |||
884 | return 0; | ||
885 | } | ||
886 | |||
887 | static int stmpe_resume(struct device *dev) | ||
888 | { | ||
889 | struct i2c_client *i2c = to_i2c_client(dev); | ||
890 | |||
891 | if (device_may_wakeup(&i2c->dev)) | ||
892 | disable_irq_wake(i2c->irq); | ||
893 | |||
894 | return 0; | ||
895 | } | ||
896 | #endif | ||
897 | |||
876 | static int __devinit stmpe_probe(struct i2c_client *i2c, | 898 | static int __devinit stmpe_probe(struct i2c_client *i2c, |
877 | const struct i2c_device_id *id) | 899 | const struct i2c_device_id *id) |
878 | { | 900 | { |
@@ -960,9 +982,19 @@ static const struct i2c_device_id stmpe_id[] = { | |||
960 | }; | 982 | }; |
961 | MODULE_DEVICE_TABLE(i2c, stmpe_id); | 983 | MODULE_DEVICE_TABLE(i2c, stmpe_id); |
962 | 984 | ||
985 | #ifdef CONFIG_PM | ||
986 | static const struct dev_pm_ops stmpe_dev_pm_ops = { | ||
987 | .suspend = stmpe_suspend, | ||
988 | .resume = stmpe_resume, | ||
989 | }; | ||
990 | #endif | ||
991 | |||
963 | static struct i2c_driver stmpe_driver = { | 992 | static struct i2c_driver stmpe_driver = { |
964 | .driver.name = "stmpe", | 993 | .driver.name = "stmpe", |
965 | .driver.owner = THIS_MODULE, | 994 | .driver.owner = THIS_MODULE, |
995 | #ifdef CONFIG_PM | ||
996 | .driver.pm = &stmpe_dev_pm_ops, | ||
997 | #endif | ||
966 | .probe = stmpe_probe, | 998 | .probe = stmpe_probe, |
967 | .remove = __devexit_p(stmpe_remove), | 999 | .remove = __devexit_p(stmpe_remove), |
968 | .id_table = stmpe_id, | 1000 | .id_table = stmpe_id, |
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index ef6c42c8917a..1ea80d8ad915 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c | |||
@@ -155,7 +155,7 @@ static struct resource __devinitdata tc6393xb_nand_resources[] = { | |||
155 | }, | 155 | }, |
156 | }; | 156 | }; |
157 | 157 | ||
158 | static struct resource __devinitdata tc6393xb_mmc_resources[] = { | 158 | static struct resource tc6393xb_mmc_resources[] = { |
159 | { | 159 | { |
160 | .start = 0x800, | 160 | .start = 0x800, |
161 | .end = 0x9ff, | 161 | .end = 0x9ff, |
diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index ac5995026c88..727f62c15a60 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c | |||
@@ -43,6 +43,8 @@ | |||
43 | 43 | ||
44 | #include <linux/timb_dma.h> | 44 | #include <linux/timb_dma.h> |
45 | 45 | ||
46 | #include <linux/ks8842.h> | ||
47 | |||
46 | #include "timberdale.h" | 48 | #include "timberdale.h" |
47 | 49 | ||
48 | #define DRIVER_NAME "timberdale" | 50 | #define DRIVER_NAME "timberdale" |
@@ -161,6 +163,12 @@ static const __devinitconst struct resource timberdale_spi_resources[] = { | |||
161 | }, | 163 | }, |
162 | }; | 164 | }; |
163 | 165 | ||
166 | static __devinitdata struct ks8842_platform_data | ||
167 | timberdale_ks8842_platform_data = { | ||
168 | .rx_dma_channel = DMA_ETH_RX, | ||
169 | .tx_dma_channel = DMA_ETH_TX | ||
170 | }; | ||
171 | |||
164 | static const __devinitconst struct resource timberdale_eth_resources[] = { | 172 | static const __devinitconst struct resource timberdale_eth_resources[] = { |
165 | { | 173 | { |
166 | .start = ETHOFFSET, | 174 | .start = ETHOFFSET, |
@@ -389,6 +397,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { | |||
389 | .name = "ks8842", | 397 | .name = "ks8842", |
390 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), | 398 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), |
391 | .resources = timberdale_eth_resources, | 399 | .resources = timberdale_eth_resources, |
400 | .platform_data = &timberdale_ks8842_platform_data, | ||
401 | .data_size = sizeof(timberdale_ks8842_platform_data) | ||
392 | }, | 402 | }, |
393 | }; | 403 | }; |
394 | 404 | ||
@@ -447,6 +457,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { | |||
447 | .name = "ks8842", | 457 | .name = "ks8842", |
448 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), | 458 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), |
449 | .resources = timberdale_eth_resources, | 459 | .resources = timberdale_eth_resources, |
460 | .platform_data = &timberdale_ks8842_platform_data, | ||
461 | .data_size = sizeof(timberdale_ks8842_platform_data) | ||
450 | }, | 462 | }, |
451 | }; | 463 | }; |
452 | 464 | ||
@@ -538,6 +550,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { | |||
538 | .name = "ks8842", | 550 | .name = "ks8842", |
539 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), | 551 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), |
540 | .resources = timberdale_eth_resources, | 552 | .resources = timberdale_eth_resources, |
553 | .platform_data = &timberdale_ks8842_platform_data, | ||
554 | .data_size = sizeof(timberdale_ks8842_platform_data) | ||
541 | }, | 555 | }, |
542 | }; | 556 | }; |
543 | 557 | ||
diff --git a/drivers/mfd/tps6507x.c b/drivers/mfd/tps6507x.c index fc0197649281..33ba7723c967 100644 --- a/drivers/mfd/tps6507x.c +++ b/drivers/mfd/tps6507x.c | |||
@@ -68,7 +68,7 @@ static int tps6507x_i2c_write_device(struct tps6507x_dev *tps6507x, char reg, | |||
68 | u8 msg[TPS6507X_MAX_REGISTER + 1]; | 68 | u8 msg[TPS6507X_MAX_REGISTER + 1]; |
69 | int ret; | 69 | int ret; |
70 | 70 | ||
71 | if (bytes > (TPS6507X_MAX_REGISTER + 1)) | 71 | if (bytes > TPS6507X_MAX_REGISTER) |
72 | return -EINVAL; | 72 | return -EINVAL; |
73 | 73 | ||
74 | msg[0] = reg; | 74 | msg[0] = reg; |
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 4cde31e6a252..b4931ab34929 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c | |||
@@ -15,6 +15,8 @@ | |||
15 | * published by the Free Software Foundation. | 15 | * published by the Free Software Foundation. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/irq.h> | ||
18 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
19 | #include <linux/module.h> | 21 | #include <linux/module.h> |
20 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
@@ -29,9 +31,64 @@ | |||
29 | #define TPS6586X_GPIOSET1 0x5d | 31 | #define TPS6586X_GPIOSET1 0x5d |
30 | #define TPS6586X_GPIOSET2 0x5e | 32 | #define TPS6586X_GPIOSET2 0x5e |
31 | 33 | ||
34 | /* interrupt control registers */ | ||
35 | #define TPS6586X_INT_ACK1 0xb5 | ||
36 | #define TPS6586X_INT_ACK2 0xb6 | ||
37 | #define TPS6586X_INT_ACK3 0xb7 | ||
38 | #define TPS6586X_INT_ACK4 0xb8 | ||
39 | |||
40 | /* interrupt mask registers */ | ||
41 | #define TPS6586X_INT_MASK1 0xb0 | ||
42 | #define TPS6586X_INT_MASK2 0xb1 | ||
43 | #define TPS6586X_INT_MASK3 0xb2 | ||
44 | #define TPS6586X_INT_MASK4 0xb3 | ||
45 | #define TPS6586X_INT_MASK5 0xb4 | ||
46 | |||
32 | /* device id */ | 47 | /* device id */ |
33 | #define TPS6586X_VERSIONCRC 0xcd | 48 | #define TPS6586X_VERSIONCRC 0xcd |
34 | #define TPS658621A_VERSIONCRC 0x15 | 49 | #define TPS658621A_VERSIONCRC 0x15 |
50 | #define TPS658621C_VERSIONCRC 0x2c | ||
51 | |||
52 | struct tps6586x_irq_data { | ||
53 | u8 mask_reg; | ||
54 | u8 mask_mask; | ||
55 | }; | ||
56 | |||
57 | #define TPS6586X_IRQ(_reg, _mask) \ | ||
58 | { \ | ||
59 | .mask_reg = (_reg) - TPS6586X_INT_MASK1, \ | ||
60 | .mask_mask = (_mask), \ | ||
61 | } | ||
62 | |||
63 | static const struct tps6586x_irq_data tps6586x_irqs[] = { | ||
64 | [TPS6586X_INT_PLDO_0] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 0), | ||
65 | [TPS6586X_INT_PLDO_1] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 1), | ||
66 | [TPS6586X_INT_PLDO_2] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 2), | ||
67 | [TPS6586X_INT_PLDO_3] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 3), | ||
68 | [TPS6586X_INT_PLDO_4] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 4), | ||
69 | [TPS6586X_INT_PLDO_5] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 5), | ||
70 | [TPS6586X_INT_PLDO_6] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 6), | ||
71 | [TPS6586X_INT_PLDO_7] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 7), | ||
72 | [TPS6586X_INT_COMP_DET] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 0), | ||
73 | [TPS6586X_INT_ADC] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 1), | ||
74 | [TPS6586X_INT_PLDO_8] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 2), | ||
75 | [TPS6586X_INT_PLDO_9] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 3), | ||
76 | [TPS6586X_INT_PSM_0] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 4), | ||
77 | [TPS6586X_INT_PSM_1] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 5), | ||
78 | [TPS6586X_INT_PSM_2] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 6), | ||
79 | [TPS6586X_INT_PSM_3] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 7), | ||
80 | [TPS6586X_INT_RTC_ALM1] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 4), | ||
81 | [TPS6586X_INT_ACUSB_OVP] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 0x03), | ||
82 | [TPS6586X_INT_USB_DET] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 2), | ||
83 | [TPS6586X_INT_AC_DET] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 3), | ||
84 | [TPS6586X_INT_BAT_DET] = TPS6586X_IRQ(TPS6586X_INT_MASK3, 1 << 0), | ||
85 | [TPS6586X_INT_CHG_STAT] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 0xfc), | ||
86 | [TPS6586X_INT_CHG_TEMP] = TPS6586X_IRQ(TPS6586X_INT_MASK3, 0x06), | ||
87 | [TPS6586X_INT_PP] = TPS6586X_IRQ(TPS6586X_INT_MASK3, 0xf0), | ||
88 | [TPS6586X_INT_RESUME] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 5), | ||
89 | [TPS6586X_INT_LOW_SYS] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 6), | ||
90 | [TPS6586X_INT_RTC_ALM2] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 1), | ||
91 | }; | ||
35 | 92 | ||
36 | struct tps6586x { | 93 | struct tps6586x { |
37 | struct mutex lock; | 94 | struct mutex lock; |
@@ -39,6 +96,12 @@ struct tps6586x { | |||
39 | struct i2c_client *client; | 96 | struct i2c_client *client; |
40 | 97 | ||
41 | struct gpio_chip gpio; | 98 | struct gpio_chip gpio; |
99 | struct irq_chip irq_chip; | ||
100 | struct mutex irq_lock; | ||
101 | int irq_base; | ||
102 | u32 irq_en; | ||
103 | u8 mask_cache[5]; | ||
104 | u8 mask_reg[5]; | ||
42 | }; | 105 | }; |
43 | 106 | ||
44 | static inline int __tps6586x_read(struct i2c_client *client, | 107 | static inline int __tps6586x_read(struct i2c_client *client, |
@@ -262,6 +325,129 @@ static int tps6586x_remove_subdevs(struct tps6586x *tps6586x) | |||
262 | return device_for_each_child(tps6586x->dev, NULL, __remove_subdev); | 325 | return device_for_each_child(tps6586x->dev, NULL, __remove_subdev); |
263 | } | 326 | } |
264 | 327 | ||
328 | static void tps6586x_irq_lock(unsigned int irq) | ||
329 | { | ||
330 | struct tps6586x *tps6586x = get_irq_chip_data(irq); | ||
331 | |||
332 | mutex_lock(&tps6586x->irq_lock); | ||
333 | } | ||
334 | |||
335 | static void tps6586x_irq_enable(unsigned int irq) | ||
336 | { | ||
337 | struct tps6586x *tps6586x = get_irq_chip_data(irq); | ||
338 | unsigned int __irq = irq - tps6586x->irq_base; | ||
339 | const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq]; | ||
340 | |||
341 | tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask; | ||
342 | tps6586x->irq_en |= (1 << __irq); | ||
343 | } | ||
344 | |||
345 | static void tps6586x_irq_disable(unsigned int irq) | ||
346 | { | ||
347 | struct tps6586x *tps6586x = get_irq_chip_data(irq); | ||
348 | |||
349 | unsigned int __irq = irq - tps6586x->irq_base; | ||
350 | const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq]; | ||
351 | |||
352 | tps6586x->mask_reg[data->mask_reg] |= data->mask_mask; | ||
353 | tps6586x->irq_en &= ~(1 << __irq); | ||
354 | } | ||
355 | |||
356 | static void tps6586x_irq_sync_unlock(unsigned int irq) | ||
357 | { | ||
358 | struct tps6586x *tps6586x = get_irq_chip_data(irq); | ||
359 | int i; | ||
360 | |||
361 | for (i = 0; i < ARRAY_SIZE(tps6586x->mask_reg); i++) { | ||
362 | if (tps6586x->mask_reg[i] != tps6586x->mask_cache[i]) { | ||
363 | if (!WARN_ON(tps6586x_write(tps6586x->dev, | ||
364 | TPS6586X_INT_MASK1 + i, | ||
365 | tps6586x->mask_reg[i]))) | ||
366 | tps6586x->mask_cache[i] = tps6586x->mask_reg[i]; | ||
367 | } | ||
368 | } | ||
369 | |||
370 | mutex_unlock(&tps6586x->irq_lock); | ||
371 | } | ||
372 | |||
373 | static irqreturn_t tps6586x_irq(int irq, void *data) | ||
374 | { | ||
375 | struct tps6586x *tps6586x = data; | ||
376 | u32 acks; | ||
377 | int ret = 0; | ||
378 | |||
379 | ret = tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1, | ||
380 | sizeof(acks), (uint8_t *)&acks); | ||
381 | |||
382 | if (ret < 0) { | ||
383 | dev_err(tps6586x->dev, "failed to read interrupt status\n"); | ||
384 | return IRQ_NONE; | ||
385 | } | ||
386 | |||
387 | acks = le32_to_cpu(acks); | ||
388 | |||
389 | while (acks) { | ||
390 | int i = __ffs(acks); | ||
391 | |||
392 | if (tps6586x->irq_en & (1 << i)) | ||
393 | handle_nested_irq(tps6586x->irq_base + i); | ||
394 | |||
395 | acks &= ~(1 << i); | ||
396 | } | ||
397 | |||
398 | return IRQ_HANDLED; | ||
399 | } | ||
400 | |||
401 | static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq, | ||
402 | int irq_base) | ||
403 | { | ||
404 | int i, ret; | ||
405 | u8 tmp[4]; | ||
406 | |||
407 | if (!irq_base) { | ||
408 | dev_warn(tps6586x->dev, "No interrupt support on IRQ base\n"); | ||
409 | return -EINVAL; | ||
410 | } | ||
411 | |||
412 | mutex_init(&tps6586x->irq_lock); | ||
413 | for (i = 0; i < 5; i++) { | ||
414 | tps6586x->mask_cache[i] = 0xff; | ||
415 | tps6586x->mask_reg[i] = 0xff; | ||
416 | tps6586x_write(tps6586x->dev, TPS6586X_INT_MASK1 + i, 0xff); | ||
417 | } | ||
418 | |||
419 | tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1, sizeof(tmp), tmp); | ||
420 | |||
421 | tps6586x->irq_base = irq_base; | ||
422 | |||
423 | tps6586x->irq_chip.name = "tps6586x"; | ||
424 | tps6586x->irq_chip.enable = tps6586x_irq_enable; | ||
425 | tps6586x->irq_chip.disable = tps6586x_irq_disable; | ||
426 | tps6586x->irq_chip.bus_lock = tps6586x_irq_lock; | ||
427 | tps6586x->irq_chip.bus_sync_unlock = tps6586x_irq_sync_unlock; | ||
428 | |||
429 | for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) { | ||
430 | int __irq = i + tps6586x->irq_base; | ||
431 | set_irq_chip_data(__irq, tps6586x); | ||
432 | set_irq_chip_and_handler(__irq, &tps6586x->irq_chip, | ||
433 | handle_simple_irq); | ||
434 | set_irq_nested_thread(__irq, 1); | ||
435 | #ifdef CONFIG_ARM | ||
436 | set_irq_flags(__irq, IRQF_VALID); | ||
437 | #endif | ||
438 | } | ||
439 | |||
440 | ret = request_threaded_irq(irq, NULL, tps6586x_irq, IRQF_ONESHOT, | ||
441 | "tps6586x", tps6586x); | ||
442 | |||
443 | if (!ret) { | ||
444 | device_init_wakeup(tps6586x->dev, 1); | ||
445 | enable_irq_wake(irq); | ||
446 | } | ||
447 | |||
448 | return ret; | ||
449 | } | ||
450 | |||
265 | static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x, | 451 | static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x, |
266 | struct tps6586x_platform_data *pdata) | 452 | struct tps6586x_platform_data *pdata) |
267 | { | 453 | { |
@@ -273,13 +459,19 @@ static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x, | |||
273 | subdev = &pdata->subdevs[i]; | 459 | subdev = &pdata->subdevs[i]; |
274 | 460 | ||
275 | pdev = platform_device_alloc(subdev->name, subdev->id); | 461 | pdev = platform_device_alloc(subdev->name, subdev->id); |
462 | if (!pdev) { | ||
463 | ret = -ENOMEM; | ||
464 | goto failed; | ||
465 | } | ||
276 | 466 | ||
277 | pdev->dev.parent = tps6586x->dev; | 467 | pdev->dev.parent = tps6586x->dev; |
278 | pdev->dev.platform_data = subdev->platform_data; | 468 | pdev->dev.platform_data = subdev->platform_data; |
279 | 469 | ||
280 | ret = platform_device_add(pdev); | 470 | ret = platform_device_add(pdev); |
281 | if (ret) | 471 | if (ret) { |
472 | platform_device_put(pdev); | ||
282 | goto failed; | 473 | goto failed; |
474 | } | ||
283 | } | 475 | } |
284 | return 0; | 476 | return 0; |
285 | 477 | ||
@@ -306,7 +498,8 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, | |||
306 | return -EIO; | 498 | return -EIO; |
307 | } | 499 | } |
308 | 500 | ||
309 | if (ret != TPS658621A_VERSIONCRC) { | 501 | if ((ret != TPS658621A_VERSIONCRC) && |
502 | (ret != TPS658621C_VERSIONCRC)) { | ||
310 | dev_err(&client->dev, "Unsupported chip ID: %x\n", ret); | 503 | dev_err(&client->dev, "Unsupported chip ID: %x\n", ret); |
311 | return -ENODEV; | 504 | return -ENODEV; |
312 | } | 505 | } |
@@ -321,6 +514,15 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, | |||
321 | 514 | ||
322 | mutex_init(&tps6586x->lock); | 515 | mutex_init(&tps6586x->lock); |
323 | 516 | ||
517 | if (client->irq) { | ||
518 | ret = tps6586x_irq_init(tps6586x, client->irq, | ||
519 | pdata->irq_base); | ||
520 | if (ret) { | ||
521 | dev_err(&client->dev, "IRQ init failed: %d\n", ret); | ||
522 | goto err_irq_init; | ||
523 | } | ||
524 | } | ||
525 | |||
324 | ret = tps6586x_add_subdevs(tps6586x, pdata); | 526 | ret = tps6586x_add_subdevs(tps6586x, pdata); |
325 | if (ret) { | 527 | if (ret) { |
326 | dev_err(&client->dev, "add devices failed: %d\n", ret); | 528 | dev_err(&client->dev, "add devices failed: %d\n", ret); |
@@ -332,12 +534,31 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, | |||
332 | return 0; | 534 | return 0; |
333 | 535 | ||
334 | err_add_devs: | 536 | err_add_devs: |
537 | if (client->irq) | ||
538 | free_irq(client->irq, tps6586x); | ||
539 | err_irq_init: | ||
335 | kfree(tps6586x); | 540 | kfree(tps6586x); |
336 | return ret; | 541 | return ret; |
337 | } | 542 | } |
338 | 543 | ||
339 | static int __devexit tps6586x_i2c_remove(struct i2c_client *client) | 544 | static int __devexit tps6586x_i2c_remove(struct i2c_client *client) |
340 | { | 545 | { |
546 | struct tps6586x *tps6586x = i2c_get_clientdata(client); | ||
547 | struct tps6586x_platform_data *pdata = client->dev.platform_data; | ||
548 | int ret; | ||
549 | |||
550 | if (client->irq) | ||
551 | free_irq(client->irq, tps6586x); | ||
552 | |||
553 | if (pdata->gpio_base) { | ||
554 | ret = gpiochip_remove(&tps6586x->gpio); | ||
555 | if (ret) | ||
556 | dev_err(&client->dev, "Can't remove gpio chip: %d\n", | ||
557 | ret); | ||
558 | } | ||
559 | |||
560 | tps6586x_remove_subdevs(tps6586x); | ||
561 | kfree(tps6586x); | ||
341 | return 0; | 562 | return 0; |
342 | } | 563 | } |
343 | 564 | ||
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 5d0fb60a4c14..35275ba7096f 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c | |||
@@ -115,6 +115,12 @@ | |||
115 | #define twl_has_codec() false | 115 | #define twl_has_codec() false |
116 | #endif | 116 | #endif |
117 | 117 | ||
118 | #if defined(CONFIG_CHARGER_TWL4030) || defined(CONFIG_CHARGER_TWL4030_MODULE) | ||
119 | #define twl_has_bci() true | ||
120 | #else | ||
121 | #define twl_has_bci() false | ||
122 | #endif | ||
123 | |||
118 | /* Triton Core internal information (BEGIN) */ | 124 | /* Triton Core internal information (BEGIN) */ |
119 | 125 | ||
120 | /* Last - for index max*/ | 126 | /* Last - for index max*/ |
@@ -202,12 +208,6 @@ | |||
202 | 208 | ||
203 | /* Few power values */ | 209 | /* Few power values */ |
204 | #define R_CFG_BOOT 0x05 | 210 | #define R_CFG_BOOT 0x05 |
205 | #define R_PROTECT_KEY 0x0E | ||
206 | |||
207 | /* access control values for R_PROTECT_KEY */ | ||
208 | #define KEY_UNLOCK1 0xce | ||
209 | #define KEY_UNLOCK2 0xec | ||
210 | #define KEY_LOCK 0x00 | ||
211 | 211 | ||
212 | /* some fields in R_CFG_BOOT */ | 212 | /* some fields in R_CFG_BOOT */ |
213 | #define HFCLK_FREQ_19p2_MHZ (1 << 0) | 213 | #define HFCLK_FREQ_19p2_MHZ (1 << 0) |
@@ -255,7 +255,7 @@ struct twl_mapping { | |||
255 | unsigned char sid; /* Slave ID */ | 255 | unsigned char sid; /* Slave ID */ |
256 | unsigned char base; /* base address */ | 256 | unsigned char base; /* base address */ |
257 | }; | 257 | }; |
258 | struct twl_mapping *twl_map; | 258 | static struct twl_mapping *twl_map; |
259 | 259 | ||
260 | static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { | 260 | static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { |
261 | /* | 261 | /* |
@@ -832,6 +832,17 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
832 | return PTR_ERR(child); | 832 | return PTR_ERR(child); |
833 | } | 833 | } |
834 | 834 | ||
835 | if (twl_has_bci() && pdata->bci && | ||
836 | !(features & (TPS_SUBSET | TWL5031))) { | ||
837 | child = add_child(3, "twl4030_bci", | ||
838 | pdata->bci, sizeof(*pdata->bci), false, | ||
839 | /* irq0 = CHG_PRES, irq1 = BCI */ | ||
840 | pdata->irq_base + BCI_PRES_INTR_OFFSET, | ||
841 | pdata->irq_base + BCI_INTR_OFFSET); | ||
842 | if (IS_ERR(child)) | ||
843 | return PTR_ERR(child); | ||
844 | } | ||
845 | |||
835 | return 0; | 846 | return 0; |
836 | } | 847 | } |
837 | 848 | ||
@@ -846,8 +857,8 @@ static inline int __init protect_pm_master(void) | |||
846 | { | 857 | { |
847 | int e = 0; | 858 | int e = 0; |
848 | 859 | ||
849 | e = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_LOCK, | 860 | e = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, |
850 | R_PROTECT_KEY); | 861 | TWL4030_PM_MASTER_PROTECT_KEY); |
851 | return e; | 862 | return e; |
852 | } | 863 | } |
853 | 864 | ||
@@ -855,10 +866,13 @@ static inline int __init unprotect_pm_master(void) | |||
855 | { | 866 | { |
856 | int e = 0; | 867 | int e = 0; |
857 | 868 | ||
858 | e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_UNLOCK1, | 869 | e |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, |
859 | R_PROTECT_KEY); | 870 | TWL4030_PM_MASTER_KEY_CFG1, |
860 | e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_UNLOCK2, | 871 | TWL4030_PM_MASTER_PROTECT_KEY); |
861 | R_PROTECT_KEY); | 872 | e |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, |
873 | TWL4030_PM_MASTER_KEY_CFG2, | ||
874 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
875 | |||
862 | return e; | 876 | return e; |
863 | } | 877 | } |
864 | 878 | ||
diff --git a/drivers/mfd/twl-core.h b/drivers/mfd/twl-core.h new file mode 100644 index 000000000000..8c50a556e986 --- /dev/null +++ b/drivers/mfd/twl-core.h | |||
@@ -0,0 +1,10 @@ | |||
1 | #ifndef __TWL_CORE_H__ | ||
2 | #define __TWL_CORE_H__ | ||
3 | |||
4 | extern int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); | ||
5 | extern int twl6030_exit_irq(void); | ||
6 | extern int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); | ||
7 | extern int twl4030_exit_irq(void); | ||
8 | extern int twl4030_init_chip_irq(const char *chip); | ||
9 | |||
10 | #endif /* __TWL_CORE_H__ */ | ||
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index b9fda7018cef..5d3a1478004b 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c | |||
@@ -35,6 +35,7 @@ | |||
35 | 35 | ||
36 | #include <linux/i2c/twl.h> | 36 | #include <linux/i2c/twl.h> |
37 | 37 | ||
38 | #include "twl-core.h" | ||
38 | 39 | ||
39 | /* | 40 | /* |
40 | * TWL4030 IRQ handling has two stages in hardware, and thus in software. | 41 | * TWL4030 IRQ handling has two stages in hardware, and thus in software. |
@@ -144,6 +145,7 @@ static const struct sih sih_modules_twl4030[6] = { | |||
144 | .name = "bci", | 145 | .name = "bci", |
145 | .module = TWL4030_MODULE_INTERRUPTS, | 146 | .module = TWL4030_MODULE_INTERRUPTS, |
146 | .control_offset = TWL4030_INTERRUPTS_BCISIHCTRL, | 147 | .control_offset = TWL4030_INTERRUPTS_BCISIHCTRL, |
148 | .set_cor = true, | ||
147 | .bits = 12, | 149 | .bits = 12, |
148 | .bytes_ixr = 2, | 150 | .bytes_ixr = 2, |
149 | .edr_offset = TWL4030_INTERRUPTS_BCIEDR1, | 151 | .edr_offset = TWL4030_INTERRUPTS_BCIEDR1, |
@@ -408,7 +410,7 @@ static int twl4030_init_sih_modules(unsigned line) | |||
408 | * set Clear-On-Read (COR) bit. | 410 | * set Clear-On-Read (COR) bit. |
409 | * | 411 | * |
410 | * NOTE that sometimes COR polarity is documented as being | 412 | * NOTE that sometimes COR polarity is documented as being |
411 | * inverted: for MADC and BCI, COR=1 means "clear on write". | 413 | * inverted: for MADC, COR=1 means "clear on write". |
412 | * And for PWR_INT it's not documented... | 414 | * And for PWR_INT it's not documented... |
413 | */ | 415 | */ |
414 | if (sih->set_cor) { | 416 | if (sih->set_cor) { |
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 7efa8789a3a2..16422de0823a 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c | |||
@@ -63,10 +63,6 @@ static u8 twl4030_start_script_address = 0x2b; | |||
63 | #define R_MEMORY_ADDRESS PHY_TO_OFF_PM_MASTER(0x59) | 63 | #define R_MEMORY_ADDRESS PHY_TO_OFF_PM_MASTER(0x59) |
64 | #define R_MEMORY_DATA PHY_TO_OFF_PM_MASTER(0x5a) | 64 | #define R_MEMORY_DATA PHY_TO_OFF_PM_MASTER(0x5a) |
65 | 65 | ||
66 | #define R_PROTECT_KEY 0x0E | ||
67 | #define R_KEY_1 0xC0 | ||
68 | #define R_KEY_2 0x0C | ||
69 | |||
70 | /* resource configuration registers | 66 | /* resource configuration registers |
71 | <RESOURCE>_DEV_GRP at address 'n+0' | 67 | <RESOURCE>_DEV_GRP at address 'n+0' |
72 | <RESOURCE>_TYPE at address 'n+1' | 68 | <RESOURCE>_TYPE at address 'n+1' |
@@ -465,15 +461,17 @@ int twl4030_remove_script(u8 flags) | |||
465 | { | 461 | { |
466 | int err = 0; | 462 | int err = 0; |
467 | 463 | ||
468 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1, | 464 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, |
469 | R_PROTECT_KEY); | 465 | TWL4030_PM_MASTER_KEY_CFG1, |
466 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
470 | if (err) { | 467 | if (err) { |
471 | pr_err("twl4030: unable to unlock PROTECT_KEY\n"); | 468 | pr_err("twl4030: unable to unlock PROTECT_KEY\n"); |
472 | return err; | 469 | return err; |
473 | } | 470 | } |
474 | 471 | ||
475 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2, | 472 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, |
476 | R_PROTECT_KEY); | 473 | TWL4030_PM_MASTER_KEY_CFG2, |
474 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
477 | if (err) { | 475 | if (err) { |
478 | pr_err("twl4030: unable to unlock PROTECT_KEY\n"); | 476 | pr_err("twl4030: unable to unlock PROTECT_KEY\n"); |
479 | return err; | 477 | return err; |
@@ -504,7 +502,8 @@ int twl4030_remove_script(u8 flags) | |||
504 | return err; | 502 | return err; |
505 | } | 503 | } |
506 | 504 | ||
507 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY); | 505 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, |
506 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
508 | if (err) | 507 | if (err) |
509 | pr_err("TWL4030 Unable to relock registers\n"); | 508 | pr_err("TWL4030 Unable to relock registers\n"); |
510 | 509 | ||
@@ -518,13 +517,15 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) | |||
518 | struct twl4030_resconfig *resconfig; | 517 | struct twl4030_resconfig *resconfig; |
519 | u8 address = twl4030_start_script_address; | 518 | u8 address = twl4030_start_script_address; |
520 | 519 | ||
521 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1, | 520 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, |
522 | R_PROTECT_KEY); | 521 | TWL4030_PM_MASTER_KEY_CFG1, |
522 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
523 | if (err) | 523 | if (err) |
524 | goto unlock; | 524 | goto unlock; |
525 | 525 | ||
526 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2, | 526 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, |
527 | R_PROTECT_KEY); | 527 | TWL4030_PM_MASTER_KEY_CFG2, |
528 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
528 | if (err) | 529 | if (err) |
529 | goto unlock; | 530 | goto unlock; |
530 | 531 | ||
@@ -546,7 +547,8 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) | |||
546 | } | 547 | } |
547 | } | 548 | } |
548 | 549 | ||
549 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY); | 550 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, |
551 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
550 | if (err) | 552 | if (err) |
551 | pr_err("TWL4030 Unable to relock registers\n"); | 553 | pr_err("TWL4030 Unable to relock registers\n"); |
552 | return; | 554 | return; |
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 10bf228ad626..aaedb11d9d2c 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c | |||
@@ -36,6 +36,9 @@ | |||
36 | #include <linux/irq.h> | 36 | #include <linux/irq.h> |
37 | #include <linux/kthread.h> | 37 | #include <linux/kthread.h> |
38 | #include <linux/i2c/twl.h> | 38 | #include <linux/i2c/twl.h> |
39 | #include <linux/platform_device.h> | ||
40 | |||
41 | #include "twl-core.h" | ||
39 | 42 | ||
40 | /* | 43 | /* |
41 | * TWL6030 (unlike its predecessors, which had two level interrupt handling) | 44 | * TWL6030 (unlike its predecessors, which had two level interrupt handling) |
@@ -223,6 +226,78 @@ int twl6030_interrupt_mask(u8 bit_mask, u8 offset) | |||
223 | } | 226 | } |
224 | EXPORT_SYMBOL(twl6030_interrupt_mask); | 227 | EXPORT_SYMBOL(twl6030_interrupt_mask); |
225 | 228 | ||
229 | int twl6030_mmc_card_detect_config(void) | ||
230 | { | ||
231 | int ret; | ||
232 | u8 reg_val = 0; | ||
233 | |||
234 | /* Unmasking the Card detect Interrupt line for MMC1 from Phoenix */ | ||
235 | twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, | ||
236 | REG_INT_MSK_LINE_B); | ||
237 | twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, | ||
238 | REG_INT_MSK_STS_B); | ||
239 | /* | ||
240 | * Intially Configuring MMC_CTRL for receving interrupts & | ||
241 | * Card status on TWL6030 for MMC1 | ||
242 | */ | ||
243 | ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, TWL6030_MMCCTRL); | ||
244 | if (ret < 0) { | ||
245 | pr_err("twl6030: Failed to read MMCCTRL, error %d\n", ret); | ||
246 | return ret; | ||
247 | } | ||
248 | reg_val &= ~VMMC_AUTO_OFF; | ||
249 | reg_val |= SW_FC; | ||
250 | ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, TWL6030_MMCCTRL); | ||
251 | if (ret < 0) { | ||
252 | pr_err("twl6030: Failed to write MMCCTRL, error %d\n", ret); | ||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | /* Configuring PullUp-PullDown register */ | ||
257 | ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, | ||
258 | TWL6030_CFG_INPUT_PUPD3); | ||
259 | if (ret < 0) { | ||
260 | pr_err("twl6030: Failed to read CFG_INPUT_PUPD3, error %d\n", | ||
261 | ret); | ||
262 | return ret; | ||
263 | } | ||
264 | reg_val &= ~(MMC_PU | MMC_PD); | ||
265 | ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, | ||
266 | TWL6030_CFG_INPUT_PUPD3); | ||
267 | if (ret < 0) { | ||
268 | pr_err("twl6030: Failed to write CFG_INPUT_PUPD3, error %d\n", | ||
269 | ret); | ||
270 | return ret; | ||
271 | } | ||
272 | return 0; | ||
273 | } | ||
274 | EXPORT_SYMBOL(twl6030_mmc_card_detect_config); | ||
275 | |||
276 | int twl6030_mmc_card_detect(struct device *dev, int slot) | ||
277 | { | ||
278 | int ret = -EIO; | ||
279 | u8 read_reg = 0; | ||
280 | struct platform_device *pdev = to_platform_device(dev); | ||
281 | |||
282 | if (pdev->id) { | ||
283 | /* TWL6030 provide's Card detect support for | ||
284 | * only MMC1 controller. | ||
285 | */ | ||
286 | pr_err("Unkown MMC controller %d in %s\n", pdev->id, __func__); | ||
287 | return ret; | ||
288 | } | ||
289 | /* | ||
290 | * BIT0 of MMC_CTRL on TWL6030 provides card status for MMC1 | ||
291 | * 0 - Card not present ,1 - Card present | ||
292 | */ | ||
293 | ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, &read_reg, | ||
294 | TWL6030_MMCCTRL); | ||
295 | if (ret >= 0) | ||
296 | ret = read_reg & STS_MMC; | ||
297 | return ret; | ||
298 | } | ||
299 | EXPORT_SYMBOL(twl6030_mmc_card_detect); | ||
300 | |||
226 | int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | 301 | int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) |
227 | { | 302 | { |
228 | 303 | ||
diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c new file mode 100644 index 000000000000..ebb059765edd --- /dev/null +++ b/drivers/mfd/vx855.c | |||
@@ -0,0 +1,147 @@ | |||
1 | /* | ||
2 | * Linux multi-function-device driver (MFD) for the integrated peripherals | ||
3 | * of the VIA VX855 chipset | ||
4 | * | ||
5 | * Copyright (C) 2009 VIA Technologies, Inc. | ||
6 | * Copyright (C) 2010 One Laptop per Child | ||
7 | * Author: Harald Welte <HaraldWelte@viatech.com> | ||
8 | * All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License as | ||
12 | * published by the Free Software Foundation; either version 2 of | ||
13 | * the License, or (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
23 | * MA 02111-1307 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/device.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/pci.h> | ||
32 | #include <linux/mfd/core.h> | ||
33 | |||
34 | /* offset into pci config space indicating the 16bit register containing | ||
35 | * the power management IO space base */ | ||
36 | #define VX855_CFG_PMIO_OFFSET 0x88 | ||
37 | |||
38 | /* ACPI I/O Space registers */ | ||
39 | #define VX855_PMIO_ACPI 0x00 | ||
40 | #define VX855_PMIO_ACPI_LEN 0x0b | ||
41 | |||
42 | /* Processor Power Management */ | ||
43 | #define VX855_PMIO_PPM 0x10 | ||
44 | #define VX855_PMIO_PPM_LEN 0x08 | ||
45 | |||
46 | /* General Purpose Power Management */ | ||
47 | #define VX855_PMIO_GPPM 0x20 | ||
48 | #define VX855_PMIO_R_GPI 0x48 | ||
49 | #define VX855_PMIO_R_GPO 0x4c | ||
50 | #define VX855_PMIO_GPPM_LEN 0x33 | ||
51 | |||
52 | #define VSPIC_MMIO_SIZE 0x1000 | ||
53 | |||
54 | static struct resource vx855_gpio_resources[] = { | ||
55 | { | ||
56 | .flags = IORESOURCE_IO, | ||
57 | }, | ||
58 | { | ||
59 | .flags = IORESOURCE_IO, | ||
60 | }, | ||
61 | }; | ||
62 | |||
63 | static struct mfd_cell vx855_cells[] = { | ||
64 | { | ||
65 | .name = "vx855_gpio", | ||
66 | .num_resources = ARRAY_SIZE(vx855_gpio_resources), | ||
67 | .resources = vx855_gpio_resources, | ||
68 | |||
69 | /* we must ignore resource conflicts, for reasons outlined in | ||
70 | * the vx855_gpio driver */ | ||
71 | .ignore_resource_conflicts = true, | ||
72 | }, | ||
73 | }; | ||
74 | |||
75 | static __devinit int vx855_probe(struct pci_dev *pdev, | ||
76 | const struct pci_device_id *id) | ||
77 | { | ||
78 | int ret; | ||
79 | u16 gpio_io_offset; | ||
80 | |||
81 | ret = pci_enable_device(pdev); | ||
82 | if (ret) | ||
83 | return -ENODEV; | ||
84 | |||
85 | pci_read_config_word(pdev, VX855_CFG_PMIO_OFFSET, &gpio_io_offset); | ||
86 | if (!gpio_io_offset) { | ||
87 | dev_warn(&pdev->dev, | ||
88 | "BIOS did not assign PMIO base offset?!?\n"); | ||
89 | ret = -ENODEV; | ||
90 | goto out; | ||
91 | } | ||
92 | |||
93 | /* mask out the lowest seven bits, as they are always zero, but | ||
94 | * hardware returns them as 0x01 */ | ||
95 | gpio_io_offset &= 0xff80; | ||
96 | |||
97 | /* As the region identified here includes many non-GPIO things, we | ||
98 | * only work with the specific registers that concern us. */ | ||
99 | vx855_gpio_resources[0].start = gpio_io_offset + VX855_PMIO_R_GPI; | ||
100 | vx855_gpio_resources[0].end = vx855_gpio_resources[0].start + 3; | ||
101 | vx855_gpio_resources[1].start = gpio_io_offset + VX855_PMIO_R_GPO; | ||
102 | vx855_gpio_resources[1].end = vx855_gpio_resources[1].start + 3; | ||
103 | |||
104 | ret = mfd_add_devices(&pdev->dev, -1, vx855_cells, ARRAY_SIZE(vx855_cells), | ||
105 | NULL, 0); | ||
106 | |||
107 | /* we always return -ENODEV here in order to enable other | ||
108 | * drivers like old, not-yet-platform_device ported i2c-viapro */ | ||
109 | return -ENODEV; | ||
110 | out: | ||
111 | pci_disable_device(pdev); | ||
112 | return ret; | ||
113 | } | ||
114 | |||
115 | static void vx855_remove(struct pci_dev *pdev) | ||
116 | { | ||
117 | mfd_remove_devices(&pdev->dev); | ||
118 | pci_disable_device(pdev); | ||
119 | } | ||
120 | |||
121 | static struct pci_device_id vx855_pci_tbl[] = { | ||
122 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) }, | ||
123 | { 0, } | ||
124 | }; | ||
125 | |||
126 | static struct pci_driver vx855_pci_driver = { | ||
127 | .name = "vx855", | ||
128 | .id_table = vx855_pci_tbl, | ||
129 | .probe = vx855_probe, | ||
130 | .remove = __devexit_p(vx855_remove), | ||
131 | }; | ||
132 | |||
133 | static int vx855_init(void) | ||
134 | { | ||
135 | return pci_register_driver(&vx855_pci_driver); | ||
136 | } | ||
137 | module_init(vx855_init); | ||
138 | |||
139 | static void vx855_exit(void) | ||
140 | { | ||
141 | pci_unregister_driver(&vx855_pci_driver); | ||
142 | } | ||
143 | module_exit(vx855_exit); | ||
144 | |||
145 | MODULE_LICENSE("GPL"); | ||
146 | MODULE_AUTHOR("Harald Welte <HaraldWelte@viatech.com>"); | ||
147 | MODULE_DESCRIPTION("Driver for the VIA VX855 chipset"); | ||
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 1e7aaaf6cc6f..7d2563fc15c6 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c | |||
@@ -14,7 +14,6 @@ | |||
14 | 14 | ||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/i2c.h> | ||
18 | #include <linux/bcd.h> | 17 | #include <linux/bcd.h> |
19 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
20 | #include <linux/mfd/core.h> | 19 | #include <linux/mfd/core.h> |
@@ -90,14 +89,6 @@ int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = { | |||
90 | }; | 89 | }; |
91 | EXPORT_SYMBOL_GPL(wm831x_isinkv_values); | 90 | EXPORT_SYMBOL_GPL(wm831x_isinkv_values); |
92 | 91 | ||
93 | enum wm831x_parent { | ||
94 | WM8310 = 0x8310, | ||
95 | WM8311 = 0x8311, | ||
96 | WM8312 = 0x8312, | ||
97 | WM8320 = 0x8320, | ||
98 | WM8321 = 0x8321, | ||
99 | }; | ||
100 | |||
101 | static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg) | 92 | static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg) |
102 | { | 93 | { |
103 | if (!wm831x->locked) | 94 | if (!wm831x->locked) |
@@ -1446,7 +1437,7 @@ static struct mfd_cell backlight_devs[] = { | |||
1446 | /* | 1437 | /* |
1447 | * Instantiate the generic non-control parts of the device. | 1438 | * Instantiate the generic non-control parts of the device. |
1448 | */ | 1439 | */ |
1449 | static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | 1440 | int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) |
1450 | { | 1441 | { |
1451 | struct wm831x_pdata *pdata = wm831x->dev->platform_data; | 1442 | struct wm831x_pdata *pdata = wm831x->dev->platform_data; |
1452 | int rev; | 1443 | int rev; |
@@ -1540,6 +1531,12 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
1540 | dev_info(wm831x->dev, "WM8321 revision %c\n", 'A' + rev); | 1531 | dev_info(wm831x->dev, "WM8321 revision %c\n", 'A' + rev); |
1541 | break; | 1532 | break; |
1542 | 1533 | ||
1534 | case WM8325: | ||
1535 | parent = WM8325; | ||
1536 | wm831x->num_gpio = 12; | ||
1537 | dev_info(wm831x->dev, "WM8325 revision %c\n", 'A' + rev); | ||
1538 | break; | ||
1539 | |||
1543 | default: | 1540 | default: |
1544 | dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret); | 1541 | dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret); |
1545 | ret = -EINVAL; | 1542 | ret = -EINVAL; |
@@ -1620,6 +1617,12 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
1620 | NULL, 0); | 1617 | NULL, 0); |
1621 | break; | 1618 | break; |
1622 | 1619 | ||
1620 | case WM8325: | ||
1621 | ret = mfd_add_devices(wm831x->dev, -1, | ||
1622 | wm8320_devs, ARRAY_SIZE(wm8320_devs), | ||
1623 | NULL, 0); | ||
1624 | break; | ||
1625 | |||
1623 | default: | 1626 | default: |
1624 | /* If this happens the bus probe function is buggy */ | 1627 | /* If this happens the bus probe function is buggy */ |
1625 | BUG(); | 1628 | BUG(); |
@@ -1660,7 +1663,7 @@ err: | |||
1660 | return ret; | 1663 | return ret; |
1661 | } | 1664 | } |
1662 | 1665 | ||
1663 | static void wm831x_device_exit(struct wm831x *wm831x) | 1666 | void wm831x_device_exit(struct wm831x *wm831x) |
1664 | { | 1667 | { |
1665 | wm831x_otp_exit(wm831x); | 1668 | wm831x_otp_exit(wm831x); |
1666 | mfd_remove_devices(wm831x->dev); | 1669 | mfd_remove_devices(wm831x->dev); |
@@ -1670,7 +1673,7 @@ static void wm831x_device_exit(struct wm831x *wm831x) | |||
1670 | kfree(wm831x); | 1673 | kfree(wm831x); |
1671 | } | 1674 | } |
1672 | 1675 | ||
1673 | static int wm831x_device_suspend(struct wm831x *wm831x) | 1676 | int wm831x_device_suspend(struct wm831x *wm831x) |
1674 | { | 1677 | { |
1675 | int reg, mask; | 1678 | int reg, mask; |
1676 | 1679 | ||
@@ -1706,125 +1709,6 @@ static int wm831x_device_suspend(struct wm831x *wm831x) | |||
1706 | return 0; | 1709 | return 0; |
1707 | } | 1710 | } |
1708 | 1711 | ||
1709 | static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg, | 1712 | MODULE_DESCRIPTION("Core support for the WM831X AudioPlus PMIC"); |
1710 | int bytes, void *dest) | ||
1711 | { | ||
1712 | struct i2c_client *i2c = wm831x->control_data; | ||
1713 | int ret; | ||
1714 | u16 r = cpu_to_be16(reg); | ||
1715 | |||
1716 | ret = i2c_master_send(i2c, (unsigned char *)&r, 2); | ||
1717 | if (ret < 0) | ||
1718 | return ret; | ||
1719 | if (ret != 2) | ||
1720 | return -EIO; | ||
1721 | |||
1722 | ret = i2c_master_recv(i2c, dest, bytes); | ||
1723 | if (ret < 0) | ||
1724 | return ret; | ||
1725 | if (ret != bytes) | ||
1726 | return -EIO; | ||
1727 | return 0; | ||
1728 | } | ||
1729 | |||
1730 | /* Currently we allocate the write buffer on the stack; this is OK for | ||
1731 | * small writes - if we need to do large writes this will need to be | ||
1732 | * revised. | ||
1733 | */ | ||
1734 | static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg, | ||
1735 | int bytes, void *src) | ||
1736 | { | ||
1737 | struct i2c_client *i2c = wm831x->control_data; | ||
1738 | unsigned char msg[bytes + 2]; | ||
1739 | int ret; | ||
1740 | |||
1741 | reg = cpu_to_be16(reg); | ||
1742 | memcpy(&msg[0], ®, 2); | ||
1743 | memcpy(&msg[2], src, bytes); | ||
1744 | |||
1745 | ret = i2c_master_send(i2c, msg, bytes + 2); | ||
1746 | if (ret < 0) | ||
1747 | return ret; | ||
1748 | if (ret < bytes + 2) | ||
1749 | return -EIO; | ||
1750 | |||
1751 | return 0; | ||
1752 | } | ||
1753 | |||
1754 | static int wm831x_i2c_probe(struct i2c_client *i2c, | ||
1755 | const struct i2c_device_id *id) | ||
1756 | { | ||
1757 | struct wm831x *wm831x; | ||
1758 | |||
1759 | wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); | ||
1760 | if (wm831x == NULL) | ||
1761 | return -ENOMEM; | ||
1762 | |||
1763 | i2c_set_clientdata(i2c, wm831x); | ||
1764 | wm831x->dev = &i2c->dev; | ||
1765 | wm831x->control_data = i2c; | ||
1766 | wm831x->read_dev = wm831x_i2c_read_device; | ||
1767 | wm831x->write_dev = wm831x_i2c_write_device; | ||
1768 | |||
1769 | return wm831x_device_init(wm831x, id->driver_data, i2c->irq); | ||
1770 | } | ||
1771 | |||
1772 | static int wm831x_i2c_remove(struct i2c_client *i2c) | ||
1773 | { | ||
1774 | struct wm831x *wm831x = i2c_get_clientdata(i2c); | ||
1775 | |||
1776 | wm831x_device_exit(wm831x); | ||
1777 | |||
1778 | return 0; | ||
1779 | } | ||
1780 | |||
1781 | static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg) | ||
1782 | { | ||
1783 | struct wm831x *wm831x = i2c_get_clientdata(i2c); | ||
1784 | |||
1785 | return wm831x_device_suspend(wm831x); | ||
1786 | } | ||
1787 | |||
1788 | static const struct i2c_device_id wm831x_i2c_id[] = { | ||
1789 | { "wm8310", WM8310 }, | ||
1790 | { "wm8311", WM8311 }, | ||
1791 | { "wm8312", WM8312 }, | ||
1792 | { "wm8320", WM8320 }, | ||
1793 | { "wm8321", WM8321 }, | ||
1794 | { } | ||
1795 | }; | ||
1796 | MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id); | ||
1797 | |||
1798 | |||
1799 | static struct i2c_driver wm831x_i2c_driver = { | ||
1800 | .driver = { | ||
1801 | .name = "wm831x", | ||
1802 | .owner = THIS_MODULE, | ||
1803 | }, | ||
1804 | .probe = wm831x_i2c_probe, | ||
1805 | .remove = wm831x_i2c_remove, | ||
1806 | .suspend = wm831x_i2c_suspend, | ||
1807 | .id_table = wm831x_i2c_id, | ||
1808 | }; | ||
1809 | |||
1810 | static int __init wm831x_i2c_init(void) | ||
1811 | { | ||
1812 | int ret; | ||
1813 | |||
1814 | ret = i2c_add_driver(&wm831x_i2c_driver); | ||
1815 | if (ret != 0) | ||
1816 | pr_err("Failed to register wm831x I2C driver: %d\n", ret); | ||
1817 | |||
1818 | return ret; | ||
1819 | } | ||
1820 | subsys_initcall(wm831x_i2c_init); | ||
1821 | |||
1822 | static void __exit wm831x_i2c_exit(void) | ||
1823 | { | ||
1824 | i2c_del_driver(&wm831x_i2c_driver); | ||
1825 | } | ||
1826 | module_exit(wm831x_i2c_exit); | ||
1827 | |||
1828 | MODULE_DESCRIPTION("I2C support for the WM831X AudioPlus PMIC"); | ||
1829 | MODULE_LICENSE("GPL"); | 1713 | MODULE_LICENSE("GPL"); |
1830 | MODULE_AUTHOR("Mark Brown"); | 1714 | MODULE_AUTHOR("Mark Brown"); |
diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c new file mode 100644 index 000000000000..156b19859e81 --- /dev/null +++ b/drivers/mfd/wm831x-i2c.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * wm831x-i2c.c -- I2C access for Wolfson WM831x PMICs | ||
3 | * | ||
4 | * Copyright 2009,2010 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/mfd/core.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | #include <linux/mfd/wm831x/core.h> | ||
23 | #include <linux/mfd/wm831x/pdata.h> | ||
24 | |||
25 | static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg, | ||
26 | int bytes, void *dest) | ||
27 | { | ||
28 | struct i2c_client *i2c = wm831x->control_data; | ||
29 | int ret; | ||
30 | u16 r = cpu_to_be16(reg); | ||
31 | |||
32 | ret = i2c_master_send(i2c, (unsigned char *)&r, 2); | ||
33 | if (ret < 0) | ||
34 | return ret; | ||
35 | if (ret != 2) | ||
36 | return -EIO; | ||
37 | |||
38 | ret = i2c_master_recv(i2c, dest, bytes); | ||
39 | if (ret < 0) | ||
40 | return ret; | ||
41 | if (ret != bytes) | ||
42 | return -EIO; | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | /* Currently we allocate the write buffer on the stack; this is OK for | ||
47 | * small writes - if we need to do large writes this will need to be | ||
48 | * revised. | ||
49 | */ | ||
50 | static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg, | ||
51 | int bytes, void *src) | ||
52 | { | ||
53 | struct i2c_client *i2c = wm831x->control_data; | ||
54 | unsigned char msg[bytes + 2]; | ||
55 | int ret; | ||
56 | |||
57 | reg = cpu_to_be16(reg); | ||
58 | memcpy(&msg[0], ®, 2); | ||
59 | memcpy(&msg[2], src, bytes); | ||
60 | |||
61 | ret = i2c_master_send(i2c, msg, bytes + 2); | ||
62 | if (ret < 0) | ||
63 | return ret; | ||
64 | if (ret < bytes + 2) | ||
65 | return -EIO; | ||
66 | |||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | static int wm831x_i2c_probe(struct i2c_client *i2c, | ||
71 | const struct i2c_device_id *id) | ||
72 | { | ||
73 | struct wm831x *wm831x; | ||
74 | |||
75 | wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); | ||
76 | if (wm831x == NULL) | ||
77 | return -ENOMEM; | ||
78 | |||
79 | i2c_set_clientdata(i2c, wm831x); | ||
80 | wm831x->dev = &i2c->dev; | ||
81 | wm831x->control_data = i2c; | ||
82 | wm831x->read_dev = wm831x_i2c_read_device; | ||
83 | wm831x->write_dev = wm831x_i2c_write_device; | ||
84 | |||
85 | return wm831x_device_init(wm831x, id->driver_data, i2c->irq); | ||
86 | } | ||
87 | |||
88 | static int wm831x_i2c_remove(struct i2c_client *i2c) | ||
89 | { | ||
90 | struct wm831x *wm831x = i2c_get_clientdata(i2c); | ||
91 | |||
92 | wm831x_device_exit(wm831x); | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg) | ||
98 | { | ||
99 | struct wm831x *wm831x = i2c_get_clientdata(i2c); | ||
100 | |||
101 | return wm831x_device_suspend(wm831x); | ||
102 | } | ||
103 | |||
104 | static const struct i2c_device_id wm831x_i2c_id[] = { | ||
105 | { "wm8310", WM8310 }, | ||
106 | { "wm8311", WM8311 }, | ||
107 | { "wm8312", WM8312 }, | ||
108 | { "wm8320", WM8320 }, | ||
109 | { "wm8321", WM8321 }, | ||
110 | { "wm8325", WM8325 }, | ||
111 | { } | ||
112 | }; | ||
113 | MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id); | ||
114 | |||
115 | |||
116 | static struct i2c_driver wm831x_i2c_driver = { | ||
117 | .driver = { | ||
118 | .name = "wm831x", | ||
119 | .owner = THIS_MODULE, | ||
120 | }, | ||
121 | .probe = wm831x_i2c_probe, | ||
122 | .remove = wm831x_i2c_remove, | ||
123 | .suspend = wm831x_i2c_suspend, | ||
124 | .id_table = wm831x_i2c_id, | ||
125 | }; | ||
126 | |||
127 | static int __init wm831x_i2c_init(void) | ||
128 | { | ||
129 | int ret; | ||
130 | |||
131 | ret = i2c_add_driver(&wm831x_i2c_driver); | ||
132 | if (ret != 0) | ||
133 | pr_err("Failed to register wm831x I2C driver: %d\n", ret); | ||
134 | |||
135 | return ret; | ||
136 | } | ||
137 | subsys_initcall(wm831x_i2c_init); | ||
138 | |||
139 | static void __exit wm831x_i2c_exit(void) | ||
140 | { | ||
141 | i2c_del_driver(&wm831x_i2c_driver); | ||
142 | } | ||
143 | module_exit(wm831x_i2c_exit); | ||
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c new file mode 100644 index 000000000000..2789b151b0f9 --- /dev/null +++ b/drivers/mfd/wm831x-spi.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * wm831x-spi.c -- SPI access for Wolfson WM831x PMICs | ||
3 | * | ||
4 | * Copyright 2009,2010 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/spi/spi.h> | ||
18 | |||
19 | #include <linux/mfd/wm831x/core.h> | ||
20 | |||
21 | static int wm831x_spi_read_device(struct wm831x *wm831x, unsigned short reg, | ||
22 | int bytes, void *dest) | ||
23 | { | ||
24 | u16 tx_val; | ||
25 | u16 *d = dest; | ||
26 | int r, ret; | ||
27 | |||
28 | /* Go register at a time */ | ||
29 | for (r = reg; r < reg + (bytes / 2); r++) { | ||
30 | tx_val = r | 0x8000; | ||
31 | |||
32 | ret = spi_write_then_read(wm831x->control_data, | ||
33 | (u8 *)&tx_val, 2, (u8 *)d, 2); | ||
34 | if (ret != 0) | ||
35 | return ret; | ||
36 | |||
37 | *d = be16_to_cpu(*d); | ||
38 | |||
39 | d++; | ||
40 | } | ||
41 | |||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | static int wm831x_spi_write_device(struct wm831x *wm831x, unsigned short reg, | ||
46 | int bytes, void *src) | ||
47 | { | ||
48 | struct spi_device *spi = wm831x->control_data; | ||
49 | u16 *s = src; | ||
50 | u16 data[2]; | ||
51 | int ret, r; | ||
52 | |||
53 | /* Go register at a time */ | ||
54 | for (r = reg; r < reg + (bytes / 2); r++) { | ||
55 | data[0] = r; | ||
56 | data[1] = *s++; | ||
57 | |||
58 | ret = spi_write(spi, (char *)&data, sizeof(data)); | ||
59 | if (ret != 0) | ||
60 | return ret; | ||
61 | } | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static int __devinit wm831x_spi_probe(struct spi_device *spi) | ||
67 | { | ||
68 | struct wm831x *wm831x; | ||
69 | enum wm831x_parent type; | ||
70 | |||
71 | /* Currently SPI support for ID tables is unmerged, we're faking it */ | ||
72 | if (strcmp(spi->modalias, "wm8310") == 0) | ||
73 | type = WM8310; | ||
74 | else if (strcmp(spi->modalias, "wm8311") == 0) | ||
75 | type = WM8311; | ||
76 | else if (strcmp(spi->modalias, "wm8312") == 0) | ||
77 | type = WM8312; | ||
78 | else if (strcmp(spi->modalias, "wm8320") == 0) | ||
79 | type = WM8320; | ||
80 | else if (strcmp(spi->modalias, "wm8321") == 0) | ||
81 | type = WM8321; | ||
82 | else if (strcmp(spi->modalias, "wm8325") == 0) | ||
83 | type = WM8325; | ||
84 | else { | ||
85 | dev_err(&spi->dev, "Unknown device type\n"); | ||
86 | return -EINVAL; | ||
87 | } | ||
88 | |||
89 | wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); | ||
90 | if (wm831x == NULL) | ||
91 | return -ENOMEM; | ||
92 | |||
93 | spi->bits_per_word = 16; | ||
94 | spi->mode = SPI_MODE_0; | ||
95 | |||
96 | dev_set_drvdata(&spi->dev, wm831x); | ||
97 | wm831x->dev = &spi->dev; | ||
98 | wm831x->control_data = spi; | ||
99 | wm831x->read_dev = wm831x_spi_read_device; | ||
100 | wm831x->write_dev = wm831x_spi_write_device; | ||
101 | |||
102 | return wm831x_device_init(wm831x, type, spi->irq); | ||
103 | } | ||
104 | |||
105 | static int __devexit wm831x_spi_remove(struct spi_device *spi) | ||
106 | { | ||
107 | struct wm831x *wm831x = dev_get_drvdata(&spi->dev); | ||
108 | |||
109 | wm831x_device_exit(wm831x); | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static int wm831x_spi_suspend(struct spi_device *spi, pm_message_t m) | ||
115 | { | ||
116 | struct wm831x *wm831x = dev_get_drvdata(&spi->dev); | ||
117 | |||
118 | return wm831x_device_suspend(wm831x); | ||
119 | } | ||
120 | |||
121 | static struct spi_driver wm8310_spi_driver = { | ||
122 | .driver = { | ||
123 | .name = "wm8310", | ||
124 | .bus = &spi_bus_type, | ||
125 | .owner = THIS_MODULE, | ||
126 | }, | ||
127 | .probe = wm831x_spi_probe, | ||
128 | .remove = __devexit_p(wm831x_spi_remove), | ||
129 | .suspend = wm831x_spi_suspend, | ||
130 | }; | ||
131 | |||
132 | static struct spi_driver wm8311_spi_driver = { | ||
133 | .driver = { | ||
134 | .name = "wm8311", | ||
135 | .bus = &spi_bus_type, | ||
136 | .owner = THIS_MODULE, | ||
137 | }, | ||
138 | .probe = wm831x_spi_probe, | ||
139 | .remove = __devexit_p(wm831x_spi_remove), | ||
140 | .suspend = wm831x_spi_suspend, | ||
141 | }; | ||
142 | |||
143 | static struct spi_driver wm8312_spi_driver = { | ||
144 | .driver = { | ||
145 | .name = "wm8312", | ||
146 | .bus = &spi_bus_type, | ||
147 | .owner = THIS_MODULE, | ||
148 | }, | ||
149 | .probe = wm831x_spi_probe, | ||
150 | .remove = __devexit_p(wm831x_spi_remove), | ||
151 | .suspend = wm831x_spi_suspend, | ||
152 | }; | ||
153 | |||
154 | static struct spi_driver wm8320_spi_driver = { | ||
155 | .driver = { | ||
156 | .name = "wm8320", | ||
157 | .bus = &spi_bus_type, | ||
158 | .owner = THIS_MODULE, | ||
159 | }, | ||
160 | .probe = wm831x_spi_probe, | ||
161 | .remove = __devexit_p(wm831x_spi_remove), | ||
162 | .suspend = wm831x_spi_suspend, | ||
163 | }; | ||
164 | |||
165 | static struct spi_driver wm8321_spi_driver = { | ||
166 | .driver = { | ||
167 | .name = "wm8321", | ||
168 | .bus = &spi_bus_type, | ||
169 | .owner = THIS_MODULE, | ||
170 | }, | ||
171 | .probe = wm831x_spi_probe, | ||
172 | .remove = __devexit_p(wm831x_spi_remove), | ||
173 | .suspend = wm831x_spi_suspend, | ||
174 | }; | ||
175 | |||
176 | static struct spi_driver wm8325_spi_driver = { | ||
177 | .driver = { | ||
178 | .name = "wm8325", | ||
179 | .bus = &spi_bus_type, | ||
180 | .owner = THIS_MODULE, | ||
181 | }, | ||
182 | .probe = wm831x_spi_probe, | ||
183 | .remove = __devexit_p(wm831x_spi_remove), | ||
184 | .suspend = wm831x_spi_suspend, | ||
185 | }; | ||
186 | |||
187 | static int __init wm831x_spi_init(void) | ||
188 | { | ||
189 | int ret; | ||
190 | |||
191 | ret = spi_register_driver(&wm8310_spi_driver); | ||
192 | if (ret != 0) | ||
193 | pr_err("Failed to register WM8310 SPI driver: %d\n", ret); | ||
194 | |||
195 | ret = spi_register_driver(&wm8311_spi_driver); | ||
196 | if (ret != 0) | ||
197 | pr_err("Failed to register WM8311 SPI driver: %d\n", ret); | ||
198 | |||
199 | ret = spi_register_driver(&wm8312_spi_driver); | ||
200 | if (ret != 0) | ||
201 | pr_err("Failed to register WM8312 SPI driver: %d\n", ret); | ||
202 | |||
203 | ret = spi_register_driver(&wm8320_spi_driver); | ||
204 | if (ret != 0) | ||
205 | pr_err("Failed to register WM8320 SPI driver: %d\n", ret); | ||
206 | |||
207 | ret = spi_register_driver(&wm8321_spi_driver); | ||
208 | if (ret != 0) | ||
209 | pr_err("Failed to register WM8321 SPI driver: %d\n", ret); | ||
210 | |||
211 | ret = spi_register_driver(&wm8325_spi_driver); | ||
212 | if (ret != 0) | ||
213 | pr_err("Failed to register WM8325 SPI driver: %d\n", ret); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | subsys_initcall(wm831x_spi_init); | ||
218 | |||
219 | static void __exit wm831x_spi_exit(void) | ||
220 | { | ||
221 | spi_unregister_driver(&wm8325_spi_driver); | ||
222 | spi_unregister_driver(&wm8321_spi_driver); | ||
223 | spi_unregister_driver(&wm8320_spi_driver); | ||
224 | spi_unregister_driver(&wm8312_spi_driver); | ||
225 | spi_unregister_driver(&wm8311_spi_driver); | ||
226 | spi_unregister_driver(&wm8310_spi_driver); | ||
227 | } | ||
228 | module_exit(wm831x_spi_exit); | ||
229 | |||
230 | MODULE_DESCRIPTION("SPI support for WM831x/2x AudioPlus PMICs"); | ||
231 | MODULE_LICENSE("GPL"); | ||
232 | MODULE_AUTHOR("Mark Brown"); | ||