diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-14 13:02:35 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-14 13:02:35 -0500 |
| commit | 76b8f82cde2d9c13ef0c9a9aa2581b9b30b68e8c (patch) | |
| tree | f94b370b95051b4a7b3c272b4b2ee20091e1b746 /drivers | |
| parent | af853e631db12a97363c8c3b727d153bd2cb346b (diff) | |
| parent | 9da66539281b5e15afc4a4739014c8923059d894 (diff) | |
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (58 commits)
mfd: Add twl6030 regulator subdevices
regulator: Add support for twl6030 regulators
rtc: Add twl6030 RTC support
mfd: Add support for twl6030 irq framework
mfd: Rename twl4030_ routines in twl-regulator.c
mfd: Rename twl4030_ routines in rtc-twl.c
mfd: Rename all twl4030_i2c*
mfd: Rename twl4030* driver files to enable re-use
mfd: Clarify twl4030 return value for read and write
mfd: Add all twl4030 regulators to the twl4030 mfd driver
mfd: Don't set mc13783 ADREFMODE for touch conversions
mfd: Remove ezx-pcap defines for custom led gpio encoding
mfd: Near complete mc13783 rewrite
mfd: Remove build time warning for WM835x register default tables
mfd: Force I2C to be built in when building WM831x
mfd: Don't allow wm831x to be built as a module
mfd: Fix incorrect error check for wm8350-core
mfd: Fix twl4030 warning
gpiolib: Implement gpio_to_irq() for wm831x
mfd: Remove default selection of AB4500
...
Diffstat (limited to 'drivers')
46 files changed, 3919 insertions, 1783 deletions
diff --git a/drivers/gpio/adp5520-gpio.c b/drivers/gpio/adp5520-gpio.c index ad05bbc7ffd5..0f93105873cd 100644 --- a/drivers/gpio/adp5520-gpio.c +++ b/drivers/gpio/adp5520-gpio.c | |||
| @@ -34,9 +34,9 @@ static int adp5520_gpio_get_value(struct gpio_chip *chip, unsigned off) | |||
| 34 | */ | 34 | */ |
| 35 | 35 | ||
| 36 | if (test_bit(off, &dev->output)) | 36 | if (test_bit(off, &dev->output)) |
| 37 | adp5520_read(dev->master, GPIO_OUT, ®_val); | 37 | adp5520_read(dev->master, ADP5520_GPIO_OUT, ®_val); |
| 38 | else | 38 | else |
| 39 | adp5520_read(dev->master, GPIO_IN, ®_val); | 39 | adp5520_read(dev->master, ADP5520_GPIO_IN, ®_val); |
| 40 | 40 | ||
| 41 | return !!(reg_val & dev->lut[off]); | 41 | return !!(reg_val & dev->lut[off]); |
| 42 | } | 42 | } |
| @@ -48,9 +48,9 @@ static void adp5520_gpio_set_value(struct gpio_chip *chip, | |||
| 48 | dev = container_of(chip, struct adp5520_gpio, gpio_chip); | 48 | dev = container_of(chip, struct adp5520_gpio, gpio_chip); |
| 49 | 49 | ||
| 50 | if (val) | 50 | if (val) |
| 51 | adp5520_set_bits(dev->master, GPIO_OUT, dev->lut[off]); | 51 | adp5520_set_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]); |
| 52 | else | 52 | else |
| 53 | adp5520_clr_bits(dev->master, GPIO_OUT, dev->lut[off]); | 53 | adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | static int adp5520_gpio_direction_input(struct gpio_chip *chip, unsigned off) | 56 | static int adp5520_gpio_direction_input(struct gpio_chip *chip, unsigned off) |
| @@ -60,7 +60,8 @@ static int adp5520_gpio_direction_input(struct gpio_chip *chip, unsigned off) | |||
| 60 | 60 | ||
| 61 | clear_bit(off, &dev->output); | 61 | clear_bit(off, &dev->output); |
| 62 | 62 | ||
| 63 | return adp5520_clr_bits(dev->master, GPIO_CFG_2, dev->lut[off]); | 63 | return adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_2, |
| 64 | dev->lut[off]); | ||
| 64 | } | 65 | } |
| 65 | 66 | ||
| 66 | static int adp5520_gpio_direction_output(struct gpio_chip *chip, | 67 | static int adp5520_gpio_direction_output(struct gpio_chip *chip, |
| @@ -73,18 +74,21 @@ static int adp5520_gpio_direction_output(struct gpio_chip *chip, | |||
| 73 | set_bit(off, &dev->output); | 74 | set_bit(off, &dev->output); |
| 74 | 75 | ||
| 75 | if (val) | 76 | if (val) |
| 76 | ret |= adp5520_set_bits(dev->master, GPIO_OUT, dev->lut[off]); | 77 | ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_OUT, |
| 78 | dev->lut[off]); | ||
| 77 | else | 79 | else |
| 78 | ret |= adp5520_clr_bits(dev->master, GPIO_OUT, dev->lut[off]); | 80 | ret |= adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT, |
| 81 | dev->lut[off]); | ||
| 79 | 82 | ||
| 80 | ret |= adp5520_set_bits(dev->master, GPIO_CFG_2, dev->lut[off]); | 83 | ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_CFG_2, |
| 84 | dev->lut[off]); | ||
| 81 | 85 | ||
| 82 | return ret; | 86 | return ret; |
| 83 | } | 87 | } |
| 84 | 88 | ||
| 85 | static int __devinit adp5520_gpio_probe(struct platform_device *pdev) | 89 | static int __devinit adp5520_gpio_probe(struct platform_device *pdev) |
| 86 | { | 90 | { |
| 87 | struct adp5520_gpio_platfrom_data *pdata = pdev->dev.platform_data; | 91 | struct adp5520_gpio_platform_data *pdata = pdev->dev.platform_data; |
| 88 | struct adp5520_gpio *dev; | 92 | struct adp5520_gpio *dev; |
| 89 | struct gpio_chip *gc; | 93 | struct gpio_chip *gc; |
| 90 | int ret, i, gpios; | 94 | int ret, i, gpios; |
| @@ -129,20 +133,20 @@ static int __devinit adp5520_gpio_probe(struct platform_device *pdev) | |||
| 129 | gc->label = pdev->name; | 133 | gc->label = pdev->name; |
| 130 | gc->owner = THIS_MODULE; | 134 | gc->owner = THIS_MODULE; |
| 131 | 135 | ||
| 132 | ret = adp5520_clr_bits(dev->master, GPIO_CFG_1, | 136 | ret = adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_1, |
| 133 | pdata->gpio_en_mask); | 137 | pdata->gpio_en_mask); |
| 134 | 138 | ||
| 135 | if (pdata->gpio_en_mask & GPIO_C3) | 139 | if (pdata->gpio_en_mask & ADP5520_GPIO_C3) |
| 136 | ctl_mask |= C3_MODE; | 140 | ctl_mask |= ADP5520_C3_MODE; |
| 137 | 141 | ||
| 138 | if (pdata->gpio_en_mask & GPIO_R3) | 142 | if (pdata->gpio_en_mask & ADP5520_GPIO_R3) |
| 139 | ctl_mask |= R3_MODE; | 143 | ctl_mask |= ADP5520_R3_MODE; |
| 140 | 144 | ||
| 141 | if (ctl_mask) | 145 | if (ctl_mask) |
| 142 | ret = adp5520_set_bits(dev->master, LED_CONTROL, | 146 | ret = adp5520_set_bits(dev->master, ADP5520_LED_CONTROL, |
| 143 | ctl_mask); | 147 | ctl_mask); |
| 144 | 148 | ||
| 145 | ret |= adp5520_set_bits(dev->master, GPIO_PULLUP, | 149 | ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_PULLUP, |
| 146 | pdata->gpio_pullup_mask); | 150 | pdata->gpio_pullup_mask); |
| 147 | 151 | ||
| 148 | if (ret) { | 152 | if (ret) { |
diff --git a/drivers/gpio/twl4030-gpio.c b/drivers/gpio/twl4030-gpio.c index 49384a7c5492..7fe881e2bdfb 100644 --- a/drivers/gpio/twl4030-gpio.c +++ b/drivers/gpio/twl4030-gpio.c | |||
| @@ -34,7 +34,7 @@ | |||
| 34 | #include <linux/platform_device.h> | 34 | #include <linux/platform_device.h> |
| 35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
| 36 | 36 | ||
| 37 | #include <linux/i2c/twl4030.h> | 37 | #include <linux/i2c/twl.h> |
| 38 | 38 | ||
| 39 | 39 | ||
| 40 | /* | 40 | /* |
| @@ -80,7 +80,7 @@ static unsigned int gpio_usage_count; | |||
| 80 | */ | 80 | */ |
| 81 | static inline int gpio_twl4030_write(u8 address, u8 data) | 81 | static inline int gpio_twl4030_write(u8 address, u8 data) |
| 82 | { | 82 | { |
| 83 | return twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, data, address); | 83 | return twl_i2c_write_u8(TWL4030_MODULE_GPIO, data, address); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | /*----------------------------------------------------------------------*/ | 86 | /*----------------------------------------------------------------------*/ |
| @@ -117,7 +117,7 @@ static inline int gpio_twl4030_read(u8 address) | |||
| 117 | u8 data; | 117 | u8 data; |
| 118 | int ret = 0; | 118 | int ret = 0; |
| 119 | 119 | ||
| 120 | ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &data, address); | 120 | ret = twl_i2c_read_u8(TWL4030_MODULE_GPIO, &data, address); |
| 121 | return (ret < 0) ? ret : data; | 121 | return (ret < 0) ? ret : data; |
| 122 | } | 122 | } |
| 123 | 123 | ||
| @@ -142,7 +142,7 @@ static void twl4030_led_set_value(int led, int value) | |||
| 142 | cached_leden &= ~mask; | 142 | cached_leden &= ~mask; |
| 143 | else | 143 | else |
| 144 | cached_leden |= mask; | 144 | cached_leden |= mask; |
| 145 | status = twl4030_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, | 145 | status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, |
| 146 | TWL4030_LED_LEDEN); | 146 | TWL4030_LED_LEDEN); |
| 147 | mutex_unlock(&gpio_lock); | 147 | mutex_unlock(&gpio_lock); |
| 148 | } | 148 | } |
| @@ -223,23 +223,23 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) | |||
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | /* initialize PWM to always-drive */ | 225 | /* initialize PWM to always-drive */ |
| 226 | status = twl4030_i2c_write_u8(module, 0x7f, | 226 | status = twl_i2c_write_u8(module, 0x7f, |
| 227 | TWL4030_PWMx_PWMxOFF); | 227 | TWL4030_PWMx_PWMxOFF); |
| 228 | if (status < 0) | 228 | if (status < 0) |
| 229 | goto done; | 229 | goto done; |
| 230 | status = twl4030_i2c_write_u8(module, 0x7f, | 230 | status = twl_i2c_write_u8(module, 0x7f, |
| 231 | TWL4030_PWMx_PWMxON); | 231 | TWL4030_PWMx_PWMxON); |
| 232 | if (status < 0) | 232 | if (status < 0) |
| 233 | goto done; | 233 | goto done; |
| 234 | 234 | ||
| 235 | /* init LED to not-driven (high) */ | 235 | /* init LED to not-driven (high) */ |
| 236 | module = TWL4030_MODULE_LED; | 236 | module = TWL4030_MODULE_LED; |
| 237 | status = twl4030_i2c_read_u8(module, &cached_leden, | 237 | status = twl_i2c_read_u8(module, &cached_leden, |
| 238 | TWL4030_LED_LEDEN); | 238 | TWL4030_LED_LEDEN); |
| 239 | if (status < 0) | 239 | if (status < 0) |
| 240 | goto done; | 240 | goto done; |
| 241 | cached_leden &= ~ledclr_mask; | 241 | cached_leden &= ~ledclr_mask; |
| 242 | status = twl4030_i2c_write_u8(module, cached_leden, | 242 | status = twl_i2c_write_u8(module, cached_leden, |
| 243 | TWL4030_LED_LEDEN); | 243 | TWL4030_LED_LEDEN); |
| 244 | if (status < 0) | 244 | if (status < 0) |
| 245 | goto done; | 245 | goto done; |
| @@ -370,7 +370,7 @@ static int __devinit gpio_twl4030_pulls(u32 ups, u32 downs) | |||
| 370 | message[i] = bit_mask; | 370 | message[i] = bit_mask; |
| 371 | } | 371 | } |
| 372 | 372 | ||
| 373 | return twl4030_i2c_write(TWL4030_MODULE_GPIO, message, | 373 | return twl_i2c_write(TWL4030_MODULE_GPIO, message, |
| 374 | REG_GPIOPUPDCTR1, 5); | 374 | REG_GPIOPUPDCTR1, 5); |
| 375 | } | 375 | } |
| 376 | 376 | ||
| @@ -387,7 +387,7 @@ static int __devinit gpio_twl4030_debounce(u32 debounce, u8 mmc_cd) | |||
| 387 | debounce >>= 8; | 387 | debounce >>= 8; |
| 388 | message[3] = (debounce & 0x03); | 388 | message[3] = (debounce & 0x03); |
| 389 | 389 | ||
| 390 | return twl4030_i2c_write(TWL4030_MODULE_GPIO, message, | 390 | return twl_i2c_write(TWL4030_MODULE_GPIO, message, |
| 391 | REG_GPIO_DEBEN1, 3); | 391 | REG_GPIO_DEBEN1, 3); |
| 392 | } | 392 | } |
| 393 | 393 | ||
diff --git a/drivers/gpio/wm831x-gpio.c b/drivers/gpio/wm831x-gpio.c index f9c09a54ec7f..b4468b616890 100644 --- a/drivers/gpio/wm831x-gpio.c +++ b/drivers/gpio/wm831x-gpio.c | |||
| @@ -22,8 +22,7 @@ | |||
| 22 | #include <linux/mfd/wm831x/core.h> | 22 | #include <linux/mfd/wm831x/core.h> |
| 23 | #include <linux/mfd/wm831x/pdata.h> | 23 | #include <linux/mfd/wm831x/pdata.h> |
| 24 | #include <linux/mfd/wm831x/gpio.h> | 24 | #include <linux/mfd/wm831x/gpio.h> |
| 25 | 25 | #include <linux/mfd/wm831x/irq.h> | |
| 26 | #define WM831X_GPIO_MAX 16 | ||
| 27 | 26 | ||
| 28 | struct wm831x_gpio { | 27 | struct wm831x_gpio { |
| 29 | struct wm831x *wm831x; | 28 | struct wm831x *wm831x; |
| @@ -80,6 +79,17 @@ static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | |||
| 80 | value << offset); | 79 | value << offset); |
| 81 | } | 80 | } |
| 82 | 81 | ||
| 82 | static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | ||
| 83 | { | ||
| 84 | struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip); | ||
| 85 | struct wm831x *wm831x = wm831x_gpio->wm831x; | ||
| 86 | |||
| 87 | if (!wm831x->irq_base) | ||
| 88 | return -EINVAL; | ||
| 89 | |||
| 90 | return wm831x->irq_base + WM831X_IRQ_GPIO_1 + offset; | ||
| 91 | } | ||
| 92 | |||
| 83 | #ifdef CONFIG_DEBUG_FS | 93 | #ifdef CONFIG_DEBUG_FS |
| 84 | static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) | 94 | static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) |
| 85 | { | 95 | { |
| @@ -175,6 +185,7 @@ static struct gpio_chip template_chip = { | |||
| 175 | .get = wm831x_gpio_get, | 185 | .get = wm831x_gpio_get, |
| 176 | .direction_output = wm831x_gpio_direction_out, | 186 | .direction_output = wm831x_gpio_direction_out, |
| 177 | .set = wm831x_gpio_set, | 187 | .set = wm831x_gpio_set, |
| 188 | .to_irq = wm831x_gpio_to_irq, | ||
| 178 | .dbg_show = wm831x_gpio_dbg_show, | 189 | .dbg_show = wm831x_gpio_dbg_show, |
| 179 | .can_sleep = 1, | 190 | .can_sleep = 1, |
| 180 | }; | 191 | }; |
| @@ -192,7 +203,7 @@ static int __devinit wm831x_gpio_probe(struct platform_device *pdev) | |||
| 192 | 203 | ||
| 193 | wm831x_gpio->wm831x = wm831x; | 204 | wm831x_gpio->wm831x = wm831x; |
| 194 | wm831x_gpio->gpio_chip = template_chip; | 205 | wm831x_gpio->gpio_chip = template_chip; |
| 195 | wm831x_gpio->gpio_chip.ngpio = WM831X_GPIO_MAX; | 206 | wm831x_gpio->gpio_chip.ngpio = wm831x->num_gpio; |
| 196 | wm831x_gpio->gpio_chip.dev = &pdev->dev; | 207 | wm831x_gpio->gpio_chip.dev = &pdev->dev; |
| 197 | if (pdata && pdata->gpio_base) | 208 | if (pdata && pdata->gpio_base) |
| 198 | wm831x_gpio->gpio_chip.base = pdata->gpio_base; | 209 | wm831x_gpio->gpio_chip.base = pdata->gpio_base; |
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 203b88a82b56..02c836e11813 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
| @@ -24,6 +24,16 @@ config KEYBOARD_AAED2000 | |||
| 24 | To compile this driver as a module, choose M here: the | 24 | To compile this driver as a module, choose M here: the |
| 25 | module will be called aaed2000_kbd. | 25 | module will be called aaed2000_kbd. |
| 26 | 26 | ||
| 27 | config KEYBOARD_ADP5520 | ||
| 28 | tristate "Keypad Support for ADP5520 PMIC" | ||
| 29 | depends on PMIC_ADP5520 | ||
| 30 | help | ||
| 31 | This option enables support for the keypad scan matrix | ||
| 32 | on Analog Devices ADP5520 PMICs. | ||
| 33 | |||
| 34 | To compile this driver as a module, choose M here: the module will | ||
| 35 | be called adp5520-keys. | ||
| 36 | |||
| 27 | config KEYBOARD_ADP5588 | 37 | config KEYBOARD_ADP5588 |
| 28 | tristate "ADP5588 I2C QWERTY Keypad and IO Expander" | 38 | tristate "ADP5588 I2C QWERTY Keypad and IO Expander" |
| 29 | depends on I2C | 39 | depends on I2C |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 68c017235ce9..78654ef65206 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | # Each configuration option enables a list of files. | 5 | # Each configuration option enables a list of files. |
| 6 | 6 | ||
| 7 | obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o | 7 | obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o |
| 8 | obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o | ||
| 8 | obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o | 9 | obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o |
| 9 | obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o | 10 | obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o |
| 10 | obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o | 11 | obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o |
diff --git a/drivers/input/keyboard/adp5520-keys.c b/drivers/input/keyboard/adp5520-keys.c new file mode 100644 index 000000000000..a7ba27fb4109 --- /dev/null +++ b/drivers/input/keyboard/adp5520-keys.c | |||
| @@ -0,0 +1,220 @@ | |||
| 1 | /* | ||
| 2 | * Keypad driver for Analog Devices ADP5520 MFD PMICs | ||
| 3 | * | ||
| 4 | * Copyright 2009 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/kernel.h> | ||
| 11 | #include <linux/init.h> | ||
| 12 | #include <linux/platform_device.h> | ||
| 13 | #include <linux/input.h> | ||
| 14 | #include <linux/mfd/adp5520.h> | ||
| 15 | |||
| 16 | struct adp5520_keys { | ||
| 17 | struct input_dev *input; | ||
| 18 | struct notifier_block notifier; | ||
| 19 | struct device *master; | ||
| 20 | unsigned short keycode[ADP5520_KEYMAPSIZE]; | ||
| 21 | }; | ||
| 22 | |||
| 23 | static void adp5520_keys_report_event(struct adp5520_keys *dev, | ||
| 24 | unsigned short keymask, int value) | ||
| 25 | { | ||
| 26 | int i; | ||
| 27 | |||
| 28 | for (i = 0; i < ADP5520_MAXKEYS; i++) | ||
| 29 | if (keymask & (1 << i)) | ||
| 30 | input_report_key(dev->input, dev->keycode[i], value); | ||
| 31 | |||
| 32 | input_sync(dev->input); | ||
| 33 | } | ||
| 34 | |||
| 35 | static int adp5520_keys_notifier(struct notifier_block *nb, | ||
| 36 | unsigned long event, void *data) | ||
| 37 | { | ||
| 38 | struct adp5520_keys *dev; | ||
| 39 | uint8_t reg_val_lo, reg_val_hi; | ||
| 40 | unsigned short keymask; | ||
| 41 | |||
| 42 | dev = container_of(nb, struct adp5520_keys, notifier); | ||
| 43 | |||
| 44 | if (event & ADP5520_KP_INT) { | ||
| 45 | adp5520_read(dev->master, ADP5520_KP_INT_STAT_1, ®_val_lo); | ||
| 46 | adp5520_read(dev->master, ADP5520_KP_INT_STAT_2, ®_val_hi); | ||
| 47 | |||
| 48 | keymask = (reg_val_hi << 8) | reg_val_lo; | ||
| 49 | /* Read twice to clear */ | ||
| 50 | adp5520_read(dev->master, ADP5520_KP_INT_STAT_1, ®_val_lo); | ||
| 51 | adp5520_read(dev->master, ADP5520_KP_INT_STAT_2, ®_val_hi); | ||
| 52 | keymask |= (reg_val_hi << 8) | reg_val_lo; | ||
| 53 | adp5520_keys_report_event(dev, keymask, 1); | ||
| 54 | } | ||
| 55 | |||
| 56 | if (event & ADP5520_KR_INT) { | ||
| 57 | adp5520_read(dev->master, ADP5520_KR_INT_STAT_1, ®_val_lo); | ||
| 58 | adp5520_read(dev->master, ADP5520_KR_INT_STAT_2, ®_val_hi); | ||
| 59 | |||
| 60 | keymask = (reg_val_hi << 8) | reg_val_lo; | ||
| 61 | /* Read twice to clear */ | ||
| 62 | adp5520_read(dev->master, ADP5520_KR_INT_STAT_1, ®_val_lo); | ||
| 63 | adp5520_read(dev->master, ADP5520_KR_INT_STAT_2, ®_val_hi); | ||
| 64 | keymask |= (reg_val_hi << 8) | reg_val_lo; | ||
| 65 | adp5520_keys_report_event(dev, keymask, 0); | ||
| 66 | } | ||
| 67 | |||
| 68 | return 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | static int __devinit adp5520_keys_probe(struct platform_device *pdev) | ||
| 72 | { | ||
| 73 | struct adp5520_keys_platform_data *pdata = pdev->dev.platform_data; | ||
| 74 | struct input_dev *input; | ||
| 75 | struct adp5520_keys *dev; | ||
| 76 | int ret, i; | ||
| 77 | unsigned char en_mask, ctl_mask = 0; | ||
| 78 | |||
| 79 | if (pdev->id != ID_ADP5520) { | ||
| 80 | dev_err(&pdev->dev, "only ADP5520 supports Keypad\n"); | ||
| 81 | return -EINVAL; | ||
| 82 | } | ||
| 83 | |||
| 84 | if (pdata == NULL) { | ||
| 85 | dev_err(&pdev->dev, "missing platform data\n"); | ||
| 86 | return -EINVAL; | ||
| 87 | } | ||
| 88 | |||
| 89 | if (!(pdata->rows_en_mask && pdata->cols_en_mask)) | ||
| 90 | return -EINVAL; | ||
| 91 | |||
| 92 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
| 93 | if (dev == NULL) { | ||
| 94 | dev_err(&pdev->dev, "failed to alloc memory\n"); | ||
| 95 | return -ENOMEM; | ||
| 96 | } | ||
| 97 | |||
| 98 | input = input_allocate_device(); | ||
| 99 | if (!input) { | ||
| 100 | ret = -ENOMEM; | ||
| 101 | goto err; | ||
| 102 | } | ||
| 103 | |||
| 104 | dev->master = pdev->dev.parent; | ||
| 105 | dev->input = input; | ||
| 106 | |||
| 107 | input->name = pdev->name; | ||
| 108 | input->phys = "adp5520-keys/input0"; | ||
| 109 | input->dev.parent = &pdev->dev; | ||
| 110 | |||
| 111 | input_set_drvdata(input, dev); | ||
| 112 | |||
| 113 | input->id.bustype = BUS_I2C; | ||
| 114 | input->id.vendor = 0x0001; | ||
| 115 | input->id.product = 0x5520; | ||
| 116 | input->id.version = 0x0001; | ||
| 117 | |||
| 118 | input->keycodesize = sizeof(dev->keycode[0]); | ||
| 119 | input->keycodemax = pdata->keymapsize; | ||
| 120 | input->keycode = dev->keycode; | ||
| 121 | |||
| 122 | memcpy(dev->keycode, pdata->keymap, | ||
| 123 | pdata->keymapsize * input->keycodesize); | ||
| 124 | |||
| 125 | /* setup input device */ | ||
| 126 | __set_bit(EV_KEY, input->evbit); | ||
| 127 | |||
| 128 | if (pdata->repeat) | ||
| 129 | __set_bit(EV_REP, input->evbit); | ||
| 130 | |||
| 131 | for (i = 0; i < input->keycodemax; i++) | ||
| 132 | __set_bit(dev->keycode[i], input->keybit); | ||
| 133 | __clear_bit(KEY_RESERVED, input->keybit); | ||
| 134 | |||
| 135 | ret = input_register_device(input); | ||
| 136 | if (ret) { | ||
| 137 | dev_err(&pdev->dev, "unable to register input device\n"); | ||
| 138 | goto err; | ||
| 139 | } | ||
| 140 | |||
| 141 | en_mask = pdata->rows_en_mask | pdata->cols_en_mask; | ||
| 142 | |||
| 143 | ret = adp5520_set_bits(dev->master, ADP5520_GPIO_CFG_1, en_mask); | ||
| 144 | |||
| 145 | if (en_mask & ADP5520_COL_C3) | ||
| 146 | ctl_mask |= ADP5520_C3_MODE; | ||
| 147 | |||
| 148 | if (en_mask & ADP5520_ROW_R3) | ||
| 149 | ctl_mask |= ADP5520_R3_MODE; | ||
| 150 | |||
| 151 | if (ctl_mask) | ||
| 152 | ret |= adp5520_set_bits(dev->master, ADP5520_LED_CONTROL, | ||
| 153 | ctl_mask); | ||
| 154 | |||
| 155 | ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_PULLUP, | ||
| 156 | pdata->rows_en_mask); | ||
| 157 | |||
| 158 | if (ret) { | ||
| 159 | dev_err(&pdev->dev, "failed to write\n"); | ||
| 160 | ret = -EIO; | ||
| 161 | goto err1; | ||
| 162 | } | ||
| 163 | |||
| 164 | dev->notifier.notifier_call = adp5520_keys_notifier; | ||
| 165 | ret = adp5520_register_notifier(dev->master, &dev->notifier, | ||
| 166 | ADP5520_KP_IEN | ADP5520_KR_IEN); | ||
| 167 | if (ret) { | ||
| 168 | dev_err(&pdev->dev, "failed to register notifier\n"); | ||
| 169 | goto err1; | ||
| 170 | } | ||
| 171 | |||
| 172 | platform_set_drvdata(pdev, dev); | ||
| 173 | return 0; | ||
| 174 | |||
| 175 | err1: | ||
| 176 | input_unregister_device(input); | ||
| 177 | input = NULL; | ||
| 178 | err: | ||
| 179 | input_free_device(input); | ||
| 180 | kfree(dev); | ||
| 181 | return ret; | ||
| 182 | } | ||
| 183 | |||
| 184 | static int __devexit adp5520_keys_remove(struct platform_device *pdev) | ||
| 185 | { | ||
| 186 | struct adp5520_keys *dev = platform_get_drvdata(pdev); | ||
| 187 | |||
| 188 | adp5520_unregister_notifier(dev->master, &dev->notifier, | ||
| 189 | ADP5520_KP_IEN | ADP5520_KR_IEN); | ||
| 190 | |||
| 191 | input_unregister_device(dev->input); | ||
| 192 | kfree(dev); | ||
| 193 | return 0; | ||
| 194 | } | ||
| 195 | |||
| 196 | static struct platform_driver adp5520_keys_driver = { | ||
| 197 | .driver = { | ||
| 198 | .name = "adp5520-keys", | ||
| 199 | .owner = THIS_MODULE, | ||
| 200 | }, | ||
| 201 | .probe = adp5520_keys_probe, | ||
| 202 | .remove = __devexit_p(adp5520_keys_remove), | ||
| 203 | }; | ||
| 204 | |||
| 205 | static int __init adp5520_keys_init(void) | ||
| 206 | { | ||
| 207 | return platform_driver_register(&adp5520_keys_driver); | ||
| 208 | } | ||
| 209 | module_init(adp5520_keys_init); | ||
| 210 | |||
| 211 | static void __exit adp5520_keys_exit(void) | ||
| 212 | { | ||
| 213 | platform_driver_unregister(&adp5520_keys_driver); | ||
| 214 | } | ||
| 215 | module_exit(adp5520_keys_exit); | ||
| 216 | |||
| 217 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
| 218 | MODULE_DESCRIPTION("Keys ADP5520 Driver"); | ||
| 219 | MODULE_LICENSE("GPL"); | ||
| 220 | MODULE_ALIAS("platform:adp5520-keys"); | ||
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index 9a2977c21696..eeaa7acb9cfc 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c | |||
| @@ -31,7 +31,7 @@ | |||
| 31 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
| 32 | #include <linux/input.h> | 32 | #include <linux/input.h> |
| 33 | #include <linux/platform_device.h> | 33 | #include <linux/platform_device.h> |
| 34 | #include <linux/i2c/twl4030.h> | 34 | #include <linux/i2c/twl.h> |
| 35 | 35 | ||
| 36 | 36 | ||
| 37 | /* | 37 | /* |
| @@ -133,7 +133,7 @@ struct twl4030_keypad { | |||
| 133 | static int twl4030_kpread(struct twl4030_keypad *kp, | 133 | static int twl4030_kpread(struct twl4030_keypad *kp, |
| 134 | u8 *data, u32 reg, u8 num_bytes) | 134 | u8 *data, u32 reg, u8 num_bytes) |
| 135 | { | 135 | { |
| 136 | int ret = twl4030_i2c_read(TWL4030_MODULE_KEYPAD, data, reg, num_bytes); | 136 | int ret = twl_i2c_read(TWL4030_MODULE_KEYPAD, data, reg, num_bytes); |
| 137 | 137 | ||
| 138 | if (ret < 0) | 138 | if (ret < 0) |
| 139 | dev_warn(kp->dbg_dev, | 139 | dev_warn(kp->dbg_dev, |
| @@ -145,7 +145,7 @@ static int twl4030_kpread(struct twl4030_keypad *kp, | |||
| 145 | 145 | ||
| 146 | static int twl4030_kpwrite_u8(struct twl4030_keypad *kp, u8 data, u32 reg) | 146 | static int twl4030_kpwrite_u8(struct twl4030_keypad *kp, u8 data, u32 reg) |
| 147 | { | 147 | { |
| 148 | int ret = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, data, reg); | 148 | int ret = twl_i2c_write_u8(TWL4030_MODULE_KEYPAD, data, reg); |
| 149 | 149 | ||
| 150 | if (ret < 0) | 150 | if (ret < 0) |
| 151 | dev_warn(kp->dbg_dev, | 151 | dev_warn(kp->dbg_dev, |
diff --git a/drivers/input/misc/pcf50633-input.c b/drivers/input/misc/pcf50633-input.c index 039dcb00ebd9..008de0c5834b 100644 --- a/drivers/input/misc/pcf50633-input.c +++ b/drivers/input/misc/pcf50633-input.c | |||
| @@ -55,7 +55,6 @@ pcf50633_input_irq(int irq, void *data) | |||
| 55 | static int __devinit pcf50633_input_probe(struct platform_device *pdev) | 55 | static int __devinit pcf50633_input_probe(struct platform_device *pdev) |
| 56 | { | 56 | { |
| 57 | struct pcf50633_input *input; | 57 | struct pcf50633_input *input; |
| 58 | struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data; | ||
| 59 | struct input_dev *input_dev; | 58 | struct input_dev *input_dev; |
| 60 | int ret; | 59 | int ret; |
| 61 | 60 | ||
| @@ -71,7 +70,7 @@ static int __devinit pcf50633_input_probe(struct platform_device *pdev) | |||
| 71 | } | 70 | } |
| 72 | 71 | ||
| 73 | platform_set_drvdata(pdev, input); | 72 | platform_set_drvdata(pdev, input); |
| 74 | input->pcf = pdata->pcf; | 73 | input->pcf = dev_to_pcf50633(pdev->dev.parent); |
| 75 | input->input_dev = input_dev; | 74 | input->input_dev = input_dev; |
| 76 | 75 | ||
| 77 | input_dev->name = "PCF50633 PMU events"; | 76 | input_dev->name = "PCF50633 PMU events"; |
| @@ -85,9 +84,9 @@ static int __devinit pcf50633_input_probe(struct platform_device *pdev) | |||
| 85 | kfree(input); | 84 | kfree(input); |
| 86 | return ret; | 85 | return ret; |
| 87 | } | 86 | } |
| 88 | pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ONKEYR, | 87 | pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYR, |
| 89 | pcf50633_input_irq, input); | 88 | pcf50633_input_irq, input); |
| 90 | pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ONKEYF, | 89 | pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYF, |
| 91 | pcf50633_input_irq, input); | 90 | pcf50633_input_irq, input); |
| 92 | 91 | ||
| 93 | return 0; | 92 | return 0; |
diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c index f5fc9974a111..bdde5c889035 100644 --- a/drivers/input/misc/twl4030-pwrbutton.c +++ b/drivers/input/misc/twl4030-pwrbutton.c | |||
| @@ -27,7 +27,7 @@ | |||
| 27 | #include <linux/input.h> | 27 | #include <linux/input.h> |
| 28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
| 29 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
| 30 | #include <linux/i2c/twl4030.h> | 30 | #include <linux/i2c/twl.h> |
| 31 | 31 | ||
| 32 | #define PWR_PWRON_IRQ (1 << 0) | 32 | #define PWR_PWRON_IRQ (1 << 0) |
| 33 | 33 | ||
| @@ -49,7 +49,7 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr) | |||
| 49 | local_irq_enable(); | 49 | local_irq_enable(); |
| 50 | #endif | 50 | #endif |
| 51 | 51 | ||
| 52 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value, | 52 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value, |
| 53 | STS_HW_CONDITIONS); | 53 | STS_HW_CONDITIONS); |
| 54 | if (!err) { | 54 | if (!err) { |
| 55 | input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ); | 55 | input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ); |
diff --git a/drivers/mfd/88pm8607.c b/drivers/mfd/88pm8607.c new file mode 100644 index 000000000000..7e3f65907993 --- /dev/null +++ b/drivers/mfd/88pm8607.c | |||
| @@ -0,0 +1,302 @@ | |||
| 1 | /* | ||
| 2 | * Base driver for Marvell 88PM8607 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009 Marvell International Ltd. | ||
| 5 | * Haojian Zhuang <haojian.zhuang@marvell.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/interrupt.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | #include <linux/i2c.h> | ||
| 17 | #include <linux/mfd/core.h> | ||
| 18 | #include <linux/mfd/88pm8607.h> | ||
| 19 | |||
| 20 | |||
| 21 | #define PM8607_REG_RESOURCE(_start, _end) \ | ||
| 22 | { \ | ||
| 23 | .start = PM8607_##_start, \ | ||
| 24 | .end = PM8607_##_end, \ | ||
| 25 | .flags = IORESOURCE_IO, \ | ||
| 26 | } | ||
| 27 | |||
| 28 | static struct resource pm8607_regulator_resources[] = { | ||
| 29 | PM8607_REG_RESOURCE(BUCK1, BUCK1), | ||
| 30 | PM8607_REG_RESOURCE(BUCK2, BUCK2), | ||
| 31 | PM8607_REG_RESOURCE(BUCK3, BUCK3), | ||
| 32 | PM8607_REG_RESOURCE(LDO1, LDO1), | ||
| 33 | PM8607_REG_RESOURCE(LDO2, LDO2), | ||
| 34 | PM8607_REG_RESOURCE(LDO3, LDO3), | ||
| 35 | PM8607_REG_RESOURCE(LDO4, LDO4), | ||
| 36 | PM8607_REG_RESOURCE(LDO5, LDO5), | ||
| 37 | PM8607_REG_RESOURCE(LDO6, LDO6), | ||
| 38 | PM8607_REG_RESOURCE(LDO7, LDO7), | ||
| 39 | PM8607_REG_RESOURCE(LDO8, LDO8), | ||
| 40 | PM8607_REG_RESOURCE(LDO9, LDO9), | ||
| 41 | PM8607_REG_RESOURCE(LDO10, LDO10), | ||
| 42 | PM8607_REG_RESOURCE(LDO12, LDO12), | ||
| 43 | PM8607_REG_RESOURCE(LDO14, LDO14), | ||
| 44 | }; | ||
| 45 | |||
| 46 | #define PM8607_REG_DEVS(_name, _id) \ | ||
| 47 | { \ | ||
| 48 | .name = "88pm8607-" #_name, \ | ||
| 49 | .num_resources = 1, \ | ||
| 50 | .resources = &pm8607_regulator_resources[PM8607_ID_##_id], \ | ||
| 51 | } | ||
| 52 | |||
| 53 | static struct mfd_cell pm8607_devs[] = { | ||
| 54 | PM8607_REG_DEVS(buck1, BUCK1), | ||
| 55 | PM8607_REG_DEVS(buck2, BUCK2), | ||
| 56 | PM8607_REG_DEVS(buck3, BUCK3), | ||
| 57 | PM8607_REG_DEVS(ldo1, LDO1), | ||
| 58 | PM8607_REG_DEVS(ldo2, LDO2), | ||
| 59 | PM8607_REG_DEVS(ldo3, LDO3), | ||
| 60 | PM8607_REG_DEVS(ldo4, LDO4), | ||
| 61 | PM8607_REG_DEVS(ldo5, LDO5), | ||
| 62 | PM8607_REG_DEVS(ldo6, LDO6), | ||
| 63 | PM8607_REG_DEVS(ldo7, LDO7), | ||
| 64 | PM8607_REG_DEVS(ldo8, LDO8), | ||
| 65 | PM8607_REG_DEVS(ldo9, LDO9), | ||
| 66 | PM8607_REG_DEVS(ldo10, LDO10), | ||
| 67 | PM8607_REG_DEVS(ldo12, LDO12), | ||
| 68 | PM8607_REG_DEVS(ldo14, LDO14), | ||
| 69 | }; | ||
| 70 | |||
| 71 | static inline int pm8607_read_device(struct pm8607_chip *chip, | ||
| 72 | int reg, int bytes, void *dest) | ||
| 73 | { | ||
| 74 | struct i2c_client *i2c = chip->client; | ||
| 75 | unsigned char data; | ||
| 76 | int ret; | ||
| 77 | |||
| 78 | data = (unsigned char)reg; | ||
| 79 | ret = i2c_master_send(i2c, &data, 1); | ||
| 80 | if (ret < 0) | ||
| 81 | return ret; | ||
| 82 | |||
| 83 | ret = i2c_master_recv(i2c, dest, bytes); | ||
| 84 | if (ret < 0) | ||
| 85 | return ret; | ||
| 86 | return 0; | ||
| 87 | } | ||
| 88 | |||
| 89 | static inline int pm8607_write_device(struct pm8607_chip *chip, | ||
| 90 | int reg, int bytes, void *src) | ||
| 91 | { | ||
| 92 | struct i2c_client *i2c = chip->client; | ||
| 93 | unsigned char buf[bytes + 1]; | ||
| 94 | int ret; | ||
| 95 | |||
| 96 | buf[0] = (unsigned char)reg; | ||
| 97 | memcpy(&buf[1], src, bytes); | ||
| 98 | |||
| 99 | ret = i2c_master_send(i2c, buf, bytes + 1); | ||
| 100 | if (ret < 0) | ||
| 101 | return ret; | ||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | int pm8607_reg_read(struct pm8607_chip *chip, int reg) | ||
| 106 | { | ||
| 107 | unsigned char data; | ||
| 108 | int ret; | ||
| 109 | |||
| 110 | mutex_lock(&chip->io_lock); | ||
| 111 | ret = chip->read(chip, reg, 1, &data); | ||
| 112 | mutex_unlock(&chip->io_lock); | ||
| 113 | |||
| 114 | if (ret < 0) | ||
| 115 | return ret; | ||
| 116 | else | ||
| 117 | return (int)data; | ||
| 118 | } | ||
| 119 | EXPORT_SYMBOL(pm8607_reg_read); | ||
| 120 | |||
| 121 | int pm8607_reg_write(struct pm8607_chip *chip, int reg, | ||
| 122 | unsigned char data) | ||
| 123 | { | ||
| 124 | int ret; | ||
| 125 | |||
| 126 | mutex_lock(&chip->io_lock); | ||
| 127 | ret = chip->write(chip, reg, 1, &data); | ||
| 128 | mutex_unlock(&chip->io_lock); | ||
| 129 | |||
| 130 | return ret; | ||
| 131 | } | ||
| 132 | EXPORT_SYMBOL(pm8607_reg_write); | ||
| 133 | |||
| 134 | int pm8607_bulk_read(struct pm8607_chip *chip, int reg, | ||
| 135 | int count, unsigned char *buf) | ||
| 136 | { | ||
| 137 | int ret; | ||
| 138 | |||
| 139 | mutex_lock(&chip->io_lock); | ||
| 140 | ret = chip->read(chip, reg, count, buf); | ||
| 141 | mutex_unlock(&chip->io_lock); | ||
| 142 | |||
| 143 | return ret; | ||
| 144 | } | ||
| 145 | EXPORT_SYMBOL(pm8607_bulk_read); | ||
| 146 | |||
| 147 | int pm8607_bulk_write(struct pm8607_chip *chip, int reg, | ||
| 148 | int count, unsigned char *buf) | ||
| 149 | { | ||
| 150 | int ret; | ||
| 151 | |||
| 152 | mutex_lock(&chip->io_lock); | ||
| 153 | ret = chip->write(chip, reg, count, buf); | ||
| 154 | mutex_unlock(&chip->io_lock); | ||
| 155 | |||
| 156 | return ret; | ||
| 157 | } | ||
| 158 | EXPORT_SYMBOL(pm8607_bulk_write); | ||
| 159 | |||
| 160 | int pm8607_set_bits(struct pm8607_chip *chip, int reg, | ||
| 161 | unsigned char mask, unsigned char data) | ||
| 162 | { | ||
| 163 | unsigned char value; | ||
| 164 | int ret; | ||
| 165 | |||
| 166 | mutex_lock(&chip->io_lock); | ||
| 167 | ret = chip->read(chip, reg, 1, &value); | ||
| 168 | if (ret < 0) | ||
| 169 | goto out; | ||
| 170 | value &= ~mask; | ||
| 171 | value |= data; | ||
| 172 | ret = chip->write(chip, reg, 1, &value); | ||
| 173 | out: | ||
| 174 | mutex_unlock(&chip->io_lock); | ||
| 175 | return ret; | ||
| 176 | } | ||
| 177 | EXPORT_SYMBOL(pm8607_set_bits); | ||
| 178 | |||
| 179 | |||
| 180 | static const struct i2c_device_id pm8607_id_table[] = { | ||
| 181 | { "88PM8607", 0 }, | ||
| 182 | {} | ||
| 183 | }; | ||
| 184 | MODULE_DEVICE_TABLE(i2c, pm8607_id_table); | ||
| 185 | |||
| 186 | |||
| 187 | static int __devinit pm8607_probe(struct i2c_client *client, | ||
| 188 | const struct i2c_device_id *id) | ||
| 189 | { | ||
| 190 | struct pm8607_platform_data *pdata = client->dev.platform_data; | ||
| 191 | struct pm8607_chip *chip; | ||
| 192 | int i, count; | ||
| 193 | int ret; | ||
| 194 | |||
| 195 | chip = kzalloc(sizeof(struct pm8607_chip), GFP_KERNEL); | ||
| 196 | if (chip == NULL) | ||
| 197 | return -ENOMEM; | ||
| 198 | |||
| 199 | chip->client = client; | ||
| 200 | chip->dev = &client->dev; | ||
| 201 | chip->read = pm8607_read_device; | ||
| 202 | chip->write = pm8607_write_device; | ||
| 203 | i2c_set_clientdata(client, chip); | ||
| 204 | |||
| 205 | mutex_init(&chip->io_lock); | ||
| 206 | dev_set_drvdata(chip->dev, chip); | ||
| 207 | |||
| 208 | ret = pm8607_reg_read(chip, PM8607_CHIP_ID); | ||
| 209 | if (ret < 0) { | ||
| 210 | dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret); | ||
| 211 | goto out; | ||
| 212 | } | ||
| 213 | if ((ret & CHIP_ID_MASK) == CHIP_ID) | ||
| 214 | dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n", | ||
| 215 | ret); | ||
| 216 | else { | ||
| 217 | dev_err(chip->dev, "Failed to detect Marvell 88PM8607. " | ||
| 218 | "Chip ID: %02x\n", ret); | ||
| 219 | goto out; | ||
| 220 | } | ||
| 221 | chip->chip_id = ret; | ||
| 222 | |||
| 223 | ret = pm8607_reg_read(chip, PM8607_BUCK3); | ||
| 224 | if (ret < 0) { | ||
| 225 | dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret); | ||
| 226 | goto out; | ||
| 227 | } | ||
| 228 | if (ret & PM8607_BUCK3_DOUBLE) | ||
| 229 | chip->buck3_double = 1; | ||
| 230 | |||
| 231 | ret = pm8607_reg_read(chip, PM8607_MISC1); | ||
| 232 | if (ret < 0) { | ||
| 233 | dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret); | ||
| 234 | goto out; | ||
| 235 | } | ||
| 236 | if (pdata->i2c_port == PI2C_PORT) | ||
| 237 | ret |= PM8607_MISC1_PI2C; | ||
| 238 | else | ||
| 239 | ret &= ~PM8607_MISC1_PI2C; | ||
| 240 | ret = pm8607_reg_write(chip, PM8607_MISC1, ret); | ||
| 241 | if (ret < 0) { | ||
| 242 | dev_err(chip->dev, "Failed to write MISC1 register: %d\n", ret); | ||
| 243 | goto out; | ||
| 244 | } | ||
| 245 | |||
| 246 | |||
| 247 | count = ARRAY_SIZE(pm8607_devs); | ||
| 248 | for (i = 0; i < count; i++) { | ||
| 249 | ret = mfd_add_devices(chip->dev, i, &pm8607_devs[i], | ||
| 250 | 1, NULL, 0); | ||
| 251 | if (ret != 0) { | ||
| 252 | dev_err(chip->dev, "Failed to add subdevs\n"); | ||
| 253 | goto out; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | return 0; | ||
| 258 | |||
| 259 | out: | ||
| 260 | i2c_set_clientdata(client, NULL); | ||
| 261 | kfree(chip); | ||
| 262 | return ret; | ||
| 263 | } | ||
| 264 | |||
| 265 | static int __devexit pm8607_remove(struct i2c_client *client) | ||
| 266 | { | ||
| 267 | struct pm8607_chip *chip = i2c_get_clientdata(client); | ||
| 268 | |||
| 269 | mfd_remove_devices(chip->dev); | ||
| 270 | kfree(chip); | ||
| 271 | return 0; | ||
| 272 | } | ||
| 273 | |||
| 274 | static struct i2c_driver pm8607_driver = { | ||
| 275 | .driver = { | ||
| 276 | .name = "88PM8607", | ||
| 277 | .owner = THIS_MODULE, | ||
| 278 | }, | ||
| 279 | .probe = pm8607_probe, | ||
| 280 | .remove = __devexit_p(pm8607_remove), | ||
| 281 | .id_table = pm8607_id_table, | ||
| 282 | }; | ||
| 283 | |||
| 284 | static int __init pm8607_init(void) | ||
| 285 | { | ||
| 286 | int ret; | ||
| 287 | ret = i2c_add_driver(&pm8607_driver); | ||
| 288 | if (ret != 0) | ||
| 289 | pr_err("Failed to register 88PM8607 I2C driver: %d\n", ret); | ||
| 290 | return ret; | ||
| 291 | } | ||
| 292 | subsys_initcall(pm8607_init); | ||
| 293 | |||
| 294 | static void __exit pm8607_exit(void) | ||
| 295 | { | ||
| 296 | i2c_del_driver(&pm8607_driver); | ||
| 297 | } | ||
| 298 | module_exit(pm8607_exit); | ||
| 299 | |||
| 300 | MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM8607"); | ||
| 301 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); | ||
| 302 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index a296e717e86e..87829789243e 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
| @@ -103,10 +103,10 @@ config MENELAUS | |||
| 103 | cell phones and PDAs. | 103 | cell phones and PDAs. |
| 104 | 104 | ||
| 105 | config TWL4030_CORE | 105 | config TWL4030_CORE |
| 106 | bool "Texas Instruments TWL4030/TPS659x0 Support" | 106 | bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" |
| 107 | depends on I2C=y && GENERIC_HARDIRQS | 107 | depends on I2C=y && GENERIC_HARDIRQS |
| 108 | help | 108 | help |
| 109 | Say yes here if you have TWL4030 family chip on your board. | 109 | Say yes here if you have TWL4030 / TWL6030 family chip on your board. |
| 110 | This core driver provides register access and IRQ handling | 110 | This core driver provides register access and IRQ handling |
| 111 | facilities, and registers devices for the various functions | 111 | facilities, and registers devices for the various functions |
| 112 | so that function-specific drivers can bind to them. | 112 | so that function-specific drivers can bind to them. |
| @@ -174,6 +174,16 @@ config PMIC_DA903X | |||
| 174 | individual components like LCD backlight, voltage regulators, | 174 | individual components like LCD backlight, voltage regulators, |
| 175 | LEDs and battery-charger under the corresponding menus. | 175 | LEDs and battery-charger under the corresponding menus. |
| 176 | 176 | ||
| 177 | config PMIC_ADP5520 | ||
| 178 | bool "Analog Devices ADP5520/01 MFD PMIC Core Support" | ||
| 179 | depends on I2C=y | ||
| 180 | help | ||
| 181 | Say yes here to add support for Analog Devices AD5520 and ADP5501, | ||
| 182 | Multifunction Power Management IC. This includes | ||
| 183 | the I2C driver and the core APIs _only_, you have to select | ||
| 184 | individual components like LCD backlight, LEDs, GPIOs and Kepad | ||
| 185 | under the corresponding menus. | ||
| 186 | |||
| 177 | config MFD_WM8400 | 187 | config MFD_WM8400 |
| 178 | tristate "Support Wolfson Microelectronics WM8400" | 188 | tristate "Support Wolfson Microelectronics WM8400" |
| 179 | select MFD_CORE | 189 | select MFD_CORE |
| @@ -185,12 +195,12 @@ config MFD_WM8400 | |||
| 185 | the functionality of the device. | 195 | the functionality of the device. |
| 186 | 196 | ||
| 187 | config MFD_WM831X | 197 | config MFD_WM831X |
| 188 | tristate "Support Wolfson Microelectronics WM831x PMICs" | 198 | bool "Support Wolfson Microelectronics WM831x/2x PMICs" |
| 189 | select MFD_CORE | 199 | select MFD_CORE |
| 190 | depends on I2C | 200 | depends on I2C=y |
| 191 | help | 201 | help |
| 192 | Support for the Wolfson Microelecronics WM831x PMICs. This | 202 | Support for the Wolfson Microelecronics WM831x and WM832x PMICs. |
| 193 | driver provides common support for accessing the device, | 203 | This driver provides common support for accessing the device, |
| 194 | additional drivers must be enabled in order to use the | 204 | additional drivers must be enabled in order to use the |
| 195 | functionality of the device. | 205 | functionality of the device. |
| 196 | 206 | ||
| @@ -319,6 +329,25 @@ config EZX_PCAP | |||
| 319 | This enables the PCAP ASIC present on EZX Phones. This is | 329 | This enables the PCAP ASIC present on EZX Phones. This is |
| 320 | needed for MMC, TouchScreen, Sound, USB, etc.. | 330 | needed for MMC, TouchScreen, Sound, USB, etc.. |
| 321 | 331 | ||
| 332 | config MFD_88PM8607 | ||
| 333 | bool "Support Marvell 88PM8607" | ||
| 334 | depends on I2C=y | ||
| 335 | select MFD_CORE | ||
| 336 | help | ||
| 337 | This supports for Marvell 88PM8607 Power Management IC. This includes | ||
| 338 | the I2C driver and the core APIs _only_, you have to select | ||
| 339 | individual components like voltage regulators, RTC and | ||
| 340 | battery-charger under the corresponding menus. | ||
| 341 | |||
| 342 | config AB4500_CORE | ||
| 343 | tristate "ST-Ericsson's AB4500 Mixed Signal Power management chip" | ||
| 344 | depends on SPI | ||
| 345 | help | ||
| 346 | Select this option to enable access to AB4500 power management | ||
| 347 | chip. This connects to U8500 on the SSP/SPI bus and exports | ||
| 348 | read/write functions for the devices to get access to this chip. | ||
| 349 | This chip embeds various other multimedia funtionalities as well. | ||
| 350 | |||
| 322 | endmenu | 351 | endmenu |
| 323 | 352 | ||
| 324 | menu "Multimedia Capabilities Port drivers" | 353 | menu "Multimedia Capabilities Port drivers" |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 11350c1d9301..ca2f2c4ff05e 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
| @@ -19,13 +19,14 @@ obj-$(CONFIG_MFD_WM8400) += wm8400-core.o | |||
| 19 | wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o | 19 | wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o |
| 20 | obj-$(CONFIG_MFD_WM831X) += wm831x.o | 20 | obj-$(CONFIG_MFD_WM831X) += wm831x.o |
| 21 | wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o | 21 | wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o |
| 22 | wm8350-objs += wm8350-irq.o | ||
| 22 | obj-$(CONFIG_MFD_WM8350) += wm8350.o | 23 | obj-$(CONFIG_MFD_WM8350) += wm8350.o |
| 23 | obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o | 24 | obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o |
| 24 | 25 | ||
| 25 | obj-$(CONFIG_TPS65010) += tps65010.o | 26 | obj-$(CONFIG_TPS65010) += tps65010.o |
| 26 | obj-$(CONFIG_MENELAUS) += menelaus.o | 27 | obj-$(CONFIG_MENELAUS) += menelaus.o |
| 27 | 28 | ||
| 28 | obj-$(CONFIG_TWL4030_CORE) += twl4030-core.o twl4030-irq.o | 29 | obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o |
| 29 | obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o | 30 | obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o |
| 30 | obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o | 31 | obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o |
| 31 | 32 | ||
| @@ -52,3 +53,6 @@ obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o | |||
| 52 | obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o | 53 | obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o |
| 53 | obj-$(CONFIG_AB3100_CORE) += ab3100-core.o | 54 | obj-$(CONFIG_AB3100_CORE) += ab3100-core.o |
| 54 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o | 55 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o |
| 56 | obj-$(CONFIG_AB4500_CORE) += ab4500-core.o | ||
| 57 | obj-$(CONFIG_MFD_88PM8607) += 88pm8607.o | ||
| 58 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o \ No newline at end of file | ||
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 613481028272..fd42a80e7bf9 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c | |||
| @@ -900,9 +900,6 @@ static int __init ab3100_probe(struct i2c_client *client, | |||
| 900 | goto exit_no_testreg_client; | 900 | goto exit_no_testreg_client; |
| 901 | } | 901 | } |
| 902 | 902 | ||
| 903 | strlcpy(ab3100->testreg_client->name, id->name, | ||
| 904 | sizeof(ab3100->testreg_client->name)); | ||
| 905 | |||
| 906 | err = ab3100_setup(ab3100); | 903 | err = ab3100_setup(ab3100); |
| 907 | if (err) | 904 | if (err) |
| 908 | goto exit_no_setup; | 905 | goto exit_no_setup; |
diff --git a/drivers/mfd/ab4500-core.c b/drivers/mfd/ab4500-core.c new file mode 100644 index 000000000000..1c44c19e073a --- /dev/null +++ b/drivers/mfd/ab4500-core.c | |||
| @@ -0,0 +1,208 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009 ST-Ericsson | ||
| 3 | * | ||
| 4 | * Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it | ||
| 7 | * and/or modify it under the terms of the GNU General Public | ||
| 8 | * License version 2, as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * AB4500 is a companion power management chip used with U8500. | ||
| 11 | * On this platform, this is interfaced with SSP0 controller | ||
| 12 | * which is a ARM primecell pl022. | ||
| 13 | * | ||
| 14 | * At the moment the module just exports read/write features. | ||
| 15 | * Interrupt management to be added - TODO. | ||
| 16 | */ | ||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/init.h> | ||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/platform_device.h> | ||
| 21 | #include <linux/spi/spi.h> | ||
| 22 | #include <linux/mfd/ab4500.h> | ||
| 23 | |||
| 24 | /* just required if probe fails, we need to | ||
| 25 | * unregister the device | ||
| 26 | */ | ||
| 27 | static struct spi_driver ab4500_driver; | ||
| 28 | |||
| 29 | /* | ||
| 30 | * This funtion writes to any AB4500 registers using | ||
| 31 | * SPI protocol & before it writes it packs the data | ||
| 32 | * in the below 24 bit frame format | ||
| 33 | * | ||
| 34 | * *|------------------------------------| | ||
| 35 | * *| 23|22...18|17.......10|9|8|7......0| | ||
| 36 | * *| r/w bank adr data | | ||
| 37 | * * ------------------------------------ | ||
| 38 | * | ||
| 39 | * This function shouldn't be called from interrupt | ||
| 40 | * context | ||
| 41 | */ | ||
| 42 | int ab4500_write(struct ab4500 *ab4500, unsigned char block, | ||
| 43 | unsigned long addr, unsigned char data) | ||
| 44 | { | ||
| 45 | struct spi_transfer xfer; | ||
| 46 | struct spi_message msg; | ||
| 47 | int err; | ||
| 48 | unsigned long spi_data = | ||
| 49 | block << 18 | addr << 10 | data; | ||
| 50 | |||
| 51 | mutex_lock(&ab4500->lock); | ||
| 52 | ab4500->tx_buf[0] = spi_data; | ||
| 53 | ab4500->rx_buf[0] = 0; | ||
| 54 | |||
| 55 | xfer.tx_buf = ab4500->tx_buf; | ||
| 56 | xfer.rx_buf = NULL; | ||
| 57 | xfer.len = sizeof(unsigned long); | ||
| 58 | |||
| 59 | spi_message_init(&msg); | ||
| 60 | spi_message_add_tail(&xfer, &msg); | ||
| 61 | |||
| 62 | err = spi_sync(ab4500->spi, &msg); | ||
| 63 | mutex_unlock(&ab4500->lock); | ||
| 64 | |||
| 65 | return err; | ||
| 66 | } | ||
| 67 | EXPORT_SYMBOL(ab4500_write); | ||
| 68 | |||
| 69 | int ab4500_read(struct ab4500 *ab4500, unsigned char block, | ||
| 70 | unsigned long addr) | ||
| 71 | { | ||
| 72 | struct spi_transfer xfer; | ||
| 73 | struct spi_message msg; | ||
| 74 | unsigned long spi_data = | ||
| 75 | 1 << 23 | block << 18 | addr << 10; | ||
| 76 | |||
| 77 | mutex_lock(&ab4500->lock); | ||
| 78 | ab4500->tx_buf[0] = spi_data; | ||
| 79 | ab4500->rx_buf[0] = 0; | ||
| 80 | |||
| 81 | xfer.tx_buf = ab4500->tx_buf; | ||
| 82 | xfer.rx_buf = ab4500->rx_buf; | ||
| 83 | xfer.len = sizeof(unsigned long); | ||
| 84 | |||
| 85 | spi_message_init(&msg); | ||
| 86 | spi_message_add_tail(&xfer, &msg); | ||
| 87 | |||
| 88 | spi_sync(ab4500->spi, &msg); | ||
| 89 | mutex_unlock(&ab4500->lock); | ||
| 90 | |||
| 91 | return ab4500->rx_buf[0]; | ||
| 92 | } | ||
| 93 | EXPORT_SYMBOL(ab4500_read); | ||
| 94 | |||
| 95 | /* ref: ab3100 core */ | ||
| 96 | #define AB4500_DEVICE(devname, devid) \ | ||
| 97 | static struct platform_device ab4500_##devname##_device = { \ | ||
| 98 | .name = devid, \ | ||
| 99 | .id = -1, \ | ||
| 100 | } | ||
| 101 | |||
| 102 | /* list of childern devices of ab4500 - all are | ||
| 103 | * not populated here - TODO | ||
| 104 | */ | ||
| 105 | AB4500_DEVICE(charger, "ab4500-charger"); | ||
| 106 | AB4500_DEVICE(audio, "ab4500-audio"); | ||
| 107 | AB4500_DEVICE(usb, "ab4500-usb"); | ||
| 108 | AB4500_DEVICE(tvout, "ab4500-tvout"); | ||
| 109 | AB4500_DEVICE(sim, "ab4500-sim"); | ||
| 110 | AB4500_DEVICE(gpadc, "ab4500-gpadc"); | ||
| 111 | AB4500_DEVICE(clkmgt, "ab4500-clkmgt"); | ||
| 112 | AB4500_DEVICE(misc, "ab4500-misc"); | ||
| 113 | |||
| 114 | static struct platform_device *ab4500_platform_devs[] = { | ||
| 115 | &ab4500_charger_device, | ||
| 116 | &ab4500_audio_device, | ||
| 117 | &ab4500_usb_device, | ||
| 118 | &ab4500_tvout_device, | ||
| 119 | &ab4500_sim_device, | ||
| 120 | &ab4500_gpadc_device, | ||
| 121 | &ab4500_clkmgt_device, | ||
| 122 | &ab4500_misc_device, | ||
| 123 | }; | ||
| 124 | |||
| 125 | static int __init ab4500_probe(struct spi_device *spi) | ||
| 126 | { | ||
| 127 | struct ab4500 *ab4500; | ||
| 128 | unsigned char revision; | ||
| 129 | int err = 0; | ||
| 130 | int i; | ||
| 131 | |||
| 132 | ab4500 = kzalloc(sizeof *ab4500, GFP_KERNEL); | ||
| 133 | if (!ab4500) { | ||
| 134 | dev_err(&spi->dev, "could not allocate AB4500\n"); | ||
| 135 | err = -ENOMEM; | ||
| 136 | goto not_detect; | ||
| 137 | } | ||
| 138 | |||
| 139 | ab4500->spi = spi; | ||
| 140 | spi_set_drvdata(spi, ab4500); | ||
| 141 | |||
| 142 | mutex_init(&ab4500->lock); | ||
| 143 | |||
| 144 | /* read the revision register */ | ||
| 145 | revision = ab4500_read(ab4500, AB4500_MISC, AB4500_REV_REG); | ||
| 146 | |||
| 147 | /* revision id 0x0 is for early drop, 0x10 is for cut1.0 */ | ||
| 148 | if (revision == 0x0 || revision == 0x10) | ||
| 149 | dev_info(&spi->dev, "Detected chip: %s, revision = %x\n", | ||
| 150 | ab4500_driver.driver.name, revision); | ||
| 151 | else { | ||
| 152 | dev_err(&spi->dev, "unknown chip: 0x%x\n", revision); | ||
| 153 | goto not_detect; | ||
| 154 | } | ||
| 155 | |||
| 156 | for (i = 0; i < ARRAY_SIZE(ab4500_platform_devs); i++) { | ||
| 157 | ab4500_platform_devs[i]->dev.parent = | ||
| 158 | &spi->dev; | ||
| 159 | platform_set_drvdata(ab4500_platform_devs[i], ab4500); | ||
| 160 | } | ||
| 161 | |||
| 162 | /* register the ab4500 platform devices */ | ||
| 163 | platform_add_devices(ab4500_platform_devs, | ||
| 164 | ARRAY_SIZE(ab4500_platform_devs)); | ||
| 165 | |||
| 166 | return err; | ||
| 167 | |||
| 168 | not_detect: | ||
| 169 | spi_unregister_driver(&ab4500_driver); | ||
| 170 | kfree(ab4500); | ||
| 171 | return err; | ||
| 172 | } | ||
| 173 | |||
| 174 | static int __devexit ab4500_remove(struct spi_device *spi) | ||
| 175 | { | ||
| 176 | struct ab4500 *ab4500 = | ||
| 177 | spi_get_drvdata(spi); | ||
| 178 | |||
| 179 | kfree(ab4500); | ||
| 180 | |||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | static struct spi_driver ab4500_driver = { | ||
| 185 | .driver = { | ||
| 186 | .name = "ab4500", | ||
| 187 | .owner = THIS_MODULE, | ||
| 188 | }, | ||
| 189 | .probe = ab4500_probe, | ||
| 190 | .remove = __devexit_p(ab4500_remove) | ||
| 191 | }; | ||
| 192 | |||
| 193 | static int __devinit ab4500_init(void) | ||
| 194 | { | ||
| 195 | return spi_register_driver(&ab4500_driver); | ||
| 196 | } | ||
| 197 | |||
| 198 | static void __exit ab4500_exit(void) | ||
| 199 | { | ||
| 200 | spi_unregister_driver(&ab4500_driver); | ||
| 201 | } | ||
| 202 | |||
| 203 | subsys_initcall(ab4500_init); | ||
| 204 | module_exit(ab4500_exit); | ||
| 205 | |||
| 206 | MODULE_AUTHOR("Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com"); | ||
| 207 | MODULE_DESCRIPTION("AB4500 core driver"); | ||
| 208 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c new file mode 100644 index 000000000000..b26644772d02 --- /dev/null +++ b/drivers/mfd/adp5520.c | |||
| @@ -0,0 +1,379 @@ | |||
| 1 | /* | ||
| 2 | * Base driver for Analog Devices ADP5520/ADP5501 MFD PMICs | ||
| 3 | * LCD Backlight: drivers/video/backlight/adp5520_bl | ||
| 4 | * LEDs : drivers/led/leds-adp5520 | ||
| 5 | * GPIO : drivers/gpio/adp5520-gpio (ADP5520 only) | ||
| 6 | * Keys : drivers/input/keyboard/adp5520-keys (ADP5520 only) | ||
| 7 | * | ||
| 8 | * Copyright 2009 Analog Devices Inc. | ||
| 9 | * | ||
| 10 | * Derived from da903x: | ||
| 11 | * Copyright (C) 2008 Compulab, Ltd. | ||
| 12 | * Mike Rapoport <mike@compulab.co.il> | ||
| 13 | * | ||
| 14 | * Copyright (C) 2006-2008 Marvell International Ltd. | ||
| 15 | * Eric Miao <eric.miao@marvell.com> | ||
| 16 | * | ||
| 17 | * Licensed under the GPL-2 or later. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/platform_device.h> | ||
| 23 | #include <linux/init.h> | ||
| 24 | #include <linux/interrupt.h> | ||
| 25 | #include <linux/irq.h> | ||
| 26 | #include <linux/err.h> | ||
| 27 | #include <linux/i2c.h> | ||
| 28 | |||
| 29 | #include <linux/mfd/adp5520.h> | ||
| 30 | |||
| 31 | struct adp5520_chip { | ||
| 32 | struct i2c_client *client; | ||
| 33 | struct device *dev; | ||
| 34 | struct mutex lock; | ||
| 35 | struct blocking_notifier_head notifier_list; | ||
| 36 | int irq; | ||
| 37 | unsigned long id; | ||
| 38 | }; | ||
| 39 | |||
| 40 | static int __adp5520_read(struct i2c_client *client, | ||
| 41 | int reg, uint8_t *val) | ||
| 42 | { | ||
| 43 | int ret; | ||
| 44 | |||
| 45 | ret = i2c_smbus_read_byte_data(client, reg); | ||
| 46 | if (ret < 0) { | ||
| 47 | dev_err(&client->dev, "failed reading at 0x%02x\n", reg); | ||
| 48 | return ret; | ||
| 49 | } | ||
| 50 | |||
| 51 | *val = (uint8_t)ret; | ||
| 52 | return 0; | ||
| 53 | } | ||
| 54 | |||
| 55 | static int __adp5520_write(struct i2c_client *client, | ||
| 56 | int reg, uint8_t val) | ||
| 57 | { | ||
| 58 | int ret; | ||
| 59 | |||
| 60 | ret = i2c_smbus_write_byte_data(client, reg, val); | ||
| 61 | if (ret < 0) { | ||
| 62 | dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n", | ||
| 63 | val, reg); | ||
| 64 | return ret; | ||
| 65 | } | ||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | static int __adp5520_ack_bits(struct i2c_client *client, int reg, | ||
| 70 | uint8_t bit_mask) | ||
| 71 | { | ||
| 72 | struct adp5520_chip *chip = i2c_get_clientdata(client); | ||
| 73 | uint8_t reg_val; | ||
| 74 | int ret; | ||
| 75 | |||
| 76 | mutex_lock(&chip->lock); | ||
| 77 | |||
| 78 | ret = __adp5520_read(client, reg, ®_val); | ||
| 79 | |||
| 80 | if (!ret) { | ||
| 81 | reg_val |= bit_mask; | ||
| 82 | ret = __adp5520_write(client, reg, reg_val); | ||
| 83 | } | ||
| 84 | |||
| 85 | mutex_unlock(&chip->lock); | ||
| 86 | return ret; | ||
| 87 | } | ||
| 88 | |||
| 89 | int adp5520_write(struct device *dev, int reg, uint8_t val) | ||
| 90 | { | ||
| 91 | return __adp5520_write(to_i2c_client(dev), reg, val); | ||
| 92 | } | ||
| 93 | EXPORT_SYMBOL_GPL(adp5520_write); | ||
| 94 | |||
| 95 | int adp5520_read(struct device *dev, int reg, uint8_t *val) | ||
| 96 | { | ||
| 97 | return __adp5520_read(to_i2c_client(dev), reg, val); | ||
| 98 | } | ||
| 99 | EXPORT_SYMBOL_GPL(adp5520_read); | ||
| 100 | |||
| 101 | int adp5520_set_bits(struct device *dev, int reg, uint8_t bit_mask) | ||
| 102 | { | ||
| 103 | struct adp5520_chip *chip = dev_get_drvdata(dev); | ||
| 104 | uint8_t reg_val; | ||
| 105 | int ret; | ||
| 106 | |||
| 107 | mutex_lock(&chip->lock); | ||
| 108 | |||
| 109 | ret = __adp5520_read(chip->client, reg, ®_val); | ||
| 110 | |||
| 111 | if (!ret && ((reg_val & bit_mask) == 0)) { | ||
| 112 | reg_val |= bit_mask; | ||
| 113 | ret = __adp5520_write(chip->client, reg, reg_val); | ||
| 114 | } | ||
| 115 | |||
| 116 | mutex_unlock(&chip->lock); | ||
| 117 | return ret; | ||
| 118 | } | ||
| 119 | EXPORT_SYMBOL_GPL(adp5520_set_bits); | ||
| 120 | |||
| 121 | int adp5520_clr_bits(struct device *dev, int reg, uint8_t bit_mask) | ||
| 122 | { | ||
| 123 | struct adp5520_chip *chip = dev_get_drvdata(dev); | ||
| 124 | uint8_t reg_val; | ||
| 125 | int ret; | ||
| 126 | |||
| 127 | mutex_lock(&chip->lock); | ||
| 128 | |||
| 129 | ret = __adp5520_read(chip->client, reg, ®_val); | ||
| 130 | |||
| 131 | if (!ret && (reg_val & bit_mask)) { | ||
| 132 | reg_val &= ~bit_mask; | ||
| 133 | ret = __adp5520_write(chip->client, reg, reg_val); | ||
| 134 | } | ||
| 135 | |||
| 136 | mutex_unlock(&chip->lock); | ||
| 137 | return ret; | ||
| 138 | } | ||
| 139 | EXPORT_SYMBOL_GPL(adp5520_clr_bits); | ||
| 140 | |||
| 141 | int adp5520_register_notifier(struct device *dev, struct notifier_block *nb, | ||
| 142 | unsigned int events) | ||
| 143 | { | ||
| 144 | struct adp5520_chip *chip = dev_get_drvdata(dev); | ||
| 145 | |||
| 146 | if (chip->irq) { | ||
| 147 | adp5520_set_bits(chip->dev, ADP5520_INTERRUPT_ENABLE, | ||
| 148 | events & (ADP5520_KP_IEN | ADP5520_KR_IEN | | ||
| 149 | ADP5520_OVP_IEN | ADP5520_CMPR_IEN)); | ||
| 150 | |||
| 151 | return blocking_notifier_chain_register(&chip->notifier_list, | ||
| 152 | nb); | ||
| 153 | } | ||
| 154 | |||
| 155 | return -ENODEV; | ||
| 156 | } | ||
| 157 | EXPORT_SYMBOL_GPL(adp5520_register_notifier); | ||
| 158 | |||
| 159 | int adp5520_unregister_notifier(struct device *dev, struct notifier_block *nb, | ||
| 160 | unsigned int events) | ||
| 161 | { | ||
| 162 | struct adp5520_chip *chip = dev_get_drvdata(dev); | ||
| 163 | |||
| 164 | adp5520_clr_bits(chip->dev, ADP5520_INTERRUPT_ENABLE, | ||
| 165 | events & (ADP5520_KP_IEN | ADP5520_KR_IEN | | ||
| 166 | ADP5520_OVP_IEN | ADP5520_CMPR_IEN)); | ||
| 167 | |||
| 168 | return blocking_notifier_chain_unregister(&chip->notifier_list, nb); | ||
| 169 | } | ||
| 170 | EXPORT_SYMBOL_GPL(adp5520_unregister_notifier); | ||
| 171 | |||
| 172 | static irqreturn_t adp5520_irq_thread(int irq, void *data) | ||
| 173 | { | ||
| 174 | struct adp5520_chip *chip = data; | ||
| 175 | unsigned int events; | ||
| 176 | uint8_t reg_val; | ||
| 177 | int ret; | ||
| 178 | |||
| 179 | ret = __adp5520_read(chip->client, ADP5520_MODE_STATUS, ®_val); | ||
| 180 | if (ret) | ||
| 181 | goto out; | ||
| 182 | |||
| 183 | events = reg_val & (ADP5520_OVP_INT | ADP5520_CMPR_INT | | ||
| 184 | ADP5520_GPI_INT | ADP5520_KR_INT | ADP5520_KP_INT); | ||
| 185 | |||
| 186 | blocking_notifier_call_chain(&chip->notifier_list, events, NULL); | ||
| 187 | /* ACK, Sticky bits are W1C */ | ||
| 188 | __adp5520_ack_bits(chip->client, ADP5520_MODE_STATUS, events); | ||
| 189 | |||
| 190 | out: | ||
| 191 | return IRQ_HANDLED; | ||
| 192 | } | ||
| 193 | |||
| 194 | static int __remove_subdev(struct device *dev, void *unused) | ||
| 195 | { | ||
| 196 | platform_device_unregister(to_platform_device(dev)); | ||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | static int adp5520_remove_subdevs(struct adp5520_chip *chip) | ||
| 201 | { | ||
| 202 | return device_for_each_child(chip->dev, NULL, __remove_subdev); | ||
| 203 | } | ||
| 204 | |||
| 205 | static int __devinit adp5520_probe(struct i2c_client *client, | ||
| 206 | const struct i2c_device_id *id) | ||
| 207 | { | ||
| 208 | struct adp5520_platform_data *pdata = client->dev.platform_data; | ||
| 209 | struct platform_device *pdev; | ||
| 210 | struct adp5520_chip *chip; | ||
| 211 | int ret; | ||
| 212 | |||
| 213 | if (!i2c_check_functionality(client->adapter, | ||
| 214 | I2C_FUNC_SMBUS_BYTE_DATA)) { | ||
| 215 | dev_err(&client->dev, "SMBUS Word Data not Supported\n"); | ||
| 216 | return -EIO; | ||
| 217 | } | ||
| 218 | |||
| 219 | if (pdata == NULL) { | ||
| 220 | dev_err(&client->dev, "missing platform data\n"); | ||
| 221 | return -ENODEV; | ||
| 222 | } | ||
| 223 | |||
| 224 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||
| 225 | if (!chip) | ||
| 226 | return -ENOMEM; | ||
| 227 | |||
| 228 | i2c_set_clientdata(client, chip); | ||
| 229 | chip->client = client; | ||
| 230 | |||
| 231 | chip->dev = &client->dev; | ||
| 232 | chip->irq = client->irq; | ||
| 233 | chip->id = id->driver_data; | ||
| 234 | mutex_init(&chip->lock); | ||
| 235 | |||
| 236 | if (chip->irq) { | ||
| 237 | BLOCKING_INIT_NOTIFIER_HEAD(&chip->notifier_list); | ||
| 238 | |||
| 239 | ret = request_threaded_irq(chip->irq, NULL, adp5520_irq_thread, | ||
| 240 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
| 241 | "adp5520", chip); | ||
| 242 | if (ret) { | ||
| 243 | dev_err(&client->dev, "failed to request irq %d\n", | ||
| 244 | chip->irq); | ||
| 245 | goto out_free_chip; | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | ret = adp5520_write(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); | ||
| 250 | if (ret) { | ||
| 251 | dev_err(&client->dev, "failed to write\n"); | ||
| 252 | goto out_free_irq; | ||
| 253 | } | ||
| 254 | |||
| 255 | if (pdata->keys) { | ||
| 256 | pdev = platform_device_register_data(chip->dev, "adp5520-keys", | ||
| 257 | chip->id, pdata->keys, sizeof(*pdata->keys)); | ||
| 258 | if (IS_ERR(pdev)) { | ||
| 259 | ret = PTR_ERR(pdev); | ||
| 260 | goto out_remove_subdevs; | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 264 | if (pdata->gpio) { | ||
| 265 | pdev = platform_device_register_data(chip->dev, "adp5520-gpio", | ||
| 266 | chip->id, pdata->gpio, sizeof(*pdata->gpio)); | ||
| 267 | if (IS_ERR(pdev)) { | ||
| 268 | ret = PTR_ERR(pdev); | ||
| 269 | goto out_remove_subdevs; | ||
| 270 | } | ||
| 271 | } | ||
| 272 | |||
| 273 | if (pdata->leds) { | ||
| 274 | pdev = platform_device_register_data(chip->dev, "adp5520-led", | ||
| 275 | chip->id, pdata->leds, sizeof(*pdata->leds)); | ||
| 276 | if (IS_ERR(pdev)) { | ||
| 277 | ret = PTR_ERR(pdev); | ||
| 278 | goto out_remove_subdevs; | ||
| 279 | } | ||
| 280 | } | ||
| 281 | |||
| 282 | if (pdata->backlight) { | ||
| 283 | pdev = platform_device_register_data(chip->dev, | ||
| 284 | "adp5520-backlight", | ||
| 285 | chip->id, | ||
| 286 | pdata->backlight, | ||
| 287 | sizeof(*pdata->backlight)); | ||
| 288 | if (IS_ERR(pdev)) { | ||
| 289 | ret = PTR_ERR(pdev); | ||
| 290 | goto out_remove_subdevs; | ||
| 291 | } | ||
| 292 | } | ||
| 293 | |||
| 294 | return 0; | ||
| 295 | |||
| 296 | out_remove_subdevs: | ||
| 297 | adp5520_remove_subdevs(chip); | ||
| 298 | |||
| 299 | out_free_irq: | ||
| 300 | if (chip->irq) | ||
| 301 | free_irq(chip->irq, chip); | ||
| 302 | |||
| 303 | out_free_chip: | ||
| 304 | i2c_set_clientdata(client, NULL); | ||
| 305 | kfree(chip); | ||
| 306 | |||
| 307 | return ret; | ||
| 308 | } | ||
| 309 | |||
| 310 | static int __devexit adp5520_remove(struct i2c_client *client) | ||
| 311 | { | ||
| 312 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); | ||
| 313 | |||
| 314 | if (chip->irq) | ||
| 315 | free_irq(chip->irq, chip); | ||
| 316 | |||
| 317 | adp5520_remove_subdevs(chip); | ||
| 318 | adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0); | ||
| 319 | i2c_set_clientdata(client, NULL); | ||
| 320 | kfree(chip); | ||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | |||
| 324 | #ifdef CONFIG_PM | ||
| 325 | static int adp5520_suspend(struct i2c_client *client, | ||
| 326 | pm_message_t state) | ||
| 327 | { | ||
| 328 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); | ||
| 329 | |||
| 330 | adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); | ||
| 331 | return 0; | ||
| 332 | } | ||
| 333 | |||
| 334 | static int adp5520_resume(struct i2c_client *client) | ||
| 335 | { | ||
| 336 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); | ||
| 337 | |||
| 338 | adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); | ||
| 339 | return 0; | ||
| 340 | } | ||
| 341 | #else | ||
| 342 | #define adp5520_suspend NULL | ||
| 343 | #define adp5520_resume NULL | ||
| 344 | #endif | ||
| 345 | |||
| 346 | static const struct i2c_device_id adp5520_id[] = { | ||
| 347 | { "pmic-adp5520", ID_ADP5520 }, | ||
| 348 | { "pmic-adp5501", ID_ADP5501 }, | ||
| 349 | { } | ||
| 350 | }; | ||
| 351 | MODULE_DEVICE_TABLE(i2c, adp5520_id); | ||
| 352 | |||
| 353 | static struct i2c_driver adp5520_driver = { | ||
| 354 | .driver = { | ||
| 355 | .name = "adp5520", | ||
| 356 | .owner = THIS_MODULE, | ||
| 357 | }, | ||
| 358 | .probe = adp5520_probe, | ||
| 359 | .remove = __devexit_p(adp5520_remove), | ||
| 360 | .suspend = adp5520_suspend, | ||
| 361 | .resume = adp5520_resume, | ||
| 362 | .id_table = adp5520_id, | ||
| 363 | }; | ||
| 364 | |||
| 365 | static int __init adp5520_init(void) | ||
| 366 | { | ||
| 367 | return i2c_add_driver(&adp5520_driver); | ||
| 368 | } | ||
| 369 | module_init(adp5520_init); | ||
| 370 | |||
| 371 | static void __exit adp5520_exit(void) | ||
| 372 | { | ||
| 373 | i2c_del_driver(&adp5520_driver); | ||
| 374 | } | ||
| 375 | module_exit(adp5520_exit); | ||
| 376 | |||
| 377 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
| 378 | MODULE_DESCRIPTION("ADP5520(01) PMIC-MFD Driver"); | ||
| 379 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 63a2a6632106..e22128c3e9a8 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c | |||
| @@ -908,7 +908,7 @@ static int __init asic3_probe(struct platform_device *pdev) | |||
| 908 | return ret; | 908 | return ret; |
| 909 | } | 909 | } |
| 910 | 910 | ||
| 911 | static int asic3_remove(struct platform_device *pdev) | 911 | static int __devexit asic3_remove(struct platform_device *pdev) |
| 912 | { | 912 | { |
| 913 | int ret; | 913 | int ret; |
| 914 | struct asic3 *asic = platform_get_drvdata(pdev); | 914 | struct asic3 *asic = platform_get_drvdata(pdev); |
diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 876288917976..df405af968fa 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c | |||
| @@ -387,7 +387,6 @@ static int __devinit pcap_add_subdev(struct pcap_chip *pcap, | |||
| 387 | pdev = platform_device_alloc(subdev->name, subdev->id); | 387 | pdev = platform_device_alloc(subdev->name, subdev->id); |
| 388 | pdev->dev.parent = &pcap->spi->dev; | 388 | pdev->dev.parent = &pcap->spi->dev; |
| 389 | pdev->dev.platform_data = subdev->platform_data; | 389 | pdev->dev.platform_data = subdev->platform_data; |
| 390 | platform_set_drvdata(pdev, pcap); | ||
| 391 | 390 | ||
| 392 | return platform_device_add(pdev); | 391 | return platform_device_add(pdev); |
| 393 | } | 392 | } |
diff --git a/drivers/mfd/mc13783-core.c b/drivers/mfd/mc13783-core.c index e354d2912ef1..a1ade2324ea9 100644 --- a/drivers/mfd/mc13783-core.c +++ b/drivers/mfd/mc13783-core.c | |||
| @@ -1,286 +1,549 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> | 2 | * Copyright 2009 Pengutronix |
| 3 | * | 3 | * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> |
| 4 | * This code is in parts based on wm8350-core.c and pcf50633-core.c | ||
| 5 | * | ||
| 6 | * Initial development of this code was funded by | ||
| 7 | * Phytec Messtechnik GmbH, http://www.phytec.de | ||
| 8 | * | 4 | * |
| 9 | * This program is free software; you can redistribute it and/or modify | 5 | * loosely based on an earlier driver that has |
| 10 | * it under the terms of the GNU General Public License as published by | 6 | * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> |
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | 7 | * |
| 19 | * You should have received a copy of the GNU General Public License | 8 | * This program is free software; you can redistribute it and/or modify it under |
| 20 | * along with this program; if not, write to the Free Software | 9 | * the terms of the GNU General Public License version 2 as published by the |
| 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 10 | * Free Software Foundation. |
| 22 | */ | 11 | */ |
| 23 | |||
| 24 | #include <linux/mfd/mc13783-private.h> | ||
| 25 | #include <linux/platform_device.h> | ||
| 26 | #include <linux/mfd/mc13783.h> | ||
| 27 | #include <linux/completion.h> | ||
| 28 | #include <linux/interrupt.h> | ||
| 29 | #include <linux/mfd/core.h> | ||
| 30 | #include <linux/spi/spi.h> | ||
| 31 | #include <linux/uaccess.h> | ||
| 32 | #include <linux/kernel.h> | ||
| 33 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 34 | #include <linux/init.h> | 13 | #include <linux/spi/spi.h> |
| 35 | #include <linux/slab.h> | 14 | #include <linux/mfd/core.h> |
| 36 | #include <linux/irq.h> | 15 | #include <linux/mfd/mc13783-private.h> |
| 16 | |||
| 17 | #define MC13783_IRQSTAT0 0 | ||
| 18 | #define MC13783_IRQSTAT0_ADCDONEI (1 << 0) | ||
| 19 | #define MC13783_IRQSTAT0_ADCBISDONEI (1 << 1) | ||
| 20 | #define MC13783_IRQSTAT0_TSI (1 << 2) | ||
| 21 | #define MC13783_IRQSTAT0_WHIGHI (1 << 3) | ||
| 22 | #define MC13783_IRQSTAT0_WLOWI (1 << 4) | ||
| 23 | #define MC13783_IRQSTAT0_CHGDETI (1 << 6) | ||
| 24 | #define MC13783_IRQSTAT0_CHGOVI (1 << 7) | ||
| 25 | #define MC13783_IRQSTAT0_CHGREVI (1 << 8) | ||
| 26 | #define MC13783_IRQSTAT0_CHGSHORTI (1 << 9) | ||
| 27 | #define MC13783_IRQSTAT0_CCCVI (1 << 10) | ||
| 28 | #define MC13783_IRQSTAT0_CHGCURRI (1 << 11) | ||
| 29 | #define MC13783_IRQSTAT0_BPONI (1 << 12) | ||
| 30 | #define MC13783_IRQSTAT0_LOBATLI (1 << 13) | ||
| 31 | #define MC13783_IRQSTAT0_LOBATHI (1 << 14) | ||
| 32 | #define MC13783_IRQSTAT0_UDPI (1 << 15) | ||
| 33 | #define MC13783_IRQSTAT0_USBI (1 << 16) | ||
| 34 | #define MC13783_IRQSTAT0_IDI (1 << 19) | ||
| 35 | #define MC13783_IRQSTAT0_SE1I (1 << 21) | ||
| 36 | #define MC13783_IRQSTAT0_CKDETI (1 << 22) | ||
| 37 | #define MC13783_IRQSTAT0_UDMI (1 << 23) | ||
| 38 | |||
| 39 | #define MC13783_IRQMASK0 1 | ||
| 40 | #define MC13783_IRQMASK0_ADCDONEM MC13783_IRQSTAT0_ADCDONEI | ||
| 41 | #define MC13783_IRQMASK0_ADCBISDONEM MC13783_IRQSTAT0_ADCBISDONEI | ||
| 42 | #define MC13783_IRQMASK0_TSM MC13783_IRQSTAT0_TSI | ||
| 43 | #define MC13783_IRQMASK0_WHIGHM MC13783_IRQSTAT0_WHIGHI | ||
| 44 | #define MC13783_IRQMASK0_WLOWM MC13783_IRQSTAT0_WLOWI | ||
| 45 | #define MC13783_IRQMASK0_CHGDETM MC13783_IRQSTAT0_CHGDETI | ||
| 46 | #define MC13783_IRQMASK0_CHGOVM MC13783_IRQSTAT0_CHGOVI | ||
| 47 | #define MC13783_IRQMASK0_CHGREVM MC13783_IRQSTAT0_CHGREVI | ||
| 48 | #define MC13783_IRQMASK0_CHGSHORTM MC13783_IRQSTAT0_CHGSHORTI | ||
| 49 | #define MC13783_IRQMASK0_CCCVM MC13783_IRQSTAT0_CCCVI | ||
| 50 | #define MC13783_IRQMASK0_CHGCURRM MC13783_IRQSTAT0_CHGCURRI | ||
| 51 | #define MC13783_IRQMASK0_BPONM MC13783_IRQSTAT0_BPONI | ||
| 52 | #define MC13783_IRQMASK0_LOBATLM MC13783_IRQSTAT0_LOBATLI | ||
| 53 | #define MC13783_IRQMASK0_LOBATHM MC13783_IRQSTAT0_LOBATHI | ||
| 54 | #define MC13783_IRQMASK0_UDPM MC13783_IRQSTAT0_UDPI | ||
| 55 | #define MC13783_IRQMASK0_USBM MC13783_IRQSTAT0_USBI | ||
| 56 | #define MC13783_IRQMASK0_IDM MC13783_IRQSTAT0_IDI | ||
| 57 | #define MC13783_IRQMASK0_SE1M MC13783_IRQSTAT0_SE1I | ||
| 58 | #define MC13783_IRQMASK0_CKDETM MC13783_IRQSTAT0_CKDETI | ||
| 59 | #define MC13783_IRQMASK0_UDMM MC13783_IRQSTAT0_UDMI | ||
| 60 | |||
| 61 | #define MC13783_IRQSTAT1 3 | ||
| 62 | #define MC13783_IRQSTAT1_1HZI (1 << 0) | ||
| 63 | #define MC13783_IRQSTAT1_TODAI (1 << 1) | ||
| 64 | #define MC13783_IRQSTAT1_ONOFD1I (1 << 3) | ||
| 65 | #define MC13783_IRQSTAT1_ONOFD2I (1 << 4) | ||
| 66 | #define MC13783_IRQSTAT1_ONOFD3I (1 << 5) | ||
| 67 | #define MC13783_IRQSTAT1_SYSRSTI (1 << 6) | ||
| 68 | #define MC13783_IRQSTAT1_RTCRSTI (1 << 7) | ||
| 69 | #define MC13783_IRQSTAT1_PCI (1 << 8) | ||
| 70 | #define MC13783_IRQSTAT1_WARMI (1 << 9) | ||
| 71 | #define MC13783_IRQSTAT1_MEMHLDI (1 << 10) | ||
| 72 | #define MC13783_IRQSTAT1_PWRRDYI (1 << 11) | ||
| 73 | #define MC13783_IRQSTAT1_THWARNLI (1 << 12) | ||
| 74 | #define MC13783_IRQSTAT1_THWARNHI (1 << 13) | ||
| 75 | #define MC13783_IRQSTAT1_CLKI (1 << 14) | ||
| 76 | #define MC13783_IRQSTAT1_SEMAFI (1 << 15) | ||
| 77 | #define MC13783_IRQSTAT1_MC2BI (1 << 17) | ||
| 78 | #define MC13783_IRQSTAT1_HSDETI (1 << 18) | ||
| 79 | #define MC13783_IRQSTAT1_HSLI (1 << 19) | ||
| 80 | #define MC13783_IRQSTAT1_ALSPTHI (1 << 20) | ||
| 81 | #define MC13783_IRQSTAT1_AHSSHORTI (1 << 21) | ||
| 82 | |||
| 83 | #define MC13783_IRQMASK1 4 | ||
| 84 | #define MC13783_IRQMASK1_1HZM MC13783_IRQSTAT1_1HZI | ||
| 85 | #define MC13783_IRQMASK1_TODAM MC13783_IRQSTAT1_TODAI | ||
| 86 | #define MC13783_IRQMASK1_ONOFD1M MC13783_IRQSTAT1_ONOFD1I | ||
| 87 | #define MC13783_IRQMASK1_ONOFD2M MC13783_IRQSTAT1_ONOFD2I | ||
| 88 | #define MC13783_IRQMASK1_ONOFD3M MC13783_IRQSTAT1_ONOFD3I | ||
| 89 | #define MC13783_IRQMASK1_SYSRSTM MC13783_IRQSTAT1_SYSRSTI | ||
| 90 | #define MC13783_IRQMASK1_RTCRSTM MC13783_IRQSTAT1_RTCRSTI | ||
| 91 | #define MC13783_IRQMASK1_PCM MC13783_IRQSTAT1_PCI | ||
| 92 | #define MC13783_IRQMASK1_WARMM MC13783_IRQSTAT1_WARMI | ||
| 93 | #define MC13783_IRQMASK1_MEMHLDM MC13783_IRQSTAT1_MEMHLDI | ||
| 94 | #define MC13783_IRQMASK1_PWRRDYM MC13783_IRQSTAT1_PWRRDYI | ||
| 95 | #define MC13783_IRQMASK1_THWARNLM MC13783_IRQSTAT1_THWARNLI | ||
| 96 | #define MC13783_IRQMASK1_THWARNHM MC13783_IRQSTAT1_THWARNHI | ||
| 97 | #define MC13783_IRQMASK1_CLKM MC13783_IRQSTAT1_CLKI | ||
| 98 | #define MC13783_IRQMASK1_SEMAFM MC13783_IRQSTAT1_SEMAFI | ||
| 99 | #define MC13783_IRQMASK1_MC2BM MC13783_IRQSTAT1_MC2BI | ||
| 100 | #define MC13783_IRQMASK1_HSDETM MC13783_IRQSTAT1_HSDETI | ||
| 101 | #define MC13783_IRQMASK1_HSLM MC13783_IRQSTAT1_HSLI | ||
| 102 | #define MC13783_IRQMASK1_ALSPTHM MC13783_IRQSTAT1_ALSPTHI | ||
| 103 | #define MC13783_IRQMASK1_AHSSHORTM MC13783_IRQSTAT1_AHSSHORTI | ||
| 104 | |||
| 105 | #define MC13783_ADC1 44 | ||
| 106 | #define MC13783_ADC1_ADEN (1 << 0) | ||
| 107 | #define MC13783_ADC1_RAND (1 << 1) | ||
| 108 | #define MC13783_ADC1_ADSEL (1 << 3) | ||
| 109 | #define MC13783_ADC1_ASC (1 << 20) | ||
| 110 | #define MC13783_ADC1_ADTRIGIGN (1 << 21) | ||
| 111 | |||
| 112 | #define MC13783_NUMREGS 0x3f | ||
| 113 | |||
| 114 | void mc13783_lock(struct mc13783 *mc13783) | ||
| 115 | { | ||
| 116 | if (!mutex_trylock(&mc13783->lock)) { | ||
| 117 | dev_dbg(&mc13783->spidev->dev, "wait for %s from %pf\n", | ||
| 118 | __func__, __builtin_return_address(0)); | ||
| 119 | |||
| 120 | mutex_lock(&mc13783->lock); | ||
| 121 | } | ||
| 122 | dev_dbg(&mc13783->spidev->dev, "%s from %pf\n", | ||
| 123 | __func__, __builtin_return_address(0)); | ||
| 124 | } | ||
| 125 | EXPORT_SYMBOL(mc13783_lock); | ||
| 37 | 126 | ||
| 38 | #define MC13783_MAX_REG_NUM 0x3f | 127 | void mc13783_unlock(struct mc13783 *mc13783) |
| 39 | #define MC13783_FRAME_MASK 0x00ffffff | 128 | { |
| 40 | #define MC13783_MAX_REG_NUM 0x3f | 129 | dev_dbg(&mc13783->spidev->dev, "%s from %pf\n", |
| 41 | #define MC13783_REG_NUM_SHIFT 0x19 | 130 | __func__, __builtin_return_address(0)); |
| 42 | #define MC13783_WRITE_BIT_SHIFT 31 | 131 | mutex_unlock(&mc13783->lock); |
| 132 | } | ||
| 133 | EXPORT_SYMBOL(mc13783_unlock); | ||
| 43 | 134 | ||
| 44 | static inline int spi_rw(struct spi_device *spi, u8 * buf, size_t len) | 135 | #define MC13783_REGOFFSET_SHIFT 25 |
| 136 | int mc13783_reg_read(struct mc13783 *mc13783, unsigned int offset, u32 *val) | ||
| 45 | { | 137 | { |
| 46 | struct spi_transfer t = { | 138 | struct spi_transfer t; |
| 47 | .tx_buf = (const void *)buf, | ||
| 48 | .rx_buf = buf, | ||
| 49 | .len = len, | ||
| 50 | .cs_change = 0, | ||
| 51 | .delay_usecs = 0, | ||
| 52 | }; | ||
| 53 | struct spi_message m; | 139 | struct spi_message m; |
| 140 | int ret; | ||
| 141 | |||
| 142 | BUG_ON(!mutex_is_locked(&mc13783->lock)); | ||
| 143 | |||
| 144 | if (offset > MC13783_NUMREGS) | ||
| 145 | return -EINVAL; | ||
| 146 | |||
| 147 | *val = offset << MC13783_REGOFFSET_SHIFT; | ||
| 148 | |||
| 149 | memset(&t, 0, sizeof(t)); | ||
| 150 | |||
| 151 | t.tx_buf = val; | ||
| 152 | t.rx_buf = val; | ||
| 153 | t.len = sizeof(u32); | ||
| 54 | 154 | ||
| 55 | spi_message_init(&m); | 155 | spi_message_init(&m); |
| 56 | spi_message_add_tail(&t, &m); | 156 | spi_message_add_tail(&t, &m); |
| 57 | if (spi_sync(spi, &m) != 0 || m.status != 0) | ||
| 58 | return -EINVAL; | ||
| 59 | return len - m.actual_length; | ||
| 60 | } | ||
| 61 | 157 | ||
| 62 | static int mc13783_read(struct mc13783 *mc13783, int reg_num, u32 *reg_val) | 158 | ret = spi_sync(mc13783->spidev, &m); |
| 63 | { | ||
| 64 | unsigned int frame = 0; | ||
| 65 | int ret = 0; | ||
| 66 | 159 | ||
| 67 | if (reg_num > MC13783_MAX_REG_NUM) | 160 | /* error in message.status implies error return from spi_sync */ |
| 68 | return -EINVAL; | 161 | BUG_ON(!ret && m.status); |
| 69 | 162 | ||
| 70 | frame |= reg_num << MC13783_REG_NUM_SHIFT; | 163 | if (ret) |
| 164 | return ret; | ||
| 71 | 165 | ||
| 72 | ret = spi_rw(mc13783->spi_device, (u8 *)&frame, 4); | 166 | *val &= 0xffffff; |
| 73 | 167 | ||
| 74 | *reg_val = frame & MC13783_FRAME_MASK; | 168 | dev_vdbg(&mc13783->spidev->dev, "[0x%02x] -> 0x%06x\n", offset, *val); |
| 75 | 169 | ||
| 76 | return ret; | 170 | return 0; |
| 77 | } | 171 | } |
| 172 | EXPORT_SYMBOL(mc13783_reg_read); | ||
| 78 | 173 | ||
| 79 | static int mc13783_write(struct mc13783 *mc13783, int reg_num, u32 reg_val) | 174 | int mc13783_reg_write(struct mc13783 *mc13783, unsigned int offset, u32 val) |
| 80 | { | 175 | { |
| 81 | unsigned int frame = 0; | 176 | u32 buf; |
| 177 | struct spi_transfer t; | ||
| 178 | struct spi_message m; | ||
| 179 | int ret; | ||
| 180 | |||
| 181 | BUG_ON(!mutex_is_locked(&mc13783->lock)); | ||
| 82 | 182 | ||
| 83 | if (reg_num > MC13783_MAX_REG_NUM) | 183 | dev_vdbg(&mc13783->spidev->dev, "[0x%02x] <- 0x%06x\n", offset, val); |
| 184 | |||
| 185 | if (offset > MC13783_NUMREGS || val > 0xffffff) | ||
| 84 | return -EINVAL; | 186 | return -EINVAL; |
| 85 | 187 | ||
| 86 | frame |= (1 << MC13783_WRITE_BIT_SHIFT); | 188 | buf = 1 << 31 | offset << MC13783_REGOFFSET_SHIFT | val; |
| 87 | frame |= reg_num << MC13783_REG_NUM_SHIFT; | 189 | |
| 88 | frame |= reg_val & MC13783_FRAME_MASK; | 190 | memset(&t, 0, sizeof(t)); |
| 89 | 191 | ||
| 90 | return spi_rw(mc13783->spi_device, (u8 *)&frame, 4); | 192 | t.tx_buf = &buf; |
| 193 | t.rx_buf = &buf; | ||
| 194 | t.len = sizeof(u32); | ||
| 195 | |||
| 196 | spi_message_init(&m); | ||
| 197 | spi_message_add_tail(&t, &m); | ||
| 198 | |||
| 199 | ret = spi_sync(mc13783->spidev, &m); | ||
| 200 | |||
| 201 | BUG_ON(!ret && m.status); | ||
| 202 | |||
| 203 | if (ret) | ||
| 204 | return ret; | ||
| 205 | |||
| 206 | return 0; | ||
| 91 | } | 207 | } |
| 208 | EXPORT_SYMBOL(mc13783_reg_write); | ||
| 92 | 209 | ||
| 93 | int mc13783_reg_read(struct mc13783 *mc13783, int reg_num, u32 *reg_val) | 210 | int mc13783_reg_rmw(struct mc13783 *mc13783, unsigned int offset, |
| 211 | u32 mask, u32 val) | ||
| 94 | { | 212 | { |
| 95 | int ret; | 213 | int ret; |
| 214 | u32 valread; | ||
| 96 | 215 | ||
| 97 | mutex_lock(&mc13783->io_lock); | 216 | BUG_ON(val & ~mask); |
| 98 | ret = mc13783_read(mc13783, reg_num, reg_val); | ||
| 99 | mutex_unlock(&mc13783->io_lock); | ||
| 100 | 217 | ||
| 101 | return ret; | 218 | ret = mc13783_reg_read(mc13783, offset, &valread); |
| 219 | if (ret) | ||
| 220 | return ret; | ||
| 221 | |||
| 222 | valread = (valread & ~mask) | val; | ||
| 223 | |||
| 224 | return mc13783_reg_write(mc13783, offset, valread); | ||
| 102 | } | 225 | } |
| 103 | EXPORT_SYMBOL_GPL(mc13783_reg_read); | 226 | EXPORT_SYMBOL(mc13783_reg_rmw); |
| 104 | 227 | ||
| 105 | int mc13783_reg_write(struct mc13783 *mc13783, int reg_num, u32 reg_val) | 228 | int mc13783_mask(struct mc13783 *mc13783, int irq) |
| 106 | { | 229 | { |
| 107 | int ret; | 230 | int ret; |
| 231 | unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1; | ||
| 232 | u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | ||
| 233 | u32 mask; | ||
| 108 | 234 | ||
| 109 | mutex_lock(&mc13783->io_lock); | 235 | if (irq < 0 || irq >= MC13783_NUM_IRQ) |
| 110 | ret = mc13783_write(mc13783, reg_num, reg_val); | 236 | return -EINVAL; |
| 111 | mutex_unlock(&mc13783->io_lock); | ||
| 112 | 237 | ||
| 113 | return ret; | 238 | ret = mc13783_reg_read(mc13783, offmask, &mask); |
| 239 | if (ret) | ||
| 240 | return ret; | ||
| 241 | |||
| 242 | if (mask & irqbit) | ||
| 243 | /* already masked */ | ||
| 244 | return 0; | ||
| 245 | |||
| 246 | return mc13783_reg_write(mc13783, offmask, mask | irqbit); | ||
| 114 | } | 247 | } |
| 115 | EXPORT_SYMBOL_GPL(mc13783_reg_write); | 248 | EXPORT_SYMBOL(mc13783_mask); |
| 116 | 249 | ||
| 117 | /** | 250 | int mc13783_unmask(struct mc13783 *mc13783, int irq) |
| 118 | * mc13783_set_bits - Bitmask write | ||
| 119 | * | ||
| 120 | * @mc13783: Pointer to mc13783 control structure | ||
| 121 | * @reg: Register to access | ||
| 122 | * @mask: Mask of bits to change | ||
| 123 | * @val: Value to set for masked bits | ||
| 124 | */ | ||
| 125 | int mc13783_set_bits(struct mc13783 *mc13783, int reg, u32 mask, u32 val) | ||
| 126 | { | 251 | { |
| 127 | u32 tmp; | ||
| 128 | int ret; | 252 | int ret; |
| 253 | unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1; | ||
| 254 | u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | ||
| 255 | u32 mask; | ||
| 129 | 256 | ||
| 130 | mutex_lock(&mc13783->io_lock); | 257 | if (irq < 0 || irq >= MC13783_NUM_IRQ) |
| 258 | return -EINVAL; | ||
| 131 | 259 | ||
| 132 | ret = mc13783_read(mc13783, reg, &tmp); | 260 | ret = mc13783_reg_read(mc13783, offmask, &mask); |
| 133 | tmp = (tmp & ~mask) | val; | 261 | if (ret) |
| 134 | if (ret == 0) | 262 | return ret; |
| 135 | ret = mc13783_write(mc13783, reg, tmp); | ||
| 136 | 263 | ||
| 137 | mutex_unlock(&mc13783->io_lock); | 264 | if (!(mask & irqbit)) |
| 265 | /* already unmasked */ | ||
| 266 | return 0; | ||
| 138 | 267 | ||
| 139 | return ret; | 268 | return mc13783_reg_write(mc13783, offmask, mask & ~irqbit); |
| 140 | } | 269 | } |
| 141 | EXPORT_SYMBOL_GPL(mc13783_set_bits); | 270 | EXPORT_SYMBOL(mc13783_unmask); |
| 142 | 271 | ||
| 143 | int mc13783_register_irq(struct mc13783 *mc13783, int irq, | 272 | int mc13783_irq_request_nounmask(struct mc13783 *mc13783, int irq, |
| 144 | void (*handler) (int, void *), void *data) | 273 | irq_handler_t handler, const char *name, void *dev) |
| 145 | { | 274 | { |
| 146 | if (irq < 0 || irq > MC13783_NUM_IRQ || !handler) | 275 | BUG_ON(!mutex_is_locked(&mc13783->lock)); |
| 276 | BUG_ON(!handler); | ||
| 277 | |||
| 278 | if (irq < 0 || irq >= MC13783_NUM_IRQ) | ||
| 147 | return -EINVAL; | 279 | return -EINVAL; |
| 148 | 280 | ||
| 149 | if (WARN_ON(mc13783->irq_handler[irq].handler)) | 281 | if (mc13783->irqhandler[irq]) |
| 150 | return -EBUSY; | 282 | return -EBUSY; |
| 151 | 283 | ||
| 152 | mutex_lock(&mc13783->io_lock); | 284 | mc13783->irqhandler[irq] = handler; |
| 153 | mc13783->irq_handler[irq].handler = handler; | 285 | mc13783->irqdata[irq] = dev; |
| 154 | mc13783->irq_handler[irq].data = data; | ||
| 155 | mutex_unlock(&mc13783->io_lock); | ||
| 156 | 286 | ||
| 157 | return 0; | 287 | return 0; |
| 158 | } | 288 | } |
| 159 | EXPORT_SYMBOL_GPL(mc13783_register_irq); | 289 | EXPORT_SYMBOL(mc13783_irq_request_nounmask); |
| 160 | 290 | ||
| 161 | int mc13783_free_irq(struct mc13783 *mc13783, int irq) | 291 | int mc13783_irq_request(struct mc13783 *mc13783, int irq, |
| 292 | irq_handler_t handler, const char *name, void *dev) | ||
| 162 | { | 293 | { |
| 163 | if (irq < 0 || irq > MC13783_NUM_IRQ) | 294 | int ret; |
| 295 | |||
| 296 | ret = mc13783_irq_request_nounmask(mc13783, irq, handler, name, dev); | ||
| 297 | if (ret) | ||
| 298 | return ret; | ||
| 299 | |||
| 300 | ret = mc13783_unmask(mc13783, irq); | ||
| 301 | if (ret) { | ||
| 302 | mc13783->irqhandler[irq] = NULL; | ||
| 303 | mc13783->irqdata[irq] = NULL; | ||
| 304 | return ret; | ||
| 305 | } | ||
| 306 | |||
| 307 | return 0; | ||
| 308 | } | ||
| 309 | EXPORT_SYMBOL(mc13783_irq_request); | ||
| 310 | |||
| 311 | int mc13783_irq_free(struct mc13783 *mc13783, int irq, void *dev) | ||
| 312 | { | ||
| 313 | int ret; | ||
| 314 | BUG_ON(!mutex_is_locked(&mc13783->lock)); | ||
| 315 | |||
| 316 | if (irq < 0 || irq >= MC13783_NUM_IRQ || !mc13783->irqhandler[irq] || | ||
| 317 | mc13783->irqdata[irq] != dev) | ||
| 164 | return -EINVAL; | 318 | return -EINVAL; |
| 165 | 319 | ||
| 166 | mutex_lock(&mc13783->io_lock); | 320 | ret = mc13783_mask(mc13783, irq); |
| 167 | mc13783->irq_handler[irq].handler = NULL; | 321 | if (ret) |
| 168 | mutex_unlock(&mc13783->io_lock); | 322 | return ret; |
| 323 | |||
| 324 | mc13783->irqhandler[irq] = NULL; | ||
| 325 | mc13783->irqdata[irq] = NULL; | ||
| 169 | 326 | ||
| 170 | return 0; | 327 | return 0; |
| 171 | } | 328 | } |
| 172 | EXPORT_SYMBOL_GPL(mc13783_free_irq); | 329 | EXPORT_SYMBOL(mc13783_irq_free); |
| 173 | 330 | ||
| 174 | static void mc13783_irq_work(struct work_struct *work) | 331 | static inline irqreturn_t mc13783_irqhandler(struct mc13783 *mc13783, int irq) |
| 175 | { | 332 | { |
| 176 | struct mc13783 *mc13783 = container_of(work, struct mc13783, work); | 333 | return mc13783->irqhandler[irq](irq, mc13783->irqdata[irq]); |
| 177 | int i; | ||
| 178 | unsigned int adc_sts; | ||
| 179 | |||
| 180 | /* check if the adc has finished any completion */ | ||
| 181 | mc13783_reg_read(mc13783, MC13783_REG_INTERRUPT_STATUS_0, &adc_sts); | ||
| 182 | mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_STATUS_0, | ||
| 183 | adc_sts & MC13783_INT_STAT_ADCDONEI); | ||
| 184 | |||
| 185 | if (adc_sts & MC13783_INT_STAT_ADCDONEI) | ||
| 186 | complete_all(&mc13783->adc_done); | ||
| 187 | |||
| 188 | for (i = 0; i < MC13783_NUM_IRQ; i++) | ||
| 189 | if (mc13783->irq_handler[i].handler) | ||
| 190 | mc13783->irq_handler[i].handler(i, | ||
| 191 | mc13783->irq_handler[i].data); | ||
| 192 | enable_irq(mc13783->irq); | ||
| 193 | } | 334 | } |
| 194 | 335 | ||
| 195 | static irqreturn_t mc13783_interrupt(int irq, void *dev_id) | 336 | int mc13783_ackirq(struct mc13783 *mc13783, int irq) |
| 196 | { | 337 | { |
| 197 | struct mc13783 *mc13783 = dev_id; | 338 | unsigned int offstat = irq < 24 ? MC13783_IRQSTAT0 : MC13783_IRQSTAT1; |
| 339 | unsigned int val = 1 << (irq < 24 ? irq : irq - 24); | ||
| 198 | 340 | ||
| 199 | disable_irq_nosync(irq); | 341 | BUG_ON(irq < 0 || irq >= MC13783_NUM_IRQ); |
| 200 | 342 | ||
| 201 | schedule_work(&mc13783->work); | 343 | return mc13783_reg_write(mc13783, offstat, val); |
| 202 | return IRQ_HANDLED; | ||
| 203 | } | 344 | } |
| 345 | EXPORT_SYMBOL(mc13783_ackirq); | ||
| 204 | 346 | ||
| 205 | /* set adc to ts interrupt mode, which generates touchscreen wakeup interrupt */ | 347 | /* |
| 206 | static inline void mc13783_adc_set_ts_irq_mode(struct mc13783 *mc13783) | 348 | * returns: number of handled irqs or negative error |
| 349 | * locking: holds mc13783->lock | ||
| 350 | */ | ||
| 351 | static int mc13783_irq_handle(struct mc13783 *mc13783, | ||
| 352 | unsigned int offstat, unsigned int offmask, int baseirq) | ||
| 207 | { | 353 | { |
| 208 | unsigned int reg_adc0, reg_adc1; | 354 | u32 stat, mask; |
| 355 | int ret = mc13783_reg_read(mc13783, offstat, &stat); | ||
| 356 | int num_handled = 0; | ||
| 357 | |||
| 358 | if (ret) | ||
| 359 | return ret; | ||
| 360 | |||
| 361 | ret = mc13783_reg_read(mc13783, offmask, &mask); | ||
| 362 | if (ret) | ||
| 363 | return ret; | ||
| 364 | |||
| 365 | while (stat & ~mask) { | ||
| 366 | int irq = __ffs(stat & ~mask); | ||
| 367 | |||
| 368 | stat &= ~(1 << irq); | ||
| 369 | |||
| 370 | if (likely(mc13783->irqhandler[baseirq + irq])) { | ||
| 371 | irqreturn_t handled; | ||
| 209 | 372 | ||
| 210 | reg_adc0 = MC13783_ADC0_ADREFEN | MC13783_ADC0_ADREFMODE | 373 | handled = mc13783_irqhandler(mc13783, baseirq + irq); |
| 211 | | MC13783_ADC0_TSMOD0; | 374 | if (handled == IRQ_HANDLED) |
| 212 | reg_adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN; | 375 | num_handled++; |
| 376 | } else { | ||
| 377 | dev_err(&mc13783->spidev->dev, | ||
| 378 | "BUG: irq %u but no handler\n", | ||
| 379 | baseirq + irq); | ||
| 213 | 380 | ||
| 214 | mc13783_reg_write(mc13783, MC13783_REG_ADC_0, reg_adc0); | 381 | mask |= 1 << irq; |
| 215 | mc13783_reg_write(mc13783, MC13783_REG_ADC_1, reg_adc1); | 382 | |
| 383 | ret = mc13783_reg_write(mc13783, offmask, mask); | ||
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 387 | return num_handled; | ||
| 216 | } | 388 | } |
| 217 | 389 | ||
| 390 | static irqreturn_t mc13783_irq_thread(int irq, void *data) | ||
| 391 | { | ||
| 392 | struct mc13783 *mc13783 = data; | ||
| 393 | irqreturn_t ret; | ||
| 394 | int handled = 0; | ||
| 395 | |||
| 396 | mc13783_lock(mc13783); | ||
| 397 | |||
| 398 | ret = mc13783_irq_handle(mc13783, MC13783_IRQSTAT0, | ||
| 399 | MC13783_IRQMASK0, MC13783_IRQ_ADCDONE); | ||
| 400 | if (ret > 0) | ||
| 401 | handled = 1; | ||
| 402 | |||
| 403 | ret = mc13783_irq_handle(mc13783, MC13783_IRQSTAT1, | ||
| 404 | MC13783_IRQMASK1, MC13783_IRQ_1HZ); | ||
| 405 | if (ret > 0) | ||
| 406 | handled = 1; | ||
| 407 | |||
| 408 | mc13783_unlock(mc13783); | ||
| 409 | |||
| 410 | return IRQ_RETVAL(handled); | ||
| 411 | } | ||
| 412 | |||
| 413 | #define MC13783_ADC1_CHAN0_SHIFT 5 | ||
| 414 | #define MC13783_ADC1_CHAN1_SHIFT 8 | ||
| 415 | |||
| 416 | struct mc13783_adcdone_data { | ||
| 417 | struct mc13783 *mc13783; | ||
| 418 | struct completion done; | ||
| 419 | }; | ||
| 420 | |||
| 421 | static irqreturn_t mc13783_handler_adcdone(int irq, void *data) | ||
| 422 | { | ||
| 423 | struct mc13783_adcdone_data *adcdone_data = data; | ||
| 424 | |||
| 425 | mc13783_ackirq(adcdone_data->mc13783, irq); | ||
| 426 | |||
| 427 | complete_all(&adcdone_data->done); | ||
| 428 | |||
| 429 | return IRQ_HANDLED; | ||
| 430 | } | ||
| 431 | |||
| 432 | #define MC13783_ADC_WORKING (1 << 16) | ||
| 433 | |||
| 218 | int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, | 434 | int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, |
| 219 | unsigned int channel, unsigned int *sample) | 435 | unsigned int channel, unsigned int *sample) |
| 220 | { | 436 | { |
| 221 | unsigned int reg_adc0, reg_adc1; | 437 | u32 adc0, adc1, old_adc0; |
| 222 | int i; | 438 | int i, ret; |
| 439 | struct mc13783_adcdone_data adcdone_data = { | ||
| 440 | .mc13783 = mc13783, | ||
| 441 | }; | ||
| 442 | init_completion(&adcdone_data.done); | ||
| 443 | |||
| 444 | dev_dbg(&mc13783->spidev->dev, "%s\n", __func__); | ||
| 445 | |||
| 446 | mc13783_lock(mc13783); | ||
| 447 | |||
| 448 | if (mc13783->flags & MC13783_ADC_WORKING) { | ||
| 449 | ret = -EBUSY; | ||
| 450 | goto out; | ||
| 451 | } | ||
| 452 | |||
| 453 | mc13783->flags |= MC13783_ADC_WORKING; | ||
| 223 | 454 | ||
| 224 | mutex_lock(&mc13783->adc_conv_lock); | 455 | mc13783_reg_read(mc13783, MC13783_ADC0, &old_adc0); |
| 225 | 456 | ||
| 226 | /* set up auto incrementing anyway to make quick read */ | 457 | adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2; |
| 227 | reg_adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2; | 458 | adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN | MC13783_ADC1_ASC; |
| 228 | /* enable the adc, ignore external triggering and set ASC to trigger | ||
| 229 | * conversion */ | ||
| 230 | reg_adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN | ||
| 231 | | MC13783_ADC1_ASC; | ||
| 232 | 459 | ||
| 233 | /* setup channel number */ | ||
| 234 | if (channel > 7) | 460 | if (channel > 7) |
| 235 | reg_adc1 |= MC13783_ADC1_ADSEL; | 461 | adc1 |= MC13783_ADC1_ADSEL; |
| 236 | 462 | ||
| 237 | switch (mode) { | 463 | switch (mode) { |
| 238 | case MC13783_ADC_MODE_TS: | 464 | case MC13783_ADC_MODE_TS: |
| 239 | /* enables touch screen reference mode and set touchscreen mode | 465 | adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_TSMOD0 | |
| 240 | * to position mode */ | 466 | MC13783_ADC0_TSMOD1; |
| 241 | reg_adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_ADREFMODE | 467 | adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; |
| 242 | | MC13783_ADC0_TSMOD0 | MC13783_ADC0_TSMOD1; | ||
| 243 | reg_adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | ||
| 244 | break; | 468 | break; |
| 469 | |||
| 245 | case MC13783_ADC_MODE_SINGLE_CHAN: | 470 | case MC13783_ADC_MODE_SINGLE_CHAN: |
| 246 | reg_adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT; | 471 | adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; |
| 247 | reg_adc1 |= MC13783_ADC1_RAND; | 472 | adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT; |
| 473 | adc1 |= MC13783_ADC1_RAND; | ||
| 248 | break; | 474 | break; |
| 475 | |||
| 249 | case MC13783_ADC_MODE_MULT_CHAN: | 476 | case MC13783_ADC_MODE_MULT_CHAN: |
| 250 | reg_adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | 477 | adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; |
| 478 | adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | ||
| 251 | break; | 479 | break; |
| 480 | |||
| 252 | default: | 481 | default: |
| 482 | mc13783_unlock(mc13783); | ||
| 253 | return -EINVAL; | 483 | return -EINVAL; |
| 254 | } | 484 | } |
| 255 | 485 | ||
| 256 | mc13783_reg_write(mc13783, MC13783_REG_ADC_0, reg_adc0); | 486 | dev_dbg(&mc13783->spidev->dev, "%s: request irq\n", __func__); |
| 257 | mc13783_reg_write(mc13783, MC13783_REG_ADC_1, reg_adc1); | 487 | mc13783_irq_request(mc13783, MC13783_IRQ_ADCDONE, |
| 488 | mc13783_handler_adcdone, __func__, &adcdone_data); | ||
| 489 | mc13783_ackirq(mc13783, MC13783_IRQ_ADCDONE); | ||
| 258 | 490 | ||
| 259 | wait_for_completion_interruptible(&mc13783->adc_done); | 491 | mc13783_reg_write(mc13783, MC13783_REG_ADC_0, adc0); |
| 492 | mc13783_reg_write(mc13783, MC13783_REG_ADC_1, adc1); | ||
| 260 | 493 | ||
| 261 | for (i = 0; i < 4; i++) | 494 | mc13783_unlock(mc13783); |
| 262 | mc13783_reg_read(mc13783, MC13783_REG_ADC_2, &sample[i]); | ||
| 263 | 495 | ||
| 264 | if (mc13783->ts_active) | 496 | ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ); |
| 265 | mc13783_adc_set_ts_irq_mode(mc13783); | ||
| 266 | 497 | ||
| 267 | mutex_unlock(&mc13783->adc_conv_lock); | 498 | if (!ret) |
| 499 | ret = -ETIMEDOUT; | ||
| 268 | 500 | ||
| 269 | return 0; | 501 | mc13783_lock(mc13783); |
| 502 | |||
| 503 | mc13783_irq_free(mc13783, MC13783_IRQ_ADCDONE, &adcdone_data); | ||
| 504 | |||
| 505 | if (ret > 0) | ||
| 506 | for (i = 0; i < 4; ++i) { | ||
| 507 | ret = mc13783_reg_read(mc13783, | ||
| 508 | MC13783_REG_ADC_2, &sample[i]); | ||
| 509 | if (ret) | ||
| 510 | break; | ||
| 511 | } | ||
| 512 | |||
| 513 | if (mode == MC13783_ADC_MODE_TS) | ||
| 514 | /* restore TSMOD */ | ||
| 515 | mc13783_reg_write(mc13783, MC13783_REG_ADC_0, old_adc0); | ||
| 516 | |||
| 517 | mc13783->flags &= ~MC13783_ADC_WORKING; | ||
| 518 | out: | ||
| 519 | mc13783_unlock(mc13783); | ||
| 520 | |||
| 521 | return ret; | ||
| 270 | } | 522 | } |
| 271 | EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); | 523 | EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); |
| 272 | 524 | ||
| 273 | void mc13783_adc_set_ts_status(struct mc13783 *mc13783, unsigned int status) | 525 | static int mc13783_add_subdevice_pdata(struct mc13783 *mc13783, |
| 526 | const char *name, void *pdata, size_t pdata_size) | ||
| 274 | { | 527 | { |
| 275 | mc13783->ts_active = status; | 528 | struct mfd_cell cell = { |
| 529 | .name = name, | ||
| 530 | .platform_data = pdata, | ||
| 531 | .data_size = pdata_size, | ||
| 532 | }; | ||
| 533 | |||
| 534 | return mfd_add_devices(&mc13783->spidev->dev, -1, &cell, 1, NULL, 0); | ||
| 535 | } | ||
| 536 | |||
| 537 | static int mc13783_add_subdevice(struct mc13783 *mc13783, const char *name) | ||
| 538 | { | ||
| 539 | return mc13783_add_subdevice_pdata(mc13783, name, NULL, 0); | ||
| 276 | } | 540 | } |
| 277 | EXPORT_SYMBOL_GPL(mc13783_adc_set_ts_status); | ||
| 278 | 541 | ||
| 279 | static int mc13783_check_revision(struct mc13783 *mc13783) | 542 | static int mc13783_check_revision(struct mc13783 *mc13783) |
| 280 | { | 543 | { |
| 281 | u32 rev_id, rev1, rev2, finid, icid; | 544 | u32 rev_id, rev1, rev2, finid, icid; |
| 282 | 545 | ||
| 283 | mc13783_read(mc13783, MC13783_REG_REVISION, &rev_id); | 546 | mc13783_reg_read(mc13783, MC13783_REG_REVISION, &rev_id); |
| 284 | 547 | ||
| 285 | rev1 = (rev_id & 0x018) >> 3; | 548 | rev1 = (rev_id & 0x018) >> 3; |
| 286 | rev2 = (rev_id & 0x007); | 549 | rev2 = (rev_id & 0x007); |
| @@ -292,38 +555,24 @@ static int mc13783_check_revision(struct mc13783 *mc13783) | |||
| 292 | rev1 = 3; | 555 | rev1 = 3; |
| 293 | 556 | ||
| 294 | if (rev1 == 0 || icid != 2) { | 557 | if (rev1 == 0 || icid != 2) { |
| 295 | dev_err(mc13783->dev, "No MC13783 detected.\n"); | 558 | dev_err(&mc13783->spidev->dev, "No MC13783 detected.\n"); |
| 296 | return -ENODEV; | 559 | return -ENODEV; |
| 297 | } | 560 | } |
| 298 | 561 | ||
| 299 | mc13783->revision = ((rev1 * 10) + rev2); | 562 | dev_info(&mc13783->spidev->dev, |
| 300 | dev_info(mc13783->dev, "MC13783 Rev %d.%d FinVer %x detected\n", rev1, | 563 | "MC13783 Rev %d.%d FinVer %x detected\n", |
| 301 | rev2, finid); | 564 | rev1, rev2, finid); |
| 302 | 565 | ||
| 303 | return 0; | 566 | return 0; |
| 304 | } | 567 | } |
| 305 | 568 | ||
| 306 | /* | 569 | static int mc13783_probe(struct spi_device *spi) |
| 307 | * Register a client device. This is non-fatal since there is no need to | ||
| 308 | * fail the entire device init due to a single platform device failing. | ||
| 309 | */ | ||
| 310 | static void mc13783_client_dev_register(struct mc13783 *mc13783, | ||
| 311 | const char *name) | ||
| 312 | { | ||
| 313 | struct mfd_cell cell = {}; | ||
| 314 | |||
| 315 | cell.name = name; | ||
| 316 | |||
| 317 | mfd_add_devices(mc13783->dev, -1, &cell, 1, NULL, 0); | ||
| 318 | } | ||
| 319 | |||
| 320 | static int __devinit mc13783_probe(struct spi_device *spi) | ||
| 321 | { | 570 | { |
| 322 | struct mc13783 *mc13783; | 571 | struct mc13783 *mc13783; |
| 323 | struct mc13783_platform_data *pdata = spi->dev.platform_data; | 572 | struct mc13783_platform_data *pdata = dev_get_platdata(&spi->dev); |
| 324 | int ret; | 573 | int ret; |
| 325 | 574 | ||
| 326 | mc13783 = kzalloc(sizeof(struct mc13783), GFP_KERNEL); | 575 | mc13783 = kzalloc(sizeof(*mc13783), GFP_KERNEL); |
| 327 | if (!mc13783) | 576 | if (!mc13783) |
| 328 | return -ENOMEM; | 577 | return -ENOMEM; |
| 329 | 578 | ||
| @@ -332,96 +581,104 @@ static int __devinit mc13783_probe(struct spi_device *spi) | |||
| 332 | spi->bits_per_word = 32; | 581 | spi->bits_per_word = 32; |
| 333 | spi_setup(spi); | 582 | spi_setup(spi); |
| 334 | 583 | ||
| 335 | mc13783->spi_device = spi; | 584 | mc13783->spidev = spi; |
| 336 | mc13783->dev = &spi->dev; | 585 | |
| 337 | mc13783->irq = spi->irq; | 586 | mutex_init(&mc13783->lock); |
| 587 | mc13783_lock(mc13783); | ||
| 588 | |||
| 589 | ret = mc13783_check_revision(mc13783); | ||
| 590 | if (ret) | ||
| 591 | goto err_revision; | ||
| 592 | |||
| 593 | /* mask all irqs */ | ||
| 594 | ret = mc13783_reg_write(mc13783, MC13783_IRQMASK0, 0x00ffffff); | ||
| 595 | if (ret) | ||
| 596 | goto err_mask; | ||
| 338 | 597 | ||
| 339 | INIT_WORK(&mc13783->work, mc13783_irq_work); | 598 | ret = mc13783_reg_write(mc13783, MC13783_IRQMASK1, 0x00ffffff); |
| 340 | mutex_init(&mc13783->io_lock); | 599 | if (ret) |
| 341 | mutex_init(&mc13783->adc_conv_lock); | 600 | goto err_mask; |
| 342 | init_completion(&mc13783->adc_done); | 601 | |
| 602 | ret = request_threaded_irq(spi->irq, NULL, mc13783_irq_thread, | ||
| 603 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13783", mc13783); | ||
| 604 | |||
| 605 | if (ret) { | ||
| 606 | err_mask: | ||
| 607 | err_revision: | ||
| 608 | mutex_unlock(&mc13783->lock); | ||
| 609 | dev_set_drvdata(&spi->dev, NULL); | ||
| 610 | kfree(mc13783); | ||
| 611 | return ret; | ||
| 612 | } | ||
| 343 | 613 | ||
| 614 | /* This should go away (BEGIN) */ | ||
| 344 | if (pdata) { | 615 | if (pdata) { |
| 345 | mc13783->flags = pdata->flags; | 616 | mc13783->flags = pdata->flags; |
| 346 | mc13783->regulators = pdata->regulators; | 617 | mc13783->regulators = pdata->regulators; |
| 347 | mc13783->num_regulators = pdata->num_regulators; | 618 | mc13783->num_regulators = pdata->num_regulators; |
| 348 | } | 619 | } |
| 620 | /* This should go away (END) */ | ||
| 349 | 621 | ||
| 350 | if (mc13783_check_revision(mc13783)) { | 622 | if (pdata->flags & MC13783_USE_ADC) |
| 351 | ret = -ENODEV; | 623 | mc13783_add_subdevice(mc13783, "mc13783-adc"); |
| 352 | goto err_out; | 624 | |
| 625 | if (pdata->flags & MC13783_USE_CODEC) | ||
| 626 | mc13783_add_subdevice(mc13783, "mc13783-codec"); | ||
| 627 | |||
| 628 | if (pdata->flags & MC13783_USE_REGULATOR) { | ||
| 629 | struct mc13783_regulator_platform_data regulator_pdata = { | ||
| 630 | .num_regulators = pdata->num_regulators, | ||
| 631 | .regulators = pdata->regulators, | ||
| 632 | }; | ||
| 633 | |||
| 634 | mc13783_add_subdevice_pdata(mc13783, "mc13783-regulator", | ||
| 635 | ®ulator_pdata, sizeof(regulator_pdata)); | ||
| 353 | } | 636 | } |
| 354 | 637 | ||
| 355 | /* clear and mask all interrupts */ | 638 | if (pdata->flags & MC13783_USE_RTC) |
| 356 | mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_STATUS_0, 0x00ffffff); | 639 | mc13783_add_subdevice(mc13783, "mc13783-rtc"); |
| 357 | mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_MASK_0, 0x00ffffff); | ||
| 358 | mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_STATUS_1, 0x00ffffff); | ||
| 359 | mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_MASK_1, 0x00ffffff); | ||
| 360 | 640 | ||
| 361 | /* unmask adcdone interrupts */ | 641 | if (pdata->flags & MC13783_USE_TOUCHSCREEN) |
| 362 | mc13783_set_bits(mc13783, MC13783_REG_INTERRUPT_MASK_0, | 642 | mc13783_add_subdevice(mc13783, "mc13783-ts"); |
| 363 | MC13783_INT_MASK_ADCDONEM, 0); | ||
| 364 | 643 | ||
| 365 | ret = request_irq(mc13783->irq, mc13783_interrupt, | 644 | mc13783_unlock(mc13783); |
| 366 | IRQF_DISABLED | IRQF_TRIGGER_HIGH, "mc13783", | ||
| 367 | mc13783); | ||
| 368 | if (ret) | ||
| 369 | goto err_out; | ||
| 370 | |||
| 371 | if (mc13783->flags & MC13783_USE_CODEC) | ||
| 372 | mc13783_client_dev_register(mc13783, "mc13783-codec"); | ||
| 373 | if (mc13783->flags & MC13783_USE_ADC) | ||
| 374 | mc13783_client_dev_register(mc13783, "mc13783-adc"); | ||
| 375 | if (mc13783->flags & MC13783_USE_RTC) | ||
| 376 | mc13783_client_dev_register(mc13783, "mc13783-rtc"); | ||
| 377 | if (mc13783->flags & MC13783_USE_REGULATOR) | ||
| 378 | mc13783_client_dev_register(mc13783, "mc13783-regulator"); | ||
| 379 | if (mc13783->flags & MC13783_USE_TOUCHSCREEN) | ||
| 380 | mc13783_client_dev_register(mc13783, "mc13783-ts"); | ||
| 381 | 645 | ||
| 382 | return 0; | 646 | return 0; |
| 383 | |||
| 384 | err_out: | ||
| 385 | kfree(mc13783); | ||
| 386 | return ret; | ||
| 387 | } | 647 | } |
| 388 | 648 | ||
| 389 | static int __devexit mc13783_remove(struct spi_device *spi) | 649 | static int __devexit mc13783_remove(struct spi_device *spi) |
| 390 | { | 650 | { |
| 391 | struct mc13783 *mc13783; | 651 | struct mc13783 *mc13783 = dev_get_drvdata(&spi->dev); |
| 392 | 652 | ||
| 393 | mc13783 = dev_get_drvdata(&spi->dev); | 653 | free_irq(mc13783->spidev->irq, mc13783); |
| 394 | |||
| 395 | free_irq(mc13783->irq, mc13783); | ||
| 396 | 654 | ||
| 397 | mfd_remove_devices(&spi->dev); | 655 | mfd_remove_devices(&spi->dev); |
| 398 | 656 | ||
| 399 | return 0; | 657 | return 0; |
| 400 | } | 658 | } |
| 401 | 659 | ||
| 402 | static struct spi_driver pmic_driver = { | 660 | static struct spi_driver mc13783_driver = { |
| 403 | .driver = { | 661 | .driver = { |
| 404 | .name = "mc13783", | 662 | .name = "mc13783", |
| 405 | .bus = &spi_bus_type, | 663 | .bus = &spi_bus_type, |
| 406 | .owner = THIS_MODULE, | 664 | .owner = THIS_MODULE, |
| 407 | }, | 665 | }, |
| 408 | .probe = mc13783_probe, | 666 | .probe = mc13783_probe, |
| 409 | .remove = __devexit_p(mc13783_remove), | 667 | .remove = __devexit_p(mc13783_remove), |
| 410 | }; | 668 | }; |
| 411 | 669 | ||
| 412 | static int __init pmic_init(void) | 670 | static int __init mc13783_init(void) |
| 413 | { | 671 | { |
| 414 | return spi_register_driver(&pmic_driver); | 672 | return spi_register_driver(&mc13783_driver); |
| 415 | } | 673 | } |
| 416 | subsys_initcall(pmic_init); | 674 | subsys_initcall(mc13783_init); |
| 417 | 675 | ||
| 418 | static void __exit pmic_exit(void) | 676 | static void __exit mc13783_exit(void) |
| 419 | { | 677 | { |
| 420 | spi_unregister_driver(&pmic_driver); | 678 | spi_unregister_driver(&mc13783_driver); |
| 421 | } | 679 | } |
| 422 | module_exit(pmic_exit); | 680 | module_exit(mc13783_exit); |
| 423 | |||
| 424 | MODULE_DESCRIPTION("Core/Protocol driver for Freescale MC13783 PMIC"); | ||
| 425 | MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); | ||
| 426 | MODULE_LICENSE("GPL"); | ||
| 427 | 681 | ||
| 682 | MODULE_DESCRIPTION("Core driver for Freescale MC13783 PMIC"); | ||
| 683 | MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); | ||
| 684 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c index 3d31e97d6a45..6d2e8466df1d 100644 --- a/drivers/mfd/pcf50633-adc.c +++ b/drivers/mfd/pcf50633-adc.c | |||
| @@ -209,17 +209,16 @@ static void pcf50633_adc_irq(int irq, void *data) | |||
| 209 | 209 | ||
| 210 | static int __devinit pcf50633_adc_probe(struct platform_device *pdev) | 210 | static int __devinit pcf50633_adc_probe(struct platform_device *pdev) |
| 211 | { | 211 | { |
| 212 | struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data; | ||
| 213 | struct pcf50633_adc *adc; | 212 | struct pcf50633_adc *adc; |
| 214 | 213 | ||
| 215 | adc = kzalloc(sizeof(*adc), GFP_KERNEL); | 214 | adc = kzalloc(sizeof(*adc), GFP_KERNEL); |
| 216 | if (!adc) | 215 | if (!adc) |
| 217 | return -ENOMEM; | 216 | return -ENOMEM; |
| 218 | 217 | ||
| 219 | adc->pcf = pdata->pcf; | 218 | adc->pcf = dev_to_pcf50633(pdev->dev.parent); |
| 220 | platform_set_drvdata(pdev, adc); | 219 | platform_set_drvdata(pdev, adc); |
| 221 | 220 | ||
| 222 | pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ADCRDY, | 221 | pcf50633_register_irq(adc->pcf, PCF50633_IRQ_ADCRDY, |
| 223 | pcf50633_adc_irq, adc); | 222 | pcf50633_adc_irq, adc); |
| 224 | 223 | ||
| 225 | mutex_init(&adc->queue_mutex); | 224 | mutex_init(&adc->queue_mutex); |
diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index d26d7747175e..03dcc9200707 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c | |||
| @@ -290,7 +290,7 @@ out: | |||
| 290 | 290 | ||
| 291 | int pcf50633_irq_mask(struct pcf50633 *pcf, int irq) | 291 | int pcf50633_irq_mask(struct pcf50633 *pcf, int irq) |
| 292 | { | 292 | { |
| 293 | dev_info(pcf->dev, "Masking IRQ %d\n", irq); | 293 | dev_dbg(pcf->dev, "Masking IRQ %d\n", irq); |
| 294 | 294 | ||
| 295 | return __pcf50633_irq_mask_set(pcf, irq, 1); | 295 | return __pcf50633_irq_mask_set(pcf, irq, 1); |
| 296 | } | 296 | } |
| @@ -298,7 +298,7 @@ EXPORT_SYMBOL_GPL(pcf50633_irq_mask); | |||
| 298 | 298 | ||
| 299 | int pcf50633_irq_unmask(struct pcf50633 *pcf, int irq) | 299 | int pcf50633_irq_unmask(struct pcf50633 *pcf, int irq) |
| 300 | { | 300 | { |
| 301 | dev_info(pcf->dev, "Unmasking IRQ %d\n", irq); | 301 | dev_dbg(pcf->dev, "Unmasking IRQ %d\n", irq); |
| 302 | 302 | ||
| 303 | return __pcf50633_irq_mask_set(pcf, irq, 0); | 303 | return __pcf50633_irq_mask_set(pcf, irq, 0); |
| 304 | } | 304 | } |
| @@ -345,6 +345,9 @@ static void pcf50633_irq_worker(struct work_struct *work) | |||
| 345 | goto out; | 345 | goto out; |
| 346 | } | 346 | } |
| 347 | 347 | ||
| 348 | /* defeat 8s death from lowsys on A5 */ | ||
| 349 | pcf50633_reg_write(pcf, PCF50633_REG_OOCSHDWN, 0x04); | ||
| 350 | |||
| 348 | /* We immediately read the usb and adapter status. We thus make sure | 351 | /* We immediately read the usb and adapter status. We thus make sure |
| 349 | * only of USBINS/USBREM IRQ handlers are called */ | 352 | * only of USBINS/USBREM IRQ handlers are called */ |
| 350 | if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) { | 353 | if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) { |
| @@ -453,7 +456,6 @@ static void | |||
| 453 | pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name, | 456 | pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name, |
| 454 | struct platform_device **pdev) | 457 | struct platform_device **pdev) |
| 455 | { | 458 | { |
| 456 | struct pcf50633_subdev_pdata *subdev_pdata; | ||
| 457 | int ret; | 459 | int ret; |
| 458 | 460 | ||
| 459 | *pdev = platform_device_alloc(name, -1); | 461 | *pdev = platform_device_alloc(name, -1); |
| @@ -462,15 +464,6 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name, | |||
| 462 | return; | 464 | return; |
| 463 | } | 465 | } |
| 464 | 466 | ||
| 465 | subdev_pdata = kmalloc(sizeof(*subdev_pdata), GFP_KERNEL); | ||
| 466 | if (!subdev_pdata) { | ||
| 467 | dev_err(pcf->dev, "Error allocating subdev pdata\n"); | ||
| 468 | platform_device_put(*pdev); | ||
| 469 | } | ||
| 470 | |||
| 471 | subdev_pdata->pcf = pcf; | ||
| 472 | platform_device_add_data(*pdev, subdev_pdata, sizeof(*subdev_pdata)); | ||
| 473 | |||
| 474 | (*pdev)->dev.parent = pcf->dev; | 467 | (*pdev)->dev.parent = pcf->dev; |
| 475 | 468 | ||
| 476 | ret = platform_device_add(*pdev); | 469 | ret = platform_device_add(*pdev); |
| @@ -482,13 +475,13 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name, | |||
| 482 | } | 475 | } |
| 483 | 476 | ||
| 484 | #ifdef CONFIG_PM | 477 | #ifdef CONFIG_PM |
| 485 | static int pcf50633_suspend(struct device *dev, pm_message_t state) | 478 | static int pcf50633_suspend(struct i2c_client *client, pm_message_t state) |
| 486 | { | 479 | { |
| 487 | struct pcf50633 *pcf; | 480 | struct pcf50633 *pcf; |
| 488 | int ret = 0, i; | 481 | int ret = 0, i; |
| 489 | u8 res[5]; | 482 | u8 res[5]; |
| 490 | 483 | ||
| 491 | pcf = dev_get_drvdata(dev); | 484 | pcf = i2c_get_clientdata(client); |
| 492 | 485 | ||
| 493 | /* Make sure our interrupt handlers are not called | 486 | /* Make sure our interrupt handlers are not called |
| 494 | * henceforth */ | 487 | * henceforth */ |
| @@ -523,12 +516,12 @@ out: | |||
| 523 | return ret; | 516 | return ret; |
| 524 | } | 517 | } |
| 525 | 518 | ||
| 526 | static int pcf50633_resume(struct device *dev) | 519 | static int pcf50633_resume(struct i2c_client *client) |
| 527 | { | 520 | { |
| 528 | struct pcf50633 *pcf; | 521 | struct pcf50633 *pcf; |
| 529 | int ret; | 522 | int ret; |
| 530 | 523 | ||
| 531 | pcf = dev_get_drvdata(dev); | 524 | pcf = i2c_get_clientdata(client); |
| 532 | 525 | ||
| 533 | /* Write the saved mask registers */ | 526 | /* Write the saved mask registers */ |
| 534 | ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M, | 527 | ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M, |
| @@ -560,9 +553,14 @@ static int __devinit pcf50633_probe(struct i2c_client *client, | |||
| 560 | { | 553 | { |
| 561 | struct pcf50633 *pcf; | 554 | struct pcf50633 *pcf; |
| 562 | struct pcf50633_platform_data *pdata = client->dev.platform_data; | 555 | struct pcf50633_platform_data *pdata = client->dev.platform_data; |
| 563 | int i, ret = 0; | 556 | int i, ret; |
| 564 | int version, variant; | 557 | int version, variant; |
| 565 | 558 | ||
| 559 | if (!client->irq) { | ||
| 560 | dev_err(&client->dev, "Missing IRQ\n"); | ||
| 561 | return -ENOENT; | ||
| 562 | } | ||
| 563 | |||
| 566 | pcf = kzalloc(sizeof(*pcf), GFP_KERNEL); | 564 | pcf = kzalloc(sizeof(*pcf), GFP_KERNEL); |
| 567 | if (!pcf) | 565 | if (!pcf) |
| 568 | return -ENOMEM; | 566 | return -ENOMEM; |
| @@ -577,6 +575,12 @@ static int __devinit pcf50633_probe(struct i2c_client *client, | |||
| 577 | pcf->irq = client->irq; | 575 | pcf->irq = client->irq; |
| 578 | pcf->work_queue = create_singlethread_workqueue("pcf50633"); | 576 | pcf->work_queue = create_singlethread_workqueue("pcf50633"); |
| 579 | 577 | ||
| 578 | if (!pcf->work_queue) { | ||
| 579 | dev_err(&client->dev, "Failed to alloc workqueue\n"); | ||
| 580 | ret = -ENOMEM; | ||
| 581 | goto err_free; | ||
| 582 | } | ||
| 583 | |||
| 580 | INIT_WORK(&pcf->irq_work, pcf50633_irq_worker); | 584 | INIT_WORK(&pcf->irq_work, pcf50633_irq_worker); |
| 581 | 585 | ||
| 582 | version = pcf50633_reg_read(pcf, 0); | 586 | version = pcf50633_reg_read(pcf, 0); |
| @@ -584,7 +588,7 @@ static int __devinit pcf50633_probe(struct i2c_client *client, | |||
| 584 | if (version < 0 || variant < 0) { | 588 | if (version < 0 || variant < 0) { |
| 585 | dev_err(pcf->dev, "Unable to probe pcf50633\n"); | 589 | dev_err(pcf->dev, "Unable to probe pcf50633\n"); |
| 586 | ret = -ENODEV; | 590 | ret = -ENODEV; |
| 587 | goto err; | 591 | goto err_destroy_workqueue; |
| 588 | } | 592 | } |
| 589 | 593 | ||
| 590 | dev_info(pcf->dev, "Probed device version %d variant %d\n", | 594 | dev_info(pcf->dev, "Probed device version %d variant %d\n", |
| @@ -598,6 +602,14 @@ static int __devinit pcf50633_probe(struct i2c_client *client, | |||
| 598 | pcf50633_reg_write(pcf, PCF50633_REG_INT4M, 0x00); | 602 | pcf50633_reg_write(pcf, PCF50633_REG_INT4M, 0x00); |
| 599 | pcf50633_reg_write(pcf, PCF50633_REG_INT5M, 0x00); | 603 | pcf50633_reg_write(pcf, PCF50633_REG_INT5M, 0x00); |
| 600 | 604 | ||
| 605 | ret = request_irq(client->irq, pcf50633_irq, | ||
| 606 | IRQF_TRIGGER_LOW, "pcf50633", pcf); | ||
| 607 | |||
| 608 | if (ret) { | ||
| 609 | dev_err(pcf->dev, "Failed to request IRQ %d\n", ret); | ||
| 610 | goto err_destroy_workqueue; | ||
| 611 | } | ||
| 612 | |||
| 601 | /* Create sub devices */ | 613 | /* Create sub devices */ |
| 602 | pcf50633_client_dev_register(pcf, "pcf50633-input", | 614 | pcf50633_client_dev_register(pcf, "pcf50633-input", |
| 603 | &pcf->input_pdev); | 615 | &pcf->input_pdev); |
| @@ -613,31 +625,18 @@ static int __devinit pcf50633_probe(struct i2c_client *client, | |||
| 613 | 625 | ||
| 614 | pdev = platform_device_alloc("pcf50633-regltr", i); | 626 | pdev = platform_device_alloc("pcf50633-regltr", i); |
| 615 | if (!pdev) { | 627 | if (!pdev) { |
| 616 | dev_err(pcf->dev, "Cannot create regulator\n"); | 628 | dev_err(pcf->dev, "Cannot create regulator %d\n", i); |
| 617 | continue; | 629 | continue; |
| 618 | } | 630 | } |
| 619 | 631 | ||
| 620 | pdev->dev.parent = pcf->dev; | 632 | pdev->dev.parent = pcf->dev; |
| 621 | pdev->dev.platform_data = &pdata->reg_init_data[i]; | 633 | platform_device_add_data(pdev, &pdata->reg_init_data[i], |
| 622 | dev_set_drvdata(&pdev->dev, pcf); | 634 | sizeof(pdata->reg_init_data[i])); |
| 623 | pcf->regulator_pdev[i] = pdev; | 635 | pcf->regulator_pdev[i] = pdev; |
| 624 | 636 | ||
| 625 | platform_device_add(pdev); | 637 | platform_device_add(pdev); |
| 626 | } | 638 | } |
| 627 | 639 | ||
| 628 | if (client->irq) { | ||
| 629 | ret = request_irq(client->irq, pcf50633_irq, | ||
| 630 | IRQF_TRIGGER_LOW, "pcf50633", pcf); | ||
| 631 | |||
| 632 | if (ret) { | ||
| 633 | dev_err(pcf->dev, "Failed to request IRQ %d\n", ret); | ||
| 634 | goto err; | ||
| 635 | } | ||
| 636 | } else { | ||
| 637 | dev_err(pcf->dev, "No IRQ configured\n"); | ||
| 638 | goto err; | ||
| 639 | } | ||
| 640 | |||
| 641 | if (enable_irq_wake(client->irq) < 0) | 640 | if (enable_irq_wake(client->irq) < 0) |
| 642 | dev_err(pcf->dev, "IRQ %u cannot be enabled as wake-up source" | 641 | dev_err(pcf->dev, "IRQ %u cannot be enabled as wake-up source" |
| 643 | "in this hardware revision", client->irq); | 642 | "in this hardware revision", client->irq); |
| @@ -651,9 +650,12 @@ static int __devinit pcf50633_probe(struct i2c_client *client, | |||
| 651 | 650 | ||
| 652 | return 0; | 651 | return 0; |
| 653 | 652 | ||
| 654 | err: | 653 | err_destroy_workqueue: |
| 655 | destroy_workqueue(pcf->work_queue); | 654 | destroy_workqueue(pcf->work_queue); |
| 655 | err_free: | ||
| 656 | i2c_set_clientdata(client, NULL); | ||
| 656 | kfree(pcf); | 657 | kfree(pcf); |
| 658 | |||
| 657 | return ret; | 659 | return ret; |
| 658 | } | 660 | } |
| 659 | 661 | ||
| @@ -686,12 +688,12 @@ static struct i2c_device_id pcf50633_id_table[] = { | |||
| 686 | static struct i2c_driver pcf50633_driver = { | 688 | static struct i2c_driver pcf50633_driver = { |
| 687 | .driver = { | 689 | .driver = { |
| 688 | .name = "pcf50633", | 690 | .name = "pcf50633", |
| 689 | .suspend = pcf50633_suspend, | ||
| 690 | .resume = pcf50633_resume, | ||
| 691 | }, | 691 | }, |
| 692 | .id_table = pcf50633_id_table, | 692 | .id_table = pcf50633_id_table, |
| 693 | .probe = pcf50633_probe, | 693 | .probe = pcf50633_probe, |
| 694 | .remove = __devexit_p(pcf50633_remove), | 694 | .remove = __devexit_p(pcf50633_remove), |
| 695 | .suspend = pcf50633_suspend, | ||
| 696 | .resume = pcf50633_resume, | ||
| 695 | }; | 697 | }; |
| 696 | 698 | ||
| 697 | static int __init pcf50633_init(void) | 699 | static int __init pcf50633_init(void) |
diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index acf8b9d5f575..e5955306c2fa 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c | |||
| @@ -637,7 +637,7 @@ static int tps65010_probe(struct i2c_client *client, | |||
| 637 | tps, DEBUG_FOPS); | 637 | tps, DEBUG_FOPS); |
| 638 | 638 | ||
| 639 | /* optionally register GPIOs */ | 639 | /* optionally register GPIOs */ |
| 640 | if (board && board->base > 0) { | 640 | if (board && board->base != 0) { |
| 641 | tps->outmask = board->outmask; | 641 | tps->outmask = board->outmask; |
| 642 | 642 | ||
| 643 | tps->chip.label = client->name; | 643 | tps->chip.label = client->name; |
| @@ -964,6 +964,34 @@ int tps65010_config_vregs1(unsigned value) | |||
| 964 | } | 964 | } |
| 965 | EXPORT_SYMBOL(tps65010_config_vregs1); | 965 | EXPORT_SYMBOL(tps65010_config_vregs1); |
| 966 | 966 | ||
| 967 | int tps65010_config_vdcdc2(unsigned value) | ||
| 968 | { | ||
| 969 | struct i2c_client *c; | ||
| 970 | int status; | ||
| 971 | |||
| 972 | if (!the_tps) | ||
| 973 | return -ENODEV; | ||
| 974 | |||
| 975 | c = the_tps->client; | ||
| 976 | mutex_lock(&the_tps->lock); | ||
| 977 | |||
| 978 | pr_debug("%s: vdcdc2 0x%02x\n", DRIVER_NAME, | ||
| 979 | i2c_smbus_read_byte_data(c, TPS_VDCDC2)); | ||
| 980 | |||
| 981 | status = i2c_smbus_write_byte_data(c, TPS_VDCDC2, value); | ||
| 982 | |||
| 983 | if (status != 0) | ||
| 984 | printk(KERN_ERR "%s: Failed to write vdcdc2 register\n", | ||
| 985 | DRIVER_NAME); | ||
| 986 | else | ||
| 987 | pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, | ||
| 988 | i2c_smbus_read_byte_data(c, TPS_VDCDC2)); | ||
| 989 | |||
| 990 | mutex_unlock(&the_tps->lock); | ||
| 991 | return status; | ||
| 992 | } | ||
| 993 | EXPORT_SYMBOL(tps65010_config_vdcdc2); | ||
| 994 | |||
| 967 | /*-------------------------------------------------------------------------*/ | 995 | /*-------------------------------------------------------------------------*/ |
| 968 | /* tps65013_set_low_pwr parameter: | 996 | /* tps65013_set_low_pwr parameter: |
| 969 | * mode: ON or OFF | 997 | * mode: ON or OFF |
diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl-core.c index 40449cdf09db..2a7606534196 100644 --- a/drivers/mfd/twl4030-core.c +++ b/drivers/mfd/twl-core.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * twl4030_core.c - driver for TWL4030/TPS659x0 PM and audio CODEC devices | 2 | * twl_core.c - driver for TWL4030/TWL5030/TWL60X0/TPS659x0 PM |
| 3 | * and audio CODEC devices | ||
| 3 | * | 4 | * |
| 4 | * Copyright (C) 2005-2006 Texas Instruments, Inc. | 5 | * Copyright (C) 2005-2006 Texas Instruments, Inc. |
| 5 | * | 6 | * |
| @@ -36,7 +37,7 @@ | |||
| 36 | #include <linux/regulator/machine.h> | 37 | #include <linux/regulator/machine.h> |
| 37 | 38 | ||
| 38 | #include <linux/i2c.h> | 39 | #include <linux/i2c.h> |
| 39 | #include <linux/i2c/twl4030.h> | 40 | #include <linux/i2c/twl.h> |
| 40 | 41 | ||
| 41 | #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) | 42 | #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) |
| 42 | #include <plat/cpu.h> | 43 | #include <plat/cpu.h> |
| @@ -55,7 +56,7 @@ | |||
| 55 | * (and associated registers). | 56 | * (and associated registers). |
| 56 | */ | 57 | */ |
| 57 | 58 | ||
| 58 | #define DRIVER_NAME "twl4030" | 59 | #define DRIVER_NAME "twl" |
| 59 | 60 | ||
| 60 | #if defined(CONFIG_TWL4030_BCI_BATTERY) || \ | 61 | #if defined(CONFIG_TWL4030_BCI_BATTERY) || \ |
| 61 | defined(CONFIG_TWL4030_BCI_BATTERY_MODULE) | 62 | defined(CONFIG_TWL4030_BCI_BATTERY_MODULE) |
| @@ -125,7 +126,7 @@ | |||
| 125 | /* Last - for index max*/ | 126 | /* Last - for index max*/ |
| 126 | #define TWL4030_MODULE_LAST TWL4030_MODULE_SECURED_REG | 127 | #define TWL4030_MODULE_LAST TWL4030_MODULE_SECURED_REG |
| 127 | 128 | ||
| 128 | #define TWL4030_NUM_SLAVES 4 | 129 | #define TWL_NUM_SLAVES 4 |
| 129 | 130 | ||
| 130 | #if defined(CONFIG_INPUT_TWL4030_PWRBUTTON) \ | 131 | #if defined(CONFIG_INPUT_TWL4030_PWRBUTTON) \ |
| 131 | || defined(CONFIG_INPUT_TWL4030_PWBUTTON_MODULE) | 132 | || defined(CONFIG_INPUT_TWL4030_PWBUTTON_MODULE) |
| @@ -134,6 +135,13 @@ | |||
| 134 | #define twl_has_pwrbutton() false | 135 | #define twl_has_pwrbutton() false |
| 135 | #endif | 136 | #endif |
| 136 | 137 | ||
| 138 | #define SUB_CHIP_ID0 0 | ||
| 139 | #define SUB_CHIP_ID1 1 | ||
| 140 | #define SUB_CHIP_ID2 2 | ||
| 141 | #define SUB_CHIP_ID3 3 | ||
| 142 | |||
| 143 | #define TWL_MODULE_LAST TWL4030_MODULE_LAST | ||
| 144 | |||
| 137 | /* Base Address defns for twl4030_map[] */ | 145 | /* Base Address defns for twl4030_map[] */ |
| 138 | 146 | ||
| 139 | /* subchip/slave 0 - USB ID */ | 147 | /* subchip/slave 0 - USB ID */ |
| @@ -158,6 +166,10 @@ | |||
| 158 | #define TWL4030_BASEADD_PWMB 0x00F1 | 166 | #define TWL4030_BASEADD_PWMB 0x00F1 |
| 159 | #define TWL4030_BASEADD_KEYPAD 0x00D2 | 167 | #define TWL4030_BASEADD_KEYPAD 0x00D2 |
| 160 | 168 | ||
| 169 | #define TWL5031_BASEADD_ACCESSORY 0x0074 /* Replaces Main Charge */ | ||
| 170 | #define TWL5031_BASEADD_INTERRUPTS 0x00B9 /* Different than TWL4030's | ||
| 171 | one */ | ||
| 172 | |||
| 161 | /* subchip/slave 3 - POWER ID */ | 173 | /* subchip/slave 3 - POWER ID */ |
| 162 | #define TWL4030_BASEADD_BACKUP 0x0014 | 174 | #define TWL4030_BASEADD_BACKUP 0x0014 |
| 163 | #define TWL4030_BASEADD_INT 0x002E | 175 | #define TWL4030_BASEADD_INT 0x002E |
| @@ -169,6 +181,30 @@ | |||
| 169 | /* Triton Core internal information (END) */ | 181 | /* Triton Core internal information (END) */ |
| 170 | 182 | ||
| 171 | 183 | ||
| 184 | /* subchip/slave 0 0x48 - POWER */ | ||
| 185 | #define TWL6030_BASEADD_RTC 0x0000 | ||
| 186 | #define TWL6030_BASEADD_MEM 0x0017 | ||
| 187 | #define TWL6030_BASEADD_PM_MASTER 0x001F | ||
| 188 | #define TWL6030_BASEADD_PM_SLAVE_MISC 0x0030 /* PM_RECEIVER */ | ||
| 189 | #define TWL6030_BASEADD_PM_MISC 0x00E2 | ||
| 190 | #define TWL6030_BASEADD_PM_PUPD 0x00F0 | ||
| 191 | |||
| 192 | /* subchip/slave 1 0x49 - FEATURE */ | ||
| 193 | #define TWL6030_BASEADD_USB 0x0000 | ||
| 194 | #define TWL6030_BASEADD_GPADC_CTRL 0x002E | ||
| 195 | #define TWL6030_BASEADD_AUX 0x0090 | ||
| 196 | #define TWL6030_BASEADD_PWM 0x00BA | ||
| 197 | #define TWL6030_BASEADD_GASGAUGE 0x00C0 | ||
| 198 | #define TWL6030_BASEADD_PIH 0x00D0 | ||
| 199 | #define TWL6030_BASEADD_CHARGER 0x00E0 | ||
| 200 | |||
| 201 | /* subchip/slave 2 0x4A - DFT */ | ||
| 202 | #define TWL6030_BASEADD_DIEID 0x00C0 | ||
| 203 | |||
| 204 | /* subchip/slave 3 0x4B - AUDIO */ | ||
| 205 | #define TWL6030_BASEADD_AUDIO 0x0000 | ||
| 206 | #define TWL6030_BASEADD_RSV 0x0000 | ||
| 207 | |||
| 172 | /* Few power values */ | 208 | /* Few power values */ |
| 173 | #define R_CFG_BOOT 0x05 | 209 | #define R_CFG_BOOT 0x05 |
| 174 | #define R_PROTECT_KEY 0x0E | 210 | #define R_PROTECT_KEY 0x0E |
| @@ -183,19 +219,29 @@ | |||
| 183 | #define HFCLK_FREQ_26_MHZ (2 << 0) | 219 | #define HFCLK_FREQ_26_MHZ (2 << 0) |
| 184 | #define HFCLK_FREQ_38p4_MHZ (3 << 0) | 220 | #define HFCLK_FREQ_38p4_MHZ (3 << 0) |
| 185 | #define HIGH_PERF_SQ (1 << 3) | 221 | #define HIGH_PERF_SQ (1 << 3) |
| 222 | #define CK32K_LOWPWR_EN (1 << 7) | ||
| 186 | 223 | ||
| 187 | 224 | ||
| 188 | /* chip-specific feature flags, for i2c_device_id.driver_data */ | 225 | /* chip-specific feature flags, for i2c_device_id.driver_data */ |
| 189 | #define TWL4030_VAUX2 BIT(0) /* pre-5030 voltage ranges */ | 226 | #define TWL4030_VAUX2 BIT(0) /* pre-5030 voltage ranges */ |
| 190 | #define TPS_SUBSET BIT(1) /* tps659[23]0 have fewer LDOs */ | 227 | #define TPS_SUBSET BIT(1) /* tps659[23]0 have fewer LDOs */ |
| 228 | #define TWL5031 BIT(2) /* twl5031 has different registers */ | ||
| 229 | #define TWL6030_CLASS BIT(3) /* TWL6030 class */ | ||
| 191 | 230 | ||
| 192 | /*----------------------------------------------------------------------*/ | 231 | /*----------------------------------------------------------------------*/ |
| 193 | 232 | ||
| 194 | /* is driver active, bound to a chip? */ | 233 | /* is driver active, bound to a chip? */ |
| 195 | static bool inuse; | 234 | static bool inuse; |
| 196 | 235 | ||
| 197 | /* Structure for each TWL4030 Slave */ | 236 | static unsigned int twl_id; |
| 198 | struct twl4030_client { | 237 | unsigned int twl_rev(void) |
| 238 | { | ||
| 239 | return twl_id; | ||
| 240 | } | ||
| 241 | EXPORT_SYMBOL(twl_rev); | ||
| 242 | |||
| 243 | /* Structure for each TWL4030/TWL6030 Slave */ | ||
| 244 | struct twl_client { | ||
| 199 | struct i2c_client *client; | 245 | struct i2c_client *client; |
| 200 | u8 address; | 246 | u8 address; |
| 201 | 247 | ||
| @@ -206,19 +252,20 @@ struct twl4030_client { | |||
| 206 | struct mutex xfer_lock; | 252 | struct mutex xfer_lock; |
| 207 | }; | 253 | }; |
| 208 | 254 | ||
| 209 | static struct twl4030_client twl4030_modules[TWL4030_NUM_SLAVES]; | 255 | static struct twl_client twl_modules[TWL_NUM_SLAVES]; |
| 210 | 256 | ||
| 211 | 257 | ||
| 212 | /* mapping the module id to slave id and base address */ | 258 | /* mapping the module id to slave id and base address */ |
| 213 | struct twl4030mapping { | 259 | struct twl_mapping { |
| 214 | unsigned char sid; /* Slave ID */ | 260 | unsigned char sid; /* Slave ID */ |
| 215 | unsigned char base; /* base address */ | 261 | unsigned char base; /* base address */ |
| 216 | }; | 262 | }; |
| 263 | struct twl_mapping *twl_map; | ||
| 217 | 264 | ||
| 218 | static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { | 265 | static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { |
| 219 | /* | 266 | /* |
| 220 | * NOTE: don't change this table without updating the | 267 | * NOTE: don't change this table without updating the |
| 221 | * <linux/i2c/twl4030.h> defines for TWL4030_MODULE_* | 268 | * <linux/i2c/twl.h> defines for TWL4030_MODULE_* |
| 222 | * so they continue to match the order in this table. | 269 | * so they continue to match the order in this table. |
| 223 | */ | 270 | */ |
| 224 | 271 | ||
| @@ -240,6 +287,8 @@ static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { | |||
| 240 | { 2, TWL4030_BASEADD_PWM1 }, | 287 | { 2, TWL4030_BASEADD_PWM1 }, |
| 241 | { 2, TWL4030_BASEADD_PWMA }, | 288 | { 2, TWL4030_BASEADD_PWMA }, |
| 242 | { 2, TWL4030_BASEADD_PWMB }, | 289 | { 2, TWL4030_BASEADD_PWMB }, |
| 290 | { 2, TWL5031_BASEADD_ACCESSORY }, | ||
| 291 | { 2, TWL5031_BASEADD_INTERRUPTS }, | ||
| 243 | 292 | ||
| 244 | { 3, TWL4030_BASEADD_BACKUP }, | 293 | { 3, TWL4030_BASEADD_BACKUP }, |
| 245 | { 3, TWL4030_BASEADD_INT }, | 294 | { 3, TWL4030_BASEADD_INT }, |
| @@ -249,12 +298,46 @@ static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { | |||
| 249 | { 3, TWL4030_BASEADD_SECURED_REG }, | 298 | { 3, TWL4030_BASEADD_SECURED_REG }, |
| 250 | }; | 299 | }; |
| 251 | 300 | ||
| 301 | static struct twl_mapping twl6030_map[] = { | ||
| 302 | /* | ||
| 303 | * NOTE: don't change this table without updating the | ||
| 304 | * <linux/i2c/twl.h> defines for TWL4030_MODULE_* | ||
| 305 | * so they continue to match the order in this table. | ||
| 306 | */ | ||
| 307 | { SUB_CHIP_ID1, TWL6030_BASEADD_USB }, | ||
| 308 | { SUB_CHIP_ID3, TWL6030_BASEADD_AUDIO }, | ||
| 309 | { SUB_CHIP_ID2, TWL6030_BASEADD_DIEID }, | ||
| 310 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
| 311 | { SUB_CHIP_ID1, TWL6030_BASEADD_PIH }, | ||
| 312 | |||
| 313 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
| 314 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
| 315 | { SUB_CHIP_ID1, TWL6030_BASEADD_GPADC_CTRL }, | ||
| 316 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
| 317 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
| 318 | |||
| 319 | { SUB_CHIP_ID1, TWL6030_BASEADD_CHARGER }, | ||
| 320 | { SUB_CHIP_ID1, TWL6030_BASEADD_GASGAUGE }, | ||
| 321 | { SUB_CHIP_ID1, TWL6030_BASEADD_PWM }, | ||
| 322 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
| 323 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
| 324 | |||
| 325 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
| 326 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
| 327 | { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, | ||
| 328 | { SUB_CHIP_ID0, TWL6030_BASEADD_PM_MASTER }, | ||
| 329 | { SUB_CHIP_ID0, TWL6030_BASEADD_PM_SLAVE_MISC }, | ||
| 330 | |||
| 331 | { SUB_CHIP_ID0, TWL6030_BASEADD_RTC }, | ||
| 332 | { SUB_CHIP_ID0, TWL6030_BASEADD_MEM }, | ||
| 333 | }; | ||
| 334 | |||
| 252 | /*----------------------------------------------------------------------*/ | 335 | /*----------------------------------------------------------------------*/ |
| 253 | 336 | ||
| 254 | /* Exported Functions */ | 337 | /* Exported Functions */ |
| 255 | 338 | ||
| 256 | /** | 339 | /** |
| 257 | * twl4030_i2c_write - Writes a n bit register in TWL4030 | 340 | * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0 |
| 258 | * @mod_no: module number | 341 | * @mod_no: module number |
| 259 | * @value: an array of num_bytes+1 containing data to write | 342 | * @value: an array of num_bytes+1 containing data to write |
| 260 | * @reg: register address (just offset will do) | 343 | * @reg: register address (just offset will do) |
| @@ -265,19 +348,19 @@ static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { | |||
| 265 | * | 348 | * |
| 266 | * Returns the result of operation - 0 is success | 349 | * Returns the result of operation - 0 is success |
| 267 | */ | 350 | */ |
| 268 | int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | 351 | int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) |
| 269 | { | 352 | { |
| 270 | int ret; | 353 | int ret; |
| 271 | int sid; | 354 | int sid; |
| 272 | struct twl4030_client *twl; | 355 | struct twl_client *twl; |
| 273 | struct i2c_msg *msg; | 356 | struct i2c_msg *msg; |
| 274 | 357 | ||
| 275 | if (unlikely(mod_no > TWL4030_MODULE_LAST)) { | 358 | if (unlikely(mod_no > TWL_MODULE_LAST)) { |
| 276 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); | 359 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); |
| 277 | return -EPERM; | 360 | return -EPERM; |
| 278 | } | 361 | } |
| 279 | sid = twl4030_map[mod_no].sid; | 362 | sid = twl_map[mod_no].sid; |
| 280 | twl = &twl4030_modules[sid]; | 363 | twl = &twl_modules[sid]; |
| 281 | 364 | ||
| 282 | if (unlikely(!inuse)) { | 365 | if (unlikely(!inuse)) { |
| 283 | pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid); | 366 | pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid); |
| @@ -294,19 +377,26 @@ int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | |||
| 294 | msg->flags = 0; | 377 | msg->flags = 0; |
| 295 | msg->buf = value; | 378 | msg->buf = value; |
| 296 | /* over write the first byte of buffer with the register address */ | 379 | /* over write the first byte of buffer with the register address */ |
| 297 | *value = twl4030_map[mod_no].base + reg; | 380 | *value = twl_map[mod_no].base + reg; |
| 298 | ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 1); | 381 | ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 1); |
| 299 | mutex_unlock(&twl->xfer_lock); | 382 | mutex_unlock(&twl->xfer_lock); |
| 300 | 383 | ||
| 301 | /* i2cTransfer returns num messages.translate it pls.. */ | 384 | /* i2c_transfer returns number of messages transferred */ |
| 302 | if (ret >= 0) | 385 | if (ret != 1) { |
| 303 | ret = 0; | 386 | pr_err("%s: i2c_write failed to transfer all messages\n", |
| 304 | return ret; | 387 | DRIVER_NAME); |
| 388 | if (ret < 0) | ||
| 389 | return ret; | ||
| 390 | else | ||
| 391 | return -EIO; | ||
| 392 | } else { | ||
| 393 | return 0; | ||
| 394 | } | ||
| 305 | } | 395 | } |
| 306 | EXPORT_SYMBOL(twl4030_i2c_write); | 396 | EXPORT_SYMBOL(twl_i2c_write); |
| 307 | 397 | ||
| 308 | /** | 398 | /** |
| 309 | * twl4030_i2c_read - Reads a n bit register in TWL4030 | 399 | * twl_i2c_read - Reads a n bit register in TWL4030/TWL5030/TWL60X0 |
| 310 | * @mod_no: module number | 400 | * @mod_no: module number |
| 311 | * @value: an array of num_bytes containing data to be read | 401 | * @value: an array of num_bytes containing data to be read |
| 312 | * @reg: register address (just offset will do) | 402 | * @reg: register address (just offset will do) |
| @@ -314,20 +404,20 @@ EXPORT_SYMBOL(twl4030_i2c_write); | |||
| 314 | * | 404 | * |
| 315 | * Returns result of operation - num_bytes is success else failure. | 405 | * Returns result of operation - num_bytes is success else failure. |
| 316 | */ | 406 | */ |
| 317 | int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | 407 | int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) |
| 318 | { | 408 | { |
| 319 | int ret; | 409 | int ret; |
| 320 | u8 val; | 410 | u8 val; |
| 321 | int sid; | 411 | int sid; |
| 322 | struct twl4030_client *twl; | 412 | struct twl_client *twl; |
| 323 | struct i2c_msg *msg; | 413 | struct i2c_msg *msg; |
| 324 | 414 | ||
| 325 | if (unlikely(mod_no > TWL4030_MODULE_LAST)) { | 415 | if (unlikely(mod_no > TWL_MODULE_LAST)) { |
| 326 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); | 416 | pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); |
| 327 | return -EPERM; | 417 | return -EPERM; |
| 328 | } | 418 | } |
| 329 | sid = twl4030_map[mod_no].sid; | 419 | sid = twl_map[mod_no].sid; |
| 330 | twl = &twl4030_modules[sid]; | 420 | twl = &twl_modules[sid]; |
| 331 | 421 | ||
| 332 | if (unlikely(!inuse)) { | 422 | if (unlikely(!inuse)) { |
| 333 | pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid); | 423 | pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid); |
| @@ -339,7 +429,7 @@ int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | |||
| 339 | msg->addr = twl->address; | 429 | msg->addr = twl->address; |
| 340 | msg->len = 1; | 430 | msg->len = 1; |
| 341 | msg->flags = 0; /* Read the register value */ | 431 | msg->flags = 0; /* Read the register value */ |
| 342 | val = twl4030_map[mod_no].base + reg; | 432 | val = twl_map[mod_no].base + reg; |
| 343 | msg->buf = &val; | 433 | msg->buf = &val; |
| 344 | /* [MSG2] fill the data rx buffer */ | 434 | /* [MSG2] fill the data rx buffer */ |
| 345 | msg = &twl->xfer_msg[1]; | 435 | msg = &twl->xfer_msg[1]; |
| @@ -350,45 +440,52 @@ int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) | |||
| 350 | ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 2); | 440 | ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 2); |
| 351 | mutex_unlock(&twl->xfer_lock); | 441 | mutex_unlock(&twl->xfer_lock); |
| 352 | 442 | ||
| 353 | /* i2cTransfer returns num messages.translate it pls.. */ | 443 | /* i2c_transfer returns number of messages transferred */ |
| 354 | if (ret >= 0) | 444 | if (ret != 2) { |
| 355 | ret = 0; | 445 | pr_err("%s: i2c_read failed to transfer all messages\n", |
| 356 | return ret; | 446 | DRIVER_NAME); |
| 447 | if (ret < 0) | ||
| 448 | return ret; | ||
| 449 | else | ||
| 450 | return -EIO; | ||
| 451 | } else { | ||
| 452 | return 0; | ||
| 453 | } | ||
| 357 | } | 454 | } |
| 358 | EXPORT_SYMBOL(twl4030_i2c_read); | 455 | EXPORT_SYMBOL(twl_i2c_read); |
| 359 | 456 | ||
| 360 | /** | 457 | /** |
| 361 | * twl4030_i2c_write_u8 - Writes a 8 bit register in TWL4030 | 458 | * twl_i2c_write_u8 - Writes a 8 bit register in TWL4030/TWL5030/TWL60X0 |
| 362 | * @mod_no: module number | 459 | * @mod_no: module number |
| 363 | * @value: the value to be written 8 bit | 460 | * @value: the value to be written 8 bit |
| 364 | * @reg: register address (just offset will do) | 461 | * @reg: register address (just offset will do) |
| 365 | * | 462 | * |
| 366 | * Returns result of operation - 0 is success | 463 | * Returns result of operation - 0 is success |
| 367 | */ | 464 | */ |
| 368 | int twl4030_i2c_write_u8(u8 mod_no, u8 value, u8 reg) | 465 | int twl_i2c_write_u8(u8 mod_no, u8 value, u8 reg) |
| 369 | { | 466 | { |
| 370 | 467 | ||
| 371 | /* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */ | 468 | /* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */ |
| 372 | u8 temp_buffer[2] = { 0 }; | 469 | u8 temp_buffer[2] = { 0 }; |
| 373 | /* offset 1 contains the data */ | 470 | /* offset 1 contains the data */ |
| 374 | temp_buffer[1] = value; | 471 | temp_buffer[1] = value; |
| 375 | return twl4030_i2c_write(mod_no, temp_buffer, reg, 1); | 472 | return twl_i2c_write(mod_no, temp_buffer, reg, 1); |
| 376 | } | 473 | } |
| 377 | EXPORT_SYMBOL(twl4030_i2c_write_u8); | 474 | EXPORT_SYMBOL(twl_i2c_write_u8); |
| 378 | 475 | ||
| 379 | /** | 476 | /** |
| 380 | * twl4030_i2c_read_u8 - Reads a 8 bit register from TWL4030 | 477 | * twl_i2c_read_u8 - Reads a 8 bit register from TWL4030/TWL5030/TWL60X0 |
| 381 | * @mod_no: module number | 478 | * @mod_no: module number |
| 382 | * @value: the value read 8 bit | 479 | * @value: the value read 8 bit |
| 383 | * @reg: register address (just offset will do) | 480 | * @reg: register address (just offset will do) |
| 384 | * | 481 | * |
| 385 | * Returns result of operation - 0 is success | 482 | * Returns result of operation - 0 is success |
| 386 | */ | 483 | */ |
| 387 | int twl4030_i2c_read_u8(u8 mod_no, u8 *value, u8 reg) | 484 | int twl_i2c_read_u8(u8 mod_no, u8 *value, u8 reg) |
| 388 | { | 485 | { |
| 389 | return twl4030_i2c_read(mod_no, value, reg, 1); | 486 | return twl_i2c_read(mod_no, value, reg, 1); |
| 390 | } | 487 | } |
| 391 | EXPORT_SYMBOL(twl4030_i2c_read_u8); | 488 | EXPORT_SYMBOL(twl_i2c_read_u8); |
| 392 | 489 | ||
| 393 | /*----------------------------------------------------------------------*/ | 490 | /*----------------------------------------------------------------------*/ |
| 394 | 491 | ||
| @@ -398,7 +495,7 @@ add_numbered_child(unsigned chip, const char *name, int num, | |||
| 398 | bool can_wakeup, int irq0, int irq1) | 495 | bool can_wakeup, int irq0, int irq1) |
| 399 | { | 496 | { |
| 400 | struct platform_device *pdev; | 497 | struct platform_device *pdev; |
| 401 | struct twl4030_client *twl = &twl4030_modules[chip]; | 498 | struct twl_client *twl = &twl_modules[chip]; |
| 402 | int status; | 499 | int status; |
| 403 | 500 | ||
| 404 | pdev = platform_device_alloc(name, num); | 501 | pdev = platform_device_alloc(name, num); |
| @@ -456,6 +553,7 @@ add_regulator_linked(int num, struct regulator_init_data *pdata, | |||
| 456 | struct regulator_consumer_supply *consumers, | 553 | struct regulator_consumer_supply *consumers, |
| 457 | unsigned num_consumers) | 554 | unsigned num_consumers) |
| 458 | { | 555 | { |
| 556 | unsigned sub_chip_id; | ||
| 459 | /* regulator framework demands init_data ... */ | 557 | /* regulator framework demands init_data ... */ |
| 460 | if (!pdata) | 558 | if (!pdata) |
| 461 | return NULL; | 559 | return NULL; |
| @@ -466,7 +564,8 @@ add_regulator_linked(int num, struct regulator_init_data *pdata, | |||
| 466 | } | 564 | } |
| 467 | 565 | ||
| 468 | /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ | 566 | /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ |
| 469 | return add_numbered_child(3, "twl4030_reg", num, | 567 | sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid; |
| 568 | return add_numbered_child(sub_chip_id, "twl_reg", num, | ||
| 470 | pdata, sizeof(*pdata), false, 0, 0); | 569 | pdata, sizeof(*pdata), false, 0, 0); |
| 471 | } | 570 | } |
| 472 | 571 | ||
| @@ -486,29 +585,32 @@ static int | |||
| 486 | add_children(struct twl4030_platform_data *pdata, unsigned long features) | 585 | add_children(struct twl4030_platform_data *pdata, unsigned long features) |
| 487 | { | 586 | { |
| 488 | struct device *child; | 587 | struct device *child; |
| 588 | unsigned sub_chip_id; | ||
| 489 | 589 | ||
| 490 | if (twl_has_bci() && pdata->bci && !(features & TPS_SUBSET)) { | 590 | if (twl_has_bci() && pdata->bci && |
| 591 | !(features & (TPS_SUBSET | TWL5031))) { | ||
| 491 | child = add_child(3, "twl4030_bci", | 592 | child = add_child(3, "twl4030_bci", |
| 492 | pdata->bci, sizeof(*pdata->bci), | 593 | pdata->bci, sizeof(*pdata->bci), |
| 493 | false, | 594 | false, |
| 494 | /* irq0 = CHG_PRES, irq1 = BCI */ | 595 | /* irq0 = CHG_PRES, irq1 = BCI */ |
| 495 | pdata->irq_base + 8 + 1, pdata->irq_base + 2); | 596 | pdata->irq_base + BCI_PRES_INTR_OFFSET, |
| 597 | pdata->irq_base + BCI_INTR_OFFSET); | ||
| 496 | if (IS_ERR(child)) | 598 | if (IS_ERR(child)) |
| 497 | return PTR_ERR(child); | 599 | return PTR_ERR(child); |
| 498 | } | 600 | } |
| 499 | 601 | ||
| 500 | if (twl_has_gpio() && pdata->gpio) { | 602 | if (twl_has_gpio() && pdata->gpio) { |
| 501 | child = add_child(1, "twl4030_gpio", | 603 | child = add_child(SUB_CHIP_ID1, "twl4030_gpio", |
| 502 | pdata->gpio, sizeof(*pdata->gpio), | 604 | pdata->gpio, sizeof(*pdata->gpio), |
| 503 | false, pdata->irq_base + 0, 0); | 605 | false, pdata->irq_base + GPIO_INTR_OFFSET, 0); |
| 504 | if (IS_ERR(child)) | 606 | if (IS_ERR(child)) |
| 505 | return PTR_ERR(child); | 607 | return PTR_ERR(child); |
| 506 | } | 608 | } |
| 507 | 609 | ||
| 508 | if (twl_has_keypad() && pdata->keypad) { | 610 | if (twl_has_keypad() && pdata->keypad) { |
| 509 | child = add_child(2, "twl4030_keypad", | 611 | child = add_child(SUB_CHIP_ID2, "twl4030_keypad", |
| 510 | pdata->keypad, sizeof(*pdata->keypad), | 612 | pdata->keypad, sizeof(*pdata->keypad), |
| 511 | true, pdata->irq_base + 1, 0); | 613 | true, pdata->irq_base + KEYPAD_INTR_OFFSET, 0); |
| 512 | if (IS_ERR(child)) | 614 | if (IS_ERR(child)) |
| 513 | return PTR_ERR(child); | 615 | return PTR_ERR(child); |
| 514 | } | 616 | } |
| @@ -516,7 +618,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
| 516 | if (twl_has_madc() && pdata->madc) { | 618 | if (twl_has_madc() && pdata->madc) { |
| 517 | child = add_child(2, "twl4030_madc", | 619 | child = add_child(2, "twl4030_madc", |
| 518 | pdata->madc, sizeof(*pdata->madc), | 620 | pdata->madc, sizeof(*pdata->madc), |
| 519 | true, pdata->irq_base + 3, 0); | 621 | true, pdata->irq_base + MADC_INTR_OFFSET, 0); |
| 520 | if (IS_ERR(child)) | 622 | if (IS_ERR(child)) |
| 521 | return PTR_ERR(child); | 623 | return PTR_ERR(child); |
| 522 | } | 624 | } |
| @@ -529,14 +631,15 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
| 529 | * Eventually, Linux might become more aware of such | 631 | * Eventually, Linux might become more aware of such |
| 530 | * HW security concerns, and "least privilege". | 632 | * HW security concerns, and "least privilege". |
| 531 | */ | 633 | */ |
| 532 | child = add_child(3, "twl4030_rtc", | 634 | sub_chip_id = twl_map[TWL_MODULE_RTC].sid; |
| 635 | child = add_child(sub_chip_id, "twl_rtc", | ||
| 533 | NULL, 0, | 636 | NULL, 0, |
| 534 | true, pdata->irq_base + 8 + 3, 0); | 637 | true, pdata->irq_base + RTC_INTR_OFFSET, 0); |
| 535 | if (IS_ERR(child)) | 638 | if (IS_ERR(child)) |
| 536 | return PTR_ERR(child); | 639 | return PTR_ERR(child); |
| 537 | } | 640 | } |
| 538 | 641 | ||
| 539 | if (twl_has_usb() && pdata->usb) { | 642 | if (twl_has_usb() && pdata->usb && twl_class_is_4030()) { |
| 540 | 643 | ||
| 541 | static struct regulator_consumer_supply usb1v5 = { | 644 | static struct regulator_consumer_supply usb1v5 = { |
| 542 | .supply = "usb1v5", | 645 | .supply = "usb1v5", |
| @@ -581,7 +684,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
| 581 | pdata->usb, sizeof(*pdata->usb), | 684 | pdata->usb, sizeof(*pdata->usb), |
| 582 | true, | 685 | true, |
| 583 | /* irq0 = USB_PRES, irq1 = USB */ | 686 | /* irq0 = USB_PRES, irq1 = USB */ |
| 584 | pdata->irq_base + 8 + 2, pdata->irq_base + 4); | 687 | pdata->irq_base + USB_PRES_INTR_OFFSET, |
| 688 | pdata->irq_base + USB_INTR_OFFSET); | ||
| 585 | 689 | ||
| 586 | if (IS_ERR(child)) | 690 | if (IS_ERR(child)) |
| 587 | return PTR_ERR(child); | 691 | return PTR_ERR(child); |
| @@ -615,12 +719,23 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
| 615 | return PTR_ERR(child); | 719 | return PTR_ERR(child); |
| 616 | } | 720 | } |
| 617 | 721 | ||
| 618 | if (twl_has_regulator()) { | 722 | /* twl4030 regulators */ |
| 619 | /* | 723 | if (twl_has_regulator() && twl_class_is_4030()) { |
| 620 | child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1); | 724 | child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1); |
| 621 | if (IS_ERR(child)) | 725 | if (IS_ERR(child)) |
| 622 | return PTR_ERR(child); | 726 | return PTR_ERR(child); |
| 623 | */ | 727 | |
| 728 | child = add_regulator(TWL4030_REG_VIO, pdata->vio); | ||
| 729 | if (IS_ERR(child)) | ||
| 730 | return PTR_ERR(child); | ||
| 731 | |||
| 732 | child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1); | ||
| 733 | if (IS_ERR(child)) | ||
| 734 | return PTR_ERR(child); | ||
| 735 | |||
| 736 | child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2); | ||
| 737 | if (IS_ERR(child)) | ||
| 738 | return PTR_ERR(child); | ||
| 624 | 739 | ||
| 625 | child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1); | 740 | child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1); |
| 626 | if (IS_ERR(child)) | 741 | if (IS_ERR(child)) |
| @@ -636,10 +751,23 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
| 636 | pdata->vaux2); | 751 | pdata->vaux2); |
| 637 | if (IS_ERR(child)) | 752 | if (IS_ERR(child)) |
| 638 | return PTR_ERR(child); | 753 | return PTR_ERR(child); |
| 754 | |||
| 755 | child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1); | ||
| 756 | if (IS_ERR(child)) | ||
| 757 | return PTR_ERR(child); | ||
| 758 | |||
| 759 | child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2); | ||
| 760 | if (IS_ERR(child)) | ||
| 761 | return PTR_ERR(child); | ||
| 762 | |||
| 763 | child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig); | ||
| 764 | if (IS_ERR(child)) | ||
| 765 | return PTR_ERR(child); | ||
| 639 | } | 766 | } |
| 640 | 767 | ||
| 641 | /* maybe add LDOs that are omitted on cost-reduced parts */ | 768 | /* maybe add LDOs that are omitted on cost-reduced parts */ |
| 642 | if (twl_has_regulator() && !(features & TPS_SUBSET)) { | 769 | if (twl_has_regulator() && !(features & TPS_SUBSET) |
| 770 | && twl_class_is_4030()) { | ||
| 643 | child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2); | 771 | child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2); |
| 644 | if (IS_ERR(child)) | 772 | if (IS_ERR(child)) |
| 645 | return PTR_ERR(child); | 773 | return PTR_ERR(child); |
| @@ -665,6 +793,49 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
| 665 | return PTR_ERR(child); | 793 | return PTR_ERR(child); |
| 666 | } | 794 | } |
| 667 | 795 | ||
| 796 | /* twl6030 regulators */ | ||
| 797 | if (twl_has_regulator() && twl_class_is_6030()) { | ||
| 798 | child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc); | ||
| 799 | if (IS_ERR(child)) | ||
| 800 | return PTR_ERR(child); | ||
| 801 | |||
| 802 | child = add_regulator(TWL6030_REG_VPP, pdata->vpp); | ||
| 803 | if (IS_ERR(child)) | ||
| 804 | return PTR_ERR(child); | ||
| 805 | |||
| 806 | child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim); | ||
| 807 | if (IS_ERR(child)) | ||
| 808 | return PTR_ERR(child); | ||
| 809 | |||
| 810 | child = add_regulator(TWL6030_REG_VANA, pdata->vana); | ||
| 811 | if (IS_ERR(child)) | ||
| 812 | return PTR_ERR(child); | ||
| 813 | |||
| 814 | child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio); | ||
| 815 | if (IS_ERR(child)) | ||
| 816 | return PTR_ERR(child); | ||
| 817 | |||
| 818 | child = add_regulator(TWL6030_REG_VDAC, pdata->vdac); | ||
| 819 | if (IS_ERR(child)) | ||
| 820 | return PTR_ERR(child); | ||
| 821 | |||
| 822 | child = add_regulator(TWL6030_REG_VUSB, pdata->vusb); | ||
| 823 | if (IS_ERR(child)) | ||
| 824 | return PTR_ERR(child); | ||
| 825 | |||
| 826 | child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1); | ||
| 827 | if (IS_ERR(child)) | ||
| 828 | return PTR_ERR(child); | ||
| 829 | |||
| 830 | child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2); | ||
| 831 | if (IS_ERR(child)) | ||
| 832 | return PTR_ERR(child); | ||
| 833 | |||
| 834 | child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3); | ||
| 835 | if (IS_ERR(child)) | ||
| 836 | return PTR_ERR(child); | ||
| 837 | } | ||
| 838 | |||
| 668 | return 0; | 839 | return 0; |
| 669 | } | 840 | } |
| 670 | 841 | ||
| @@ -679,7 +850,7 @@ static inline int __init protect_pm_master(void) | |||
| 679 | { | 850 | { |
| 680 | int e = 0; | 851 | int e = 0; |
| 681 | 852 | ||
| 682 | e = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_LOCK, | 853 | e = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_LOCK, |
| 683 | R_PROTECT_KEY); | 854 | R_PROTECT_KEY); |
| 684 | return e; | 855 | return e; |
| 685 | } | 856 | } |
| @@ -688,14 +859,15 @@ static inline int __init unprotect_pm_master(void) | |||
| 688 | { | 859 | { |
| 689 | int e = 0; | 860 | int e = 0; |
| 690 | 861 | ||
| 691 | e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK1, | 862 | e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_UNLOCK1, |
| 692 | R_PROTECT_KEY); | 863 | R_PROTECT_KEY); |
| 693 | e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK2, | 864 | e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_UNLOCK2, |
| 694 | R_PROTECT_KEY); | 865 | R_PROTECT_KEY); |
| 695 | return e; | 866 | return e; |
| 696 | } | 867 | } |
| 697 | 868 | ||
| 698 | static void clocks_init(struct device *dev) | 869 | static void clocks_init(struct device *dev, |
| 870 | struct twl4030_clock_init_data *clock) | ||
| 699 | { | 871 | { |
| 700 | int e = 0; | 872 | int e = 0; |
| 701 | struct clk *osc; | 873 | struct clk *osc; |
| @@ -709,7 +881,7 @@ static void clocks_init(struct device *dev) | |||
| 709 | osc = clk_get(dev, "osc_sys_ck"); | 881 | osc = clk_get(dev, "osc_sys_ck"); |
| 710 | 882 | ||
| 711 | if (IS_ERR(osc)) { | 883 | if (IS_ERR(osc)) { |
| 712 | printk(KERN_WARNING "Skipping twl4030 internal clock init and " | 884 | printk(KERN_WARNING "Skipping twl internal clock init and " |
| 713 | "using bootloader value (unknown osc rate)\n"); | 885 | "using bootloader value (unknown osc rate)\n"); |
| 714 | return; | 886 | return; |
| 715 | } | 887 | } |
| @@ -723,7 +895,7 @@ static void clocks_init(struct device *dev) | |||
| 723 | */ | 895 | */ |
| 724 | osc = ERR_PTR(-EIO); | 896 | osc = ERR_PTR(-EIO); |
| 725 | 897 | ||
| 726 | printk(KERN_WARNING "Skipping twl4030 internal clock init and " | 898 | printk(KERN_WARNING "Skipping twl internal clock init and " |
| 727 | "using bootloader value (unknown osc rate)\n"); | 899 | "using bootloader value (unknown osc rate)\n"); |
| 728 | 900 | ||
| 729 | return; | 901 | return; |
| @@ -742,9 +914,12 @@ static void clocks_init(struct device *dev) | |||
| 742 | } | 914 | } |
| 743 | 915 | ||
| 744 | ctrl |= HIGH_PERF_SQ; | 916 | ctrl |= HIGH_PERF_SQ; |
| 917 | if (clock && clock->ck32k_lowpwr_enable) | ||
| 918 | ctrl |= CK32K_LOWPWR_EN; | ||
| 919 | |||
| 745 | e |= unprotect_pm_master(); | 920 | e |= unprotect_pm_master(); |
| 746 | /* effect->MADC+USB ck en */ | 921 | /* effect->MADC+USB ck en */ |
| 747 | e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, ctrl, R_CFG_BOOT); | 922 | e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, ctrl, R_CFG_BOOT); |
| 748 | e |= protect_pm_master(); | 923 | e |= protect_pm_master(); |
| 749 | 924 | ||
| 750 | if (e < 0) | 925 | if (e < 0) |
| @@ -753,24 +928,31 @@ static void clocks_init(struct device *dev) | |||
| 753 | 928 | ||
| 754 | /*----------------------------------------------------------------------*/ | 929 | /*----------------------------------------------------------------------*/ |
| 755 | 930 | ||
| 756 | int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); | 931 | int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); |
| 757 | int twl_exit_irq(void); | 932 | int twl4030_exit_irq(void); |
| 933 | int twl4030_init_chip_irq(const char *chip); | ||
| 934 | int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); | ||
| 935 | int twl6030_exit_irq(void); | ||
| 758 | 936 | ||
| 759 | static int twl4030_remove(struct i2c_client *client) | 937 | static int twl_remove(struct i2c_client *client) |
| 760 | { | 938 | { |
| 761 | unsigned i; | 939 | unsigned i; |
| 762 | int status; | 940 | int status; |
| 763 | 941 | ||
| 764 | status = twl_exit_irq(); | 942 | if (twl_class_is_4030()) |
| 943 | status = twl4030_exit_irq(); | ||
| 944 | else | ||
| 945 | status = twl6030_exit_irq(); | ||
| 946 | |||
| 765 | if (status < 0) | 947 | if (status < 0) |
| 766 | return status; | 948 | return status; |
| 767 | 949 | ||
| 768 | for (i = 0; i < TWL4030_NUM_SLAVES; i++) { | 950 | for (i = 0; i < TWL_NUM_SLAVES; i++) { |
| 769 | struct twl4030_client *twl = &twl4030_modules[i]; | 951 | struct twl_client *twl = &twl_modules[i]; |
| 770 | 952 | ||
| 771 | if (twl->client && twl->client != client) | 953 | if (twl->client && twl->client != client) |
| 772 | i2c_unregister_device(twl->client); | 954 | i2c_unregister_device(twl->client); |
| 773 | twl4030_modules[i].client = NULL; | 955 | twl_modules[i].client = NULL; |
| 774 | } | 956 | } |
| 775 | inuse = false; | 957 | inuse = false; |
| 776 | return 0; | 958 | return 0; |
| @@ -778,7 +960,7 @@ static int twl4030_remove(struct i2c_client *client) | |||
| 778 | 960 | ||
| 779 | /* NOTE: this driver only handles a single twl4030/tps659x0 chip */ | 961 | /* NOTE: this driver only handles a single twl4030/tps659x0 chip */ |
| 780 | static int __init | 962 | static int __init |
| 781 | twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id) | 963 | twl_probe(struct i2c_client *client, const struct i2c_device_id *id) |
| 782 | { | 964 | { |
| 783 | int status; | 965 | int status; |
| 784 | unsigned i; | 966 | unsigned i; |
| @@ -799,8 +981,8 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
| 799 | return -EBUSY; | 981 | return -EBUSY; |
| 800 | } | 982 | } |
| 801 | 983 | ||
| 802 | for (i = 0; i < TWL4030_NUM_SLAVES; i++) { | 984 | for (i = 0; i < TWL_NUM_SLAVES; i++) { |
| 803 | struct twl4030_client *twl = &twl4030_modules[i]; | 985 | struct twl_client *twl = &twl_modules[i]; |
| 804 | 986 | ||
| 805 | twl->address = client->addr + i; | 987 | twl->address = client->addr + i; |
| 806 | if (i == 0) | 988 | if (i == 0) |
| @@ -814,15 +996,20 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
| 814 | status = -ENOMEM; | 996 | status = -ENOMEM; |
| 815 | goto fail; | 997 | goto fail; |
| 816 | } | 998 | } |
| 817 | strlcpy(twl->client->name, id->name, | ||
| 818 | sizeof(twl->client->name)); | ||
| 819 | } | 999 | } |
| 820 | mutex_init(&twl->xfer_lock); | 1000 | mutex_init(&twl->xfer_lock); |
| 821 | } | 1001 | } |
| 822 | inuse = true; | 1002 | inuse = true; |
| 1003 | if ((id->driver_data) & TWL6030_CLASS) { | ||
| 1004 | twl_id = TWL6030_CLASS_ID; | ||
| 1005 | twl_map = &twl6030_map[0]; | ||
| 1006 | } else { | ||
| 1007 | twl_id = TWL4030_CLASS_ID; | ||
| 1008 | twl_map = &twl4030_map[0]; | ||
| 1009 | } | ||
| 823 | 1010 | ||
| 824 | /* setup clock framework */ | 1011 | /* setup clock framework */ |
| 825 | clocks_init(&client->dev); | 1012 | clocks_init(&client->dev, pdata->clock); |
| 826 | 1013 | ||
| 827 | /* load power event scripts */ | 1014 | /* load power event scripts */ |
| 828 | if (twl_has_power() && pdata->power) | 1015 | if (twl_has_power() && pdata->power) |
| @@ -832,7 +1019,15 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
| 832 | if (client->irq | 1019 | if (client->irq |
| 833 | && pdata->irq_base | 1020 | && pdata->irq_base |
| 834 | && pdata->irq_end > pdata->irq_base) { | 1021 | && pdata->irq_end > pdata->irq_base) { |
| 835 | status = twl_init_irq(client->irq, pdata->irq_base, pdata->irq_end); | 1022 | if (twl_class_is_4030()) { |
| 1023 | twl4030_init_chip_irq(id->name); | ||
| 1024 | status = twl4030_init_irq(client->irq, pdata->irq_base, | ||
| 1025 | pdata->irq_end); | ||
| 1026 | } else { | ||
| 1027 | status = twl6030_init_irq(client->irq, pdata->irq_base, | ||
| 1028 | pdata->irq_end); | ||
| 1029 | } | ||
| 1030 | |||
| 836 | if (status < 0) | 1031 | if (status < 0) |
| 837 | goto fail; | 1032 | goto fail; |
| 838 | } | 1033 | } |
| @@ -840,40 +1035,42 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
| 840 | status = add_children(pdata, id->driver_data); | 1035 | status = add_children(pdata, id->driver_data); |
| 841 | fail: | 1036 | fail: |
| 842 | if (status < 0) | 1037 | if (status < 0) |
| 843 | twl4030_remove(client); | 1038 | twl_remove(client); |
| 844 | return status; | 1039 | return status; |
| 845 | } | 1040 | } |
| 846 | 1041 | ||
| 847 | static const struct i2c_device_id twl4030_ids[] = { | 1042 | static const struct i2c_device_id twl_ids[] = { |
| 848 | { "twl4030", TWL4030_VAUX2 }, /* "Triton 2" */ | 1043 | { "twl4030", TWL4030_VAUX2 }, /* "Triton 2" */ |
| 849 | { "twl5030", 0 }, /* T2 updated */ | 1044 | { "twl5030", 0 }, /* T2 updated */ |
| 1045 | { "twl5031", TWL5031 }, /* TWL5030 updated */ | ||
| 850 | { "tps65950", 0 }, /* catalog version of twl5030 */ | 1046 | { "tps65950", 0 }, /* catalog version of twl5030 */ |
| 851 | { "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */ | 1047 | { "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */ |
| 852 | { "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */ | 1048 | { "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */ |
| 1049 | { "twl6030", TWL6030_CLASS }, /* "Phoenix power chip" */ | ||
| 853 | { /* end of list */ }, | 1050 | { /* end of list */ }, |
| 854 | }; | 1051 | }; |
| 855 | MODULE_DEVICE_TABLE(i2c, twl4030_ids); | 1052 | MODULE_DEVICE_TABLE(i2c, twl_ids); |
| 856 | 1053 | ||
| 857 | /* One Client Driver , 4 Clients */ | 1054 | /* One Client Driver , 4 Clients */ |
| 858 | static struct i2c_driver twl4030_driver = { | 1055 | static struct i2c_driver twl_driver = { |
| 859 | .driver.name = DRIVER_NAME, | 1056 | .driver.name = DRIVER_NAME, |
| 860 | .id_table = twl4030_ids, | 1057 | .id_table = twl_ids, |
| 861 | .probe = twl4030_probe, | 1058 | .probe = twl_probe, |
| 862 | .remove = twl4030_remove, | 1059 | .remove = twl_remove, |
| 863 | }; | 1060 | }; |
| 864 | 1061 | ||
| 865 | static int __init twl4030_init(void) | 1062 | static int __init twl_init(void) |
| 866 | { | 1063 | { |
| 867 | return i2c_add_driver(&twl4030_driver); | 1064 | return i2c_add_driver(&twl_driver); |
| 868 | } | 1065 | } |
| 869 | subsys_initcall(twl4030_init); | 1066 | subsys_initcall(twl_init); |
| 870 | 1067 | ||
| 871 | static void __exit twl4030_exit(void) | 1068 | static void __exit twl_exit(void) |
| 872 | { | 1069 | { |
| 873 | i2c_del_driver(&twl4030_driver); | 1070 | i2c_del_driver(&twl_driver); |
| 874 | } | 1071 | } |
| 875 | module_exit(twl4030_exit); | 1072 | module_exit(twl_exit); |
| 876 | 1073 | ||
| 877 | MODULE_AUTHOR("Texas Instruments, Inc."); | 1074 | MODULE_AUTHOR("Texas Instruments, Inc."); |
| 878 | MODULE_DESCRIPTION("I2C Core interface for TWL4030"); | 1075 | MODULE_DESCRIPTION("I2C Core interface for TWL"); |
| 879 | MODULE_LICENSE("GPL"); | 1076 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index fb194fe244c1..20d29bafc9f5 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c | |||
| @@ -32,7 +32,7 @@ | |||
| 32 | #include <linux/irq.h> | 32 | #include <linux/irq.h> |
| 33 | #include <linux/kthread.h> | 33 | #include <linux/kthread.h> |
| 34 | 34 | ||
| 35 | #include <linux/i2c/twl4030.h> | 35 | #include <linux/i2c/twl.h> |
| 36 | 36 | ||
| 37 | 37 | ||
| 38 | /* | 38 | /* |
| @@ -74,6 +74,8 @@ struct sih { | |||
| 74 | u8 edr_offset; | 74 | u8 edr_offset; |
| 75 | u8 bytes_edr; /* bytelen of EDR */ | 75 | u8 bytes_edr; /* bytelen of EDR */ |
| 76 | 76 | ||
| 77 | u8 irq_lines; /* number of supported irq lines */ | ||
| 78 | |||
| 77 | /* SIR ignored -- set interrupt, for testing only */ | 79 | /* SIR ignored -- set interrupt, for testing only */ |
| 78 | struct irq_data { | 80 | struct irq_data { |
| 79 | u8 isr_offset; | 81 | u8 isr_offset; |
| @@ -82,6 +84,9 @@ struct sih { | |||
| 82 | /* + 2 bytes padding */ | 84 | /* + 2 bytes padding */ |
| 83 | }; | 85 | }; |
| 84 | 86 | ||
| 87 | static const struct sih *sih_modules; | ||
| 88 | static int nr_sih_modules; | ||
| 89 | |||
| 85 | #define SIH_INITIALIZER(modname, nbits) \ | 90 | #define SIH_INITIALIZER(modname, nbits) \ |
| 86 | .module = TWL4030_MODULE_ ## modname, \ | 91 | .module = TWL4030_MODULE_ ## modname, \ |
| 87 | .control_offset = TWL4030_ ## modname ## _SIH_CTRL, \ | 92 | .control_offset = TWL4030_ ## modname ## _SIH_CTRL, \ |
| @@ -89,6 +94,7 @@ struct sih { | |||
| 89 | .bytes_ixr = DIV_ROUND_UP(nbits, 8), \ | 94 | .bytes_ixr = DIV_ROUND_UP(nbits, 8), \ |
| 90 | .edr_offset = TWL4030_ ## modname ## _EDR, \ | 95 | .edr_offset = TWL4030_ ## modname ## _EDR, \ |
| 91 | .bytes_edr = DIV_ROUND_UP((2*(nbits)), 8), \ | 96 | .bytes_edr = DIV_ROUND_UP((2*(nbits)), 8), \ |
| 97 | .irq_lines = 2, \ | ||
| 92 | .mask = { { \ | 98 | .mask = { { \ |
| 93 | .isr_offset = TWL4030_ ## modname ## _ISR1, \ | 99 | .isr_offset = TWL4030_ ## modname ## _ISR1, \ |
| 94 | .imr_offset = TWL4030_ ## modname ## _IMR1, \ | 100 | .imr_offset = TWL4030_ ## modname ## _IMR1, \ |
| @@ -107,7 +113,8 @@ struct sih { | |||
| 107 | /* Order in this table matches order in PIH_ISR. That is, | 113 | /* Order in this table matches order in PIH_ISR. That is, |
| 108 | * BIT(n) in PIH_ISR is sih_modules[n]. | 114 | * BIT(n) in PIH_ISR is sih_modules[n]. |
| 109 | */ | 115 | */ |
| 110 | static const struct sih sih_modules[6] = { | 116 | /* sih_modules_twl4030 is used both in twl4030 and twl5030 */ |
| 117 | static const struct sih sih_modules_twl4030[6] = { | ||
| 111 | [0] = { | 118 | [0] = { |
| 112 | .name = "gpio", | 119 | .name = "gpio", |
| 113 | .module = TWL4030_MODULE_GPIO, | 120 | .module = TWL4030_MODULE_GPIO, |
| @@ -118,6 +125,7 @@ static const struct sih sih_modules[6] = { | |||
| 118 | /* Note: *all* of these IRQs default to no-trigger */ | 125 | /* Note: *all* of these IRQs default to no-trigger */ |
| 119 | .edr_offset = REG_GPIO_EDR1, | 126 | .edr_offset = REG_GPIO_EDR1, |
| 120 | .bytes_edr = 5, | 127 | .bytes_edr = 5, |
| 128 | .irq_lines = 2, | ||
| 121 | .mask = { { | 129 | .mask = { { |
| 122 | .isr_offset = REG_GPIO_ISR1A, | 130 | .isr_offset = REG_GPIO_ISR1A, |
| 123 | .imr_offset = REG_GPIO_IMR1A, | 131 | .imr_offset = REG_GPIO_IMR1A, |
| @@ -140,6 +148,7 @@ static const struct sih sih_modules[6] = { | |||
| 140 | .edr_offset = TWL4030_INTERRUPTS_BCIEDR1, | 148 | .edr_offset = TWL4030_INTERRUPTS_BCIEDR1, |
| 141 | /* Note: most of these IRQs default to no-trigger */ | 149 | /* Note: most of these IRQs default to no-trigger */ |
| 142 | .bytes_edr = 3, | 150 | .bytes_edr = 3, |
| 151 | .irq_lines = 2, | ||
| 143 | .mask = { { | 152 | .mask = { { |
| 144 | .isr_offset = TWL4030_INTERRUPTS_BCIISR1A, | 153 | .isr_offset = TWL4030_INTERRUPTS_BCIISR1A, |
| 145 | .imr_offset = TWL4030_INTERRUPTS_BCIIMR1A, | 154 | .imr_offset = TWL4030_INTERRUPTS_BCIIMR1A, |
| @@ -164,6 +173,99 @@ static const struct sih sih_modules[6] = { | |||
| 164 | /* there are no SIH modules #6 or #7 ... */ | 173 | /* there are no SIH modules #6 or #7 ... */ |
| 165 | }; | 174 | }; |
| 166 | 175 | ||
| 176 | static const struct sih sih_modules_twl5031[8] = { | ||
| 177 | [0] = { | ||
| 178 | .name = "gpio", | ||
| 179 | .module = TWL4030_MODULE_GPIO, | ||
| 180 | .control_offset = REG_GPIO_SIH_CTRL, | ||
| 181 | .set_cor = true, | ||
| 182 | .bits = TWL4030_GPIO_MAX, | ||
| 183 | .bytes_ixr = 3, | ||
| 184 | /* Note: *all* of these IRQs default to no-trigger */ | ||
| 185 | .edr_offset = REG_GPIO_EDR1, | ||
| 186 | .bytes_edr = 5, | ||
| 187 | .irq_lines = 2, | ||
| 188 | .mask = { { | ||
| 189 | .isr_offset = REG_GPIO_ISR1A, | ||
| 190 | .imr_offset = REG_GPIO_IMR1A, | ||
| 191 | }, { | ||
| 192 | .isr_offset = REG_GPIO_ISR1B, | ||
| 193 | .imr_offset = REG_GPIO_IMR1B, | ||
| 194 | }, }, | ||
| 195 | }, | ||
| 196 | [1] = { | ||
| 197 | .name = "keypad", | ||
| 198 | .set_cor = true, | ||
| 199 | SIH_INITIALIZER(KEYPAD_KEYP, 4) | ||
| 200 | }, | ||
| 201 | [2] = { | ||
| 202 | .name = "bci", | ||
| 203 | .module = TWL5031_MODULE_INTERRUPTS, | ||
| 204 | .control_offset = TWL5031_INTERRUPTS_BCISIHCTRL, | ||
| 205 | .bits = 7, | ||
| 206 | .bytes_ixr = 1, | ||
| 207 | .edr_offset = TWL5031_INTERRUPTS_BCIEDR1, | ||
| 208 | /* Note: most of these IRQs default to no-trigger */ | ||
| 209 | .bytes_edr = 2, | ||
| 210 | .irq_lines = 2, | ||
| 211 | .mask = { { | ||
| 212 | .isr_offset = TWL5031_INTERRUPTS_BCIISR1, | ||
| 213 | .imr_offset = TWL5031_INTERRUPTS_BCIIMR1, | ||
| 214 | }, { | ||
| 215 | .isr_offset = TWL5031_INTERRUPTS_BCIISR2, | ||
| 216 | .imr_offset = TWL5031_INTERRUPTS_BCIIMR2, | ||
| 217 | }, }, | ||
| 218 | }, | ||
| 219 | [3] = { | ||
| 220 | .name = "madc", | ||
| 221 | SIH_INITIALIZER(MADC, 4) | ||
| 222 | }, | ||
| 223 | [4] = { | ||
| 224 | /* USB doesn't use the same SIH organization */ | ||
| 225 | .name = "usb", | ||
| 226 | }, | ||
| 227 | [5] = { | ||
| 228 | .name = "power", | ||
| 229 | .set_cor = true, | ||
| 230 | SIH_INITIALIZER(INT_PWR, 8) | ||
| 231 | }, | ||
| 232 | [6] = { | ||
| 233 | /* | ||
| 234 | * ACI doesn't use the same SIH organization. | ||
| 235 | * For example, it supports only one interrupt line | ||
| 236 | */ | ||
| 237 | .name = "aci", | ||
| 238 | .module = TWL5031_MODULE_ACCESSORY, | ||
| 239 | .bits = 9, | ||
| 240 | .bytes_ixr = 2, | ||
| 241 | .irq_lines = 1, | ||
| 242 | .mask = { { | ||
| 243 | .isr_offset = TWL5031_ACIIDR_LSB, | ||
| 244 | .imr_offset = TWL5031_ACIIMR_LSB, | ||
| 245 | }, }, | ||
| 246 | |||
| 247 | }, | ||
| 248 | [7] = { | ||
| 249 | /* Accessory */ | ||
| 250 | .name = "acc", | ||
| 251 | .module = TWL5031_MODULE_ACCESSORY, | ||
| 252 | .control_offset = TWL5031_ACCSIHCTRL, | ||
| 253 | .bits = 2, | ||
| 254 | .bytes_ixr = 1, | ||
| 255 | .edr_offset = TWL5031_ACCEDR1, | ||
| 256 | /* Note: most of these IRQs default to no-trigger */ | ||
| 257 | .bytes_edr = 1, | ||
| 258 | .irq_lines = 2, | ||
| 259 | .mask = { { | ||
| 260 | .isr_offset = TWL5031_ACCISR1, | ||
| 261 | .imr_offset = TWL5031_ACCIMR1, | ||
| 262 | }, { | ||
| 263 | .isr_offset = TWL5031_ACCISR2, | ||
| 264 | .imr_offset = TWL5031_ACCIMR2, | ||
| 265 | }, }, | ||
| 266 | }, | ||
| 267 | }; | ||
| 268 | |||
| 167 | #undef TWL4030_MODULE_KEYPAD_KEYP | 269 | #undef TWL4030_MODULE_KEYPAD_KEYP |
| 168 | #undef TWL4030_MODULE_INT_PWR | 270 | #undef TWL4030_MODULE_INT_PWR |
| 169 | #undef TWL4030_INT_PWR_EDR | 271 | #undef TWL4030_INT_PWR_EDR |
| @@ -194,7 +296,7 @@ static int twl4030_irq_thread(void *data) | |||
| 194 | /* Wait for IRQ, then read PIH irq status (also blocking) */ | 296 | /* Wait for IRQ, then read PIH irq status (also blocking) */ |
| 195 | wait_for_completion_interruptible(&irq_event); | 297 | wait_for_completion_interruptible(&irq_event); |
| 196 | 298 | ||
| 197 | ret = twl4030_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr, | 299 | ret = twl_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr, |
| 198 | REG_PIH_ISR_P1); | 300 | REG_PIH_ISR_P1); |
| 199 | if (ret) { | 301 | if (ret) { |
| 200 | pr_warning("twl4030: I2C error %d reading PIH ISR\n", | 302 | pr_warning("twl4030: I2C error %d reading PIH ISR\n", |
| @@ -284,13 +386,17 @@ static int twl4030_init_sih_modules(unsigned line) | |||
| 284 | /* disable all interrupts on our line */ | 386 | /* disable all interrupts on our line */ |
| 285 | memset(buf, 0xff, sizeof buf); | 387 | memset(buf, 0xff, sizeof buf); |
| 286 | sih = sih_modules; | 388 | sih = sih_modules; |
| 287 | for (i = 0; i < ARRAY_SIZE(sih_modules); i++, sih++) { | 389 | for (i = 0; i < nr_sih_modules; i++, sih++) { |
| 288 | 390 | ||
| 289 | /* skip USB -- it's funky */ | 391 | /* skip USB -- it's funky */ |
| 290 | if (!sih->bytes_ixr) | 392 | if (!sih->bytes_ixr) |
| 291 | continue; | 393 | continue; |
| 292 | 394 | ||
| 293 | status = twl4030_i2c_write(sih->module, buf, | 395 | /* Not all the SIH modules support multiple interrupt lines */ |
| 396 | if (sih->irq_lines <= line) | ||
| 397 | continue; | ||
| 398 | |||
| 399 | status = twl_i2c_write(sih->module, buf, | ||
| 294 | sih->mask[line].imr_offset, sih->bytes_ixr); | 400 | sih->mask[line].imr_offset, sih->bytes_ixr); |
| 295 | if (status < 0) | 401 | if (status < 0) |
| 296 | pr_err("twl4030: err %d initializing %s %s\n", | 402 | pr_err("twl4030: err %d initializing %s %s\n", |
| @@ -304,7 +410,7 @@ static int twl4030_init_sih_modules(unsigned line) | |||
| 304 | * And for PWR_INT it's not documented... | 410 | * And for PWR_INT it's not documented... |
| 305 | */ | 411 | */ |
| 306 | if (sih->set_cor) { | 412 | if (sih->set_cor) { |
| 307 | status = twl4030_i2c_write_u8(sih->module, | 413 | status = twl_i2c_write_u8(sih->module, |
| 308 | TWL4030_SIH_CTRL_COR_MASK, | 414 | TWL4030_SIH_CTRL_COR_MASK, |
| 309 | sih->control_offset); | 415 | sih->control_offset); |
| 310 | if (status < 0) | 416 | if (status < 0) |
| @@ -314,7 +420,7 @@ static int twl4030_init_sih_modules(unsigned line) | |||
| 314 | } | 420 | } |
| 315 | 421 | ||
| 316 | sih = sih_modules; | 422 | sih = sih_modules; |
| 317 | for (i = 0; i < ARRAY_SIZE(sih_modules); i++, sih++) { | 423 | for (i = 0; i < nr_sih_modules; i++, sih++) { |
| 318 | u8 rxbuf[4]; | 424 | u8 rxbuf[4]; |
| 319 | int j; | 425 | int j; |
| 320 | 426 | ||
| @@ -322,20 +428,24 @@ static int twl4030_init_sih_modules(unsigned line) | |||
| 322 | if (!sih->bytes_ixr) | 428 | if (!sih->bytes_ixr) |
| 323 | continue; | 429 | continue; |
| 324 | 430 | ||
| 431 | /* Not all the SIH modules support multiple interrupt lines */ | ||
| 432 | if (sih->irq_lines <= line) | ||
| 433 | continue; | ||
| 434 | |||
| 325 | /* Clear pending interrupt status. Either the read was | 435 | /* Clear pending interrupt status. Either the read was |
| 326 | * enough, or we need to write those bits. Repeat, in | 436 | * enough, or we need to write those bits. Repeat, in |
| 327 | * case an IRQ is pending (PENDDIS=0) ... that's not | 437 | * case an IRQ is pending (PENDDIS=0) ... that's not |
| 328 | * uncommon with PWR_INT.PWRON. | 438 | * uncommon with PWR_INT.PWRON. |
| 329 | */ | 439 | */ |
| 330 | for (j = 0; j < 2; j++) { | 440 | for (j = 0; j < 2; j++) { |
| 331 | status = twl4030_i2c_read(sih->module, rxbuf, | 441 | status = twl_i2c_read(sih->module, rxbuf, |
| 332 | sih->mask[line].isr_offset, sih->bytes_ixr); | 442 | sih->mask[line].isr_offset, sih->bytes_ixr); |
| 333 | if (status < 0) | 443 | if (status < 0) |
| 334 | pr_err("twl4030: err %d initializing %s %s\n", | 444 | pr_err("twl4030: err %d initializing %s %s\n", |
| 335 | status, sih->name, "ISR"); | 445 | status, sih->name, "ISR"); |
| 336 | 446 | ||
| 337 | if (!sih->set_cor) | 447 | if (!sih->set_cor) |
| 338 | status = twl4030_i2c_write(sih->module, buf, | 448 | status = twl_i2c_write(sih->module, buf, |
| 339 | sih->mask[line].isr_offset, | 449 | sih->mask[line].isr_offset, |
| 340 | sih->bytes_ixr); | 450 | sih->bytes_ixr); |
| 341 | /* else COR=1 means read sufficed. | 451 | /* else COR=1 means read sufficed. |
| @@ -404,7 +514,7 @@ static void twl4030_sih_do_mask(struct work_struct *work) | |||
| 404 | return; | 514 | return; |
| 405 | 515 | ||
| 406 | /* write the whole mask ... simpler than subsetting it */ | 516 | /* write the whole mask ... simpler than subsetting it */ |
| 407 | status = twl4030_i2c_write(sih->module, imr.bytes, | 517 | status = twl_i2c_write(sih->module, imr.bytes, |
| 408 | sih->mask[irq_line].imr_offset, sih->bytes_ixr); | 518 | sih->mask[irq_line].imr_offset, sih->bytes_ixr); |
| 409 | if (status) | 519 | if (status) |
| 410 | pr_err("twl4030: %s, %s --> %d\n", __func__, | 520 | pr_err("twl4030: %s, %s --> %d\n", __func__, |
| @@ -435,7 +545,7 @@ static void twl4030_sih_do_edge(struct work_struct *work) | |||
| 435 | * any processor on the other IRQ line, EDR registers are | 545 | * any processor on the other IRQ line, EDR registers are |
| 436 | * shared. | 546 | * shared. |
| 437 | */ | 547 | */ |
| 438 | status = twl4030_i2c_read(sih->module, bytes + 1, | 548 | status = twl_i2c_read(sih->module, bytes + 1, |
| 439 | sih->edr_offset, sih->bytes_edr); | 549 | sih->edr_offset, sih->bytes_edr); |
| 440 | if (status) { | 550 | if (status) { |
| 441 | pr_err("twl4030: %s, %s --> %d\n", __func__, | 551 | pr_err("twl4030: %s, %s --> %d\n", __func__, |
| @@ -469,7 +579,7 @@ static void twl4030_sih_do_edge(struct work_struct *work) | |||
| 469 | } | 579 | } |
| 470 | 580 | ||
| 471 | /* Write */ | 581 | /* Write */ |
| 472 | status = twl4030_i2c_write(sih->module, bytes, | 582 | status = twl_i2c_write(sih->module, bytes, |
| 473 | sih->edr_offset, sih->bytes_edr); | 583 | sih->edr_offset, sih->bytes_edr); |
| 474 | if (status) | 584 | if (status) |
| 475 | pr_err("twl4030: %s, %s --> %d\n", __func__, | 585 | pr_err("twl4030: %s, %s --> %d\n", __func__, |
| @@ -554,7 +664,7 @@ static inline int sih_read_isr(const struct sih *sih) | |||
| 554 | /* FIXME need retry-on-error ... */ | 664 | /* FIXME need retry-on-error ... */ |
| 555 | 665 | ||
| 556 | isr.word = 0; | 666 | isr.word = 0; |
| 557 | status = twl4030_i2c_read(sih->module, isr.bytes, | 667 | status = twl_i2c_read(sih->module, isr.bytes, |
| 558 | sih->mask[irq_line].isr_offset, sih->bytes_ixr); | 668 | sih->mask[irq_line].isr_offset, sih->bytes_ixr); |
| 559 | 669 | ||
| 560 | return (status < 0) ? status : le32_to_cpu(isr.word); | 670 | return (status < 0) ? status : le32_to_cpu(isr.word); |
| @@ -611,7 +721,7 @@ int twl4030_sih_setup(int module) | |||
| 611 | 721 | ||
| 612 | /* only support modules with standard clear-on-read for now */ | 722 | /* only support modules with standard clear-on-read for now */ |
| 613 | for (sih_mod = 0, sih = sih_modules; | 723 | for (sih_mod = 0, sih = sih_modules; |
| 614 | sih_mod < ARRAY_SIZE(sih_modules); | 724 | sih_mod < nr_sih_modules; |
| 615 | sih_mod++, sih++) { | 725 | sih_mod++, sih++) { |
| 616 | if (sih->module == module && sih->set_cor) { | 726 | if (sih->module == module && sih->set_cor) { |
| 617 | if (!WARN((irq_base + sih->bits) > NR_IRQS, | 727 | if (!WARN((irq_base + sih->bits) > NR_IRQS, |
| @@ -668,7 +778,7 @@ int twl4030_sih_setup(int module) | |||
| 668 | /* FIXME pass in which interrupt line we'll use ... */ | 778 | /* FIXME pass in which interrupt line we'll use ... */ |
| 669 | #define twl_irq_line 0 | 779 | #define twl_irq_line 0 |
| 670 | 780 | ||
| 671 | int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | 781 | int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) |
| 672 | { | 782 | { |
| 673 | static struct irq_chip twl4030_irq_chip; | 783 | static struct irq_chip twl4030_irq_chip; |
| 674 | 784 | ||
| @@ -728,7 +838,8 @@ int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | |||
| 728 | goto fail_rqirq; | 838 | goto fail_rqirq; |
| 729 | } | 839 | } |
| 730 | 840 | ||
| 731 | task = kthread_run(twl4030_irq_thread, (void *)irq_num, "twl4030-irq"); | 841 | task = kthread_run(twl4030_irq_thread, (void *)(long)irq_num, |
| 842 | "twl4030-irq"); | ||
| 732 | if (IS_ERR(task)) { | 843 | if (IS_ERR(task)) { |
| 733 | pr_err("twl4030: could not create irq %d thread!\n", irq_num); | 844 | pr_err("twl4030: could not create irq %d thread!\n", irq_num); |
| 734 | status = PTR_ERR(task); | 845 | status = PTR_ERR(task); |
| @@ -747,7 +858,7 @@ fail: | |||
| 747 | return status; | 858 | return status; |
| 748 | } | 859 | } |
| 749 | 860 | ||
| 750 | int twl_exit_irq(void) | 861 | int twl4030_exit_irq(void) |
| 751 | { | 862 | { |
| 752 | /* FIXME undo twl_init_irq() */ | 863 | /* FIXME undo twl_init_irq() */ |
| 753 | if (twl4030_irq_base) { | 864 | if (twl4030_irq_base) { |
| @@ -756,3 +867,16 @@ int twl_exit_irq(void) | |||
| 756 | } | 867 | } |
| 757 | return 0; | 868 | return 0; |
| 758 | } | 869 | } |
| 870 | |||
| 871 | int twl4030_init_chip_irq(const char *chip) | ||
| 872 | { | ||
| 873 | if (!strcmp(chip, "twl5031")) { | ||
| 874 | sih_modules = sih_modules_twl5031; | ||
| 875 | nr_sih_modules = ARRAY_SIZE(sih_modules_twl5031); | ||
| 876 | } else { | ||
| 877 | sih_modules = sih_modules_twl4030; | ||
| 878 | nr_sih_modules = ARRAY_SIZE(sih_modules_twl4030); | ||
| 879 | } | ||
| 880 | |||
| 881 | return 0; | ||
| 882 | } | ||
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index d423e0c4176b..0815292fdafc 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c | |||
| @@ -26,7 +26,7 @@ | |||
| 26 | 26 | ||
| 27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
| 28 | #include <linux/pm.h> | 28 | #include <linux/pm.h> |
| 29 | #include <linux/i2c/twl4030.h> | 29 | #include <linux/i2c/twl.h> |
| 30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
| 31 | 31 | ||
| 32 | #include <asm/mach-types.h> | 32 | #include <asm/mach-types.h> |
| @@ -67,19 +67,35 @@ static u8 twl4030_start_script_address = 0x2b; | |||
| 67 | #define R_KEY_1 0xC0 | 67 | #define R_KEY_1 0xC0 |
| 68 | #define R_KEY_2 0x0C | 68 | #define R_KEY_2 0x0C |
| 69 | 69 | ||
| 70 | /* resource configuration registers */ | 70 | /* resource configuration registers |
| 71 | 71 | <RESOURCE>_DEV_GRP at address 'n+0' | |
| 72 | #define DEVGROUP_OFFSET 0 | 72 | <RESOURCE>_TYPE at address 'n+1' |
| 73 | <RESOURCE>_REMAP at address 'n+2' | ||
| 74 | <RESOURCE>_DEDICATED at address 'n+3' | ||
| 75 | */ | ||
| 76 | #define DEV_GRP_OFFSET 0 | ||
| 73 | #define TYPE_OFFSET 1 | 77 | #define TYPE_OFFSET 1 |
| 78 | #define REMAP_OFFSET 2 | ||
| 79 | #define DEDICATED_OFFSET 3 | ||
| 80 | |||
| 81 | /* Bit positions in the registers */ | ||
| 82 | |||
| 83 | /* <RESOURCE>_DEV_GRP */ | ||
| 84 | #define DEV_GRP_SHIFT 5 | ||
| 85 | #define DEV_GRP_MASK (7 << DEV_GRP_SHIFT) | ||
| 74 | 86 | ||
| 75 | /* Bit positions */ | 87 | /* <RESOURCE>_TYPE */ |
| 76 | #define DEVGROUP_SHIFT 5 | ||
| 77 | #define DEVGROUP_MASK (7 << DEVGROUP_SHIFT) | ||
| 78 | #define TYPE_SHIFT 0 | 88 | #define TYPE_SHIFT 0 |
| 79 | #define TYPE_MASK (7 << TYPE_SHIFT) | 89 | #define TYPE_MASK (7 << TYPE_SHIFT) |
| 80 | #define TYPE2_SHIFT 3 | 90 | #define TYPE2_SHIFT 3 |
| 81 | #define TYPE2_MASK (3 << TYPE2_SHIFT) | 91 | #define TYPE2_MASK (3 << TYPE2_SHIFT) |
| 82 | 92 | ||
| 93 | /* <RESOURCE>_REMAP */ | ||
| 94 | #define SLEEP_STATE_SHIFT 0 | ||
| 95 | #define SLEEP_STATE_MASK (0xf << SLEEP_STATE_SHIFT) | ||
| 96 | #define OFF_STATE_SHIFT 4 | ||
| 97 | #define OFF_STATE_MASK (0xf << OFF_STATE_SHIFT) | ||
| 98 | |||
| 83 | static u8 res_config_addrs[] = { | 99 | static u8 res_config_addrs[] = { |
| 84 | [RES_VAUX1] = 0x17, | 100 | [RES_VAUX1] = 0x17, |
| 85 | [RES_VAUX2] = 0x1b, | 101 | [RES_VAUX2] = 0x1b, |
| @@ -115,11 +131,11 @@ static int __init twl4030_write_script_byte(u8 address, u8 byte) | |||
| 115 | { | 131 | { |
| 116 | int err; | 132 | int err; |
| 117 | 133 | ||
| 118 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, | 134 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, |
| 119 | R_MEMORY_ADDRESS); | 135 | R_MEMORY_ADDRESS); |
| 120 | if (err) | 136 | if (err) |
| 121 | goto out; | 137 | goto out; |
| 122 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte, | 138 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte, |
| 123 | R_MEMORY_DATA); | 139 | R_MEMORY_DATA); |
| 124 | out: | 140 | out: |
| 125 | return err; | 141 | return err; |
| @@ -176,18 +192,18 @@ static int __init twl4030_config_wakeup3_sequence(u8 address) | |||
| 176 | u8 data; | 192 | u8 data; |
| 177 | 193 | ||
| 178 | /* Set SLEEP to ACTIVE SEQ address for P3 */ | 194 | /* Set SLEEP to ACTIVE SEQ address for P3 */ |
| 179 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, | 195 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, |
| 180 | R_SEQ_ADD_S2A3); | 196 | R_SEQ_ADD_S2A3); |
| 181 | if (err) | 197 | if (err) |
| 182 | goto out; | 198 | goto out; |
| 183 | 199 | ||
| 184 | /* P3 LVL_WAKEUP should be on LEVEL */ | 200 | /* P3 LVL_WAKEUP should be on LEVEL */ |
| 185 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, | 201 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, |
| 186 | R_P3_SW_EVENTS); | 202 | R_P3_SW_EVENTS); |
| 187 | if (err) | 203 | if (err) |
| 188 | goto out; | 204 | goto out; |
| 189 | data |= LVL_WAKEUP; | 205 | data |= LVL_WAKEUP; |
| 190 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data, | 206 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data, |
| 191 | R_P3_SW_EVENTS); | 207 | R_P3_SW_EVENTS); |
| 192 | out: | 208 | out: |
| 193 | if (err) | 209 | if (err) |
| @@ -201,42 +217,42 @@ static int __init twl4030_config_wakeup12_sequence(u8 address) | |||
| 201 | u8 data; | 217 | u8 data; |
| 202 | 218 | ||
| 203 | /* Set SLEEP to ACTIVE SEQ address for P1 and P2 */ | 219 | /* Set SLEEP to ACTIVE SEQ address for P1 and P2 */ |
| 204 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, | 220 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, |
| 205 | R_SEQ_ADD_S2A12); | 221 | R_SEQ_ADD_S2A12); |
| 206 | if (err) | 222 | if (err) |
| 207 | goto out; | 223 | goto out; |
| 208 | 224 | ||
| 209 | /* P1/P2 LVL_WAKEUP should be on LEVEL */ | 225 | /* P1/P2 LVL_WAKEUP should be on LEVEL */ |
| 210 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, | 226 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, |
| 211 | R_P1_SW_EVENTS); | 227 | R_P1_SW_EVENTS); |
| 212 | if (err) | 228 | if (err) |
| 213 | goto out; | 229 | goto out; |
| 214 | 230 | ||
| 215 | data |= LVL_WAKEUP; | 231 | data |= LVL_WAKEUP; |
| 216 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data, | 232 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data, |
| 217 | R_P1_SW_EVENTS); | 233 | R_P1_SW_EVENTS); |
| 218 | if (err) | 234 | if (err) |
| 219 | goto out; | 235 | goto out; |
| 220 | 236 | ||
| 221 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, | 237 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, |
| 222 | R_P2_SW_EVENTS); | 238 | R_P2_SW_EVENTS); |
| 223 | if (err) | 239 | if (err) |
| 224 | goto out; | 240 | goto out; |
| 225 | 241 | ||
| 226 | data |= LVL_WAKEUP; | 242 | data |= LVL_WAKEUP; |
| 227 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data, | 243 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data, |
| 228 | R_P2_SW_EVENTS); | 244 | R_P2_SW_EVENTS); |
| 229 | if (err) | 245 | if (err) |
| 230 | goto out; | 246 | goto out; |
| 231 | 247 | ||
| 232 | if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) { | 248 | if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) { |
| 233 | /* Disabling AC charger effect on sleep-active transitions */ | 249 | /* Disabling AC charger effect on sleep-active transitions */ |
| 234 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, | 250 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data, |
| 235 | R_CFG_P1_TRANSITION); | 251 | R_CFG_P1_TRANSITION); |
| 236 | if (err) | 252 | if (err) |
| 237 | goto out; | 253 | goto out; |
| 238 | data &= ~(1<<1); | 254 | data &= ~(1<<1); |
| 239 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data , | 255 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data , |
| 240 | R_CFG_P1_TRANSITION); | 256 | R_CFG_P1_TRANSITION); |
| 241 | if (err) | 257 | if (err) |
| 242 | goto out; | 258 | goto out; |
| @@ -254,7 +270,7 @@ static int __init twl4030_config_sleep_sequence(u8 address) | |||
| 254 | int err; | 270 | int err; |
| 255 | 271 | ||
| 256 | /* Set ACTIVE to SLEEP SEQ address in T2 memory*/ | 272 | /* Set ACTIVE to SLEEP SEQ address in T2 memory*/ |
| 257 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, | 273 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, |
| 258 | R_SEQ_ADD_A2S); | 274 | R_SEQ_ADD_A2S); |
| 259 | 275 | ||
| 260 | if (err) | 276 | if (err) |
| @@ -269,41 +285,41 @@ static int __init twl4030_config_warmreset_sequence(u8 address) | |||
| 269 | u8 rd_data; | 285 | u8 rd_data; |
| 270 | 286 | ||
| 271 | /* Set WARM RESET SEQ address for P1 */ | 287 | /* Set WARM RESET SEQ address for P1 */ |
| 272 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, | 288 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address, |
| 273 | R_SEQ_ADD_WARM); | 289 | R_SEQ_ADD_WARM); |
| 274 | if (err) | 290 | if (err) |
| 275 | goto out; | 291 | goto out; |
| 276 | 292 | ||
| 277 | /* P1/P2/P3 enable WARMRESET */ | 293 | /* P1/P2/P3 enable WARMRESET */ |
| 278 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data, | 294 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data, |
| 279 | R_P1_SW_EVENTS); | 295 | R_P1_SW_EVENTS); |
| 280 | if (err) | 296 | if (err) |
| 281 | goto out; | 297 | goto out; |
| 282 | 298 | ||
| 283 | rd_data |= ENABLE_WARMRESET; | 299 | rd_data |= ENABLE_WARMRESET; |
| 284 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data, | 300 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data, |
| 285 | R_P1_SW_EVENTS); | 301 | R_P1_SW_EVENTS); |
| 286 | if (err) | 302 | if (err) |
| 287 | goto out; | 303 | goto out; |
| 288 | 304 | ||
| 289 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data, | 305 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data, |
| 290 | R_P2_SW_EVENTS); | 306 | R_P2_SW_EVENTS); |
| 291 | if (err) | 307 | if (err) |
| 292 | goto out; | 308 | goto out; |
| 293 | 309 | ||
| 294 | rd_data |= ENABLE_WARMRESET; | 310 | rd_data |= ENABLE_WARMRESET; |
| 295 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data, | 311 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data, |
| 296 | R_P2_SW_EVENTS); | 312 | R_P2_SW_EVENTS); |
| 297 | if (err) | 313 | if (err) |
| 298 | goto out; | 314 | goto out; |
| 299 | 315 | ||
| 300 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data, | 316 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data, |
| 301 | R_P3_SW_EVENTS); | 317 | R_P3_SW_EVENTS); |
| 302 | if (err) | 318 | if (err) |
| 303 | goto out; | 319 | goto out; |
| 304 | 320 | ||
| 305 | rd_data |= ENABLE_WARMRESET; | 321 | rd_data |= ENABLE_WARMRESET; |
| 306 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data, | 322 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data, |
| 307 | R_P3_SW_EVENTS); | 323 | R_P3_SW_EVENTS); |
| 308 | out: | 324 | out: |
| 309 | if (err) | 325 | if (err) |
| @@ -317,6 +333,7 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig) | |||
| 317 | int err; | 333 | int err; |
| 318 | u8 type; | 334 | u8 type; |
| 319 | u8 grp; | 335 | u8 grp; |
| 336 | u8 remap; | ||
| 320 | 337 | ||
| 321 | if (rconfig->resource > TOTAL_RESOURCES) { | 338 | if (rconfig->resource > TOTAL_RESOURCES) { |
| 322 | pr_err("TWL4030 Resource %d does not exist\n", | 339 | pr_err("TWL4030 Resource %d does not exist\n", |
| @@ -327,19 +344,19 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig) | |||
| 327 | rconfig_addr = res_config_addrs[rconfig->resource]; | 344 | rconfig_addr = res_config_addrs[rconfig->resource]; |
| 328 | 345 | ||
| 329 | /* Set resource group */ | 346 | /* Set resource group */ |
| 330 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp, | 347 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp, |
| 331 | rconfig_addr + DEVGROUP_OFFSET); | 348 | rconfig_addr + DEV_GRP_OFFSET); |
| 332 | if (err) { | 349 | if (err) { |
| 333 | pr_err("TWL4030 Resource %d group could not be read\n", | 350 | pr_err("TWL4030 Resource %d group could not be read\n", |
| 334 | rconfig->resource); | 351 | rconfig->resource); |
| 335 | return err; | 352 | return err; |
| 336 | } | 353 | } |
| 337 | 354 | ||
| 338 | if (rconfig->devgroup >= 0) { | 355 | if (rconfig->devgroup != TWL4030_RESCONFIG_UNDEF) { |
| 339 | grp &= ~DEVGROUP_MASK; | 356 | grp &= ~DEV_GRP_MASK; |
| 340 | grp |= rconfig->devgroup << DEVGROUP_SHIFT; | 357 | grp |= rconfig->devgroup << DEV_GRP_SHIFT; |
| 341 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, | 358 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, |
| 342 | grp, rconfig_addr + DEVGROUP_OFFSET); | 359 | grp, rconfig_addr + DEV_GRP_OFFSET); |
| 343 | if (err < 0) { | 360 | if (err < 0) { |
| 344 | pr_err("TWL4030 failed to program devgroup\n"); | 361 | pr_err("TWL4030 failed to program devgroup\n"); |
| 345 | return err; | 362 | return err; |
| @@ -347,7 +364,7 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig) | |||
| 347 | } | 364 | } |
| 348 | 365 | ||
| 349 | /* Set resource types */ | 366 | /* Set resource types */ |
| 350 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &type, | 367 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &type, |
| 351 | rconfig_addr + TYPE_OFFSET); | 368 | rconfig_addr + TYPE_OFFSET); |
| 352 | if (err < 0) { | 369 | if (err < 0) { |
| 353 | pr_err("TWL4030 Resource %d type could not be read\n", | 370 | pr_err("TWL4030 Resource %d type could not be read\n", |
| @@ -355,23 +372,50 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig) | |||
| 355 | return err; | 372 | return err; |
| 356 | } | 373 | } |
| 357 | 374 | ||
| 358 | if (rconfig->type >= 0) { | 375 | if (rconfig->type != TWL4030_RESCONFIG_UNDEF) { |
| 359 | type &= ~TYPE_MASK; | 376 | type &= ~TYPE_MASK; |
| 360 | type |= rconfig->type << TYPE_SHIFT; | 377 | type |= rconfig->type << TYPE_SHIFT; |
| 361 | } | 378 | } |
| 362 | 379 | ||
| 363 | if (rconfig->type2 >= 0) { | 380 | if (rconfig->type2 != TWL4030_RESCONFIG_UNDEF) { |
| 364 | type &= ~TYPE2_MASK; | 381 | type &= ~TYPE2_MASK; |
| 365 | type |= rconfig->type2 << TYPE2_SHIFT; | 382 | type |= rconfig->type2 << TYPE2_SHIFT; |
| 366 | } | 383 | } |
| 367 | 384 | ||
| 368 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, | 385 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, |
| 369 | type, rconfig_addr + TYPE_OFFSET); | 386 | type, rconfig_addr + TYPE_OFFSET); |
| 370 | if (err < 0) { | 387 | if (err < 0) { |
| 371 | pr_err("TWL4030 failed to program resource type\n"); | 388 | pr_err("TWL4030 failed to program resource type\n"); |
| 372 | return err; | 389 | return err; |
| 373 | } | 390 | } |
| 374 | 391 | ||
| 392 | /* Set remap states */ | ||
| 393 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &remap, | ||
| 394 | rconfig_addr + REMAP_OFFSET); | ||
| 395 | if (err < 0) { | ||
| 396 | pr_err("TWL4030 Resource %d remap could not be read\n", | ||
| 397 | rconfig->resource); | ||
| 398 | return err; | ||
| 399 | } | ||
| 400 | |||
| 401 | if (rconfig->remap_off != TWL4030_RESCONFIG_UNDEF) { | ||
| 402 | remap &= ~OFF_STATE_MASK; | ||
| 403 | remap |= rconfig->remap_off << OFF_STATE_SHIFT; | ||
| 404 | } | ||
| 405 | |||
| 406 | if (rconfig->remap_sleep != TWL4030_RESCONFIG_UNDEF) { | ||
| 407 | remap &= ~SLEEP_STATE_MASK; | ||
| 408 | remap |= rconfig->remap_off << SLEEP_STATE_SHIFT; | ||
| 409 | } | ||
| 410 | |||
| 411 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, | ||
| 412 | remap, | ||
| 413 | rconfig_addr + REMAP_OFFSET); | ||
| 414 | if (err < 0) { | ||
| 415 | pr_err("TWL4030 failed to program remap\n"); | ||
| 416 | return err; | ||
| 417 | } | ||
| 418 | |||
| 375 | return 0; | 419 | return 0; |
| 376 | } | 420 | } |
| 377 | 421 | ||
| @@ -424,12 +468,12 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) | |||
| 424 | struct twl4030_resconfig *resconfig; | 468 | struct twl4030_resconfig *resconfig; |
| 425 | u8 address = twl4030_start_script_address; | 469 | u8 address = twl4030_start_script_address; |
| 426 | 470 | ||
| 427 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1, | 471 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1, |
| 428 | R_PROTECT_KEY); | 472 | R_PROTECT_KEY); |
| 429 | if (err) | 473 | if (err) |
| 430 | goto unlock; | 474 | goto unlock; |
| 431 | 475 | ||
| 432 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2, | 476 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2, |
| 433 | R_PROTECT_KEY); | 477 | R_PROTECT_KEY); |
| 434 | if (err) | 478 | if (err) |
| 435 | goto unlock; | 479 | goto unlock; |
| @@ -452,7 +496,7 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) | |||
| 452 | } | 496 | } |
| 453 | } | 497 | } |
| 454 | 498 | ||
| 455 | err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY); | 499 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY); |
| 456 | if (err) | 500 | if (err) |
| 457 | pr_err("TWL4030 Unable to relock registers\n"); | 501 | pr_err("TWL4030 Unable to relock registers\n"); |
| 458 | return; | 502 | return; |
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c new file mode 100644 index 000000000000..10bf228ad626 --- /dev/null +++ b/drivers/mfd/twl6030-irq.c | |||
| @@ -0,0 +1,299 @@ | |||
| 1 | /* | ||
| 2 | * twl6030-irq.c - TWL6030 irq support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2005-2009 Texas Instruments, Inc. | ||
| 5 | * | ||
| 6 | * Modifications to defer interrupt handling to a kernel thread: | ||
| 7 | * Copyright (C) 2006 MontaVista Software, Inc. | ||
| 8 | * | ||
| 9 | * Based on tlv320aic23.c: | ||
| 10 | * Copyright (c) by Kai Svahn <kai.svahn@nokia.com> | ||
| 11 | * | ||
| 12 | * Code cleanup and modifications to IRQ handler. | ||
| 13 | * by syed khasim <x0khasim@ti.com> | ||
| 14 | * | ||
| 15 | * TWL6030 specific code and IRQ handling changes by | ||
| 16 | * Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com> | ||
| 17 | * Balaji T K <balajitk@ti.com> | ||
| 18 | * | ||
| 19 | * This program is free software; you can redistribute it and/or modify | ||
| 20 | * it under the terms of the GNU General Public License as published by | ||
| 21 | * the Free Software Foundation; either version 2 of the License, or | ||
| 22 | * (at your option) any later version. | ||
| 23 | * | ||
| 24 | * This program is distributed in the hope that it will be useful, | ||
| 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 27 | * GNU General Public License for more details. | ||
| 28 | * | ||
| 29 | * You should have received a copy of the GNU General Public License | ||
| 30 | * along with this program; if not, write to the Free Software | ||
| 31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 32 | */ | ||
| 33 | |||
| 34 | #include <linux/init.h> | ||
| 35 | #include <linux/interrupt.h> | ||
| 36 | #include <linux/irq.h> | ||
| 37 | #include <linux/kthread.h> | ||
| 38 | #include <linux/i2c/twl.h> | ||
| 39 | |||
| 40 | /* | ||
| 41 | * TWL6030 (unlike its predecessors, which had two level interrupt handling) | ||
| 42 | * three interrupt registers INT_STS_A, INT_STS_B and INT_STS_C. | ||
| 43 | * It exposes status bits saying who has raised an interrupt. There are | ||
| 44 | * three mask registers that corresponds to these status registers, that | ||
| 45 | * enables/disables these interrupts. | ||
| 46 | * | ||
| 47 | * We set up IRQs starting at a platform-specified base. An interrupt map table, | ||
| 48 | * specifies mapping between interrupt number and the associated module. | ||
| 49 | * | ||
| 50 | */ | ||
| 51 | |||
| 52 | static int twl6030_interrupt_mapping[24] = { | ||
| 53 | PWR_INTR_OFFSET, /* Bit 0 PWRON */ | ||
| 54 | PWR_INTR_OFFSET, /* Bit 1 RPWRON */ | ||
| 55 | PWR_INTR_OFFSET, /* Bit 2 BAT_VLOW */ | ||
| 56 | RTC_INTR_OFFSET, /* Bit 3 RTC_ALARM */ | ||
| 57 | RTC_INTR_OFFSET, /* Bit 4 RTC_PERIOD */ | ||
| 58 | HOTDIE_INTR_OFFSET, /* Bit 5 HOT_DIE */ | ||
| 59 | SMPSLDO_INTR_OFFSET, /* Bit 6 VXXX_SHORT */ | ||
| 60 | SMPSLDO_INTR_OFFSET, /* Bit 7 VMMC_SHORT */ | ||
| 61 | |||
| 62 | SMPSLDO_INTR_OFFSET, /* Bit 8 VUSIM_SHORT */ | ||
| 63 | BATDETECT_INTR_OFFSET, /* Bit 9 BAT */ | ||
| 64 | SIMDETECT_INTR_OFFSET, /* Bit 10 SIM */ | ||
| 65 | MMCDETECT_INTR_OFFSET, /* Bit 11 MMC */ | ||
| 66 | RSV_INTR_OFFSET, /* Bit 12 Reserved */ | ||
| 67 | MADC_INTR_OFFSET, /* Bit 13 GPADC_RT_EOC */ | ||
| 68 | MADC_INTR_OFFSET, /* Bit 14 GPADC_SW_EOC */ | ||
| 69 | GASGAUGE_INTR_OFFSET, /* Bit 15 CC_AUTOCAL */ | ||
| 70 | |||
| 71 | USBOTG_INTR_OFFSET, /* Bit 16 ID_WKUP */ | ||
| 72 | USBOTG_INTR_OFFSET, /* Bit 17 VBUS_WKUP */ | ||
| 73 | USBOTG_INTR_OFFSET, /* Bit 18 ID */ | ||
| 74 | USBOTG_INTR_OFFSET, /* Bit 19 VBUS */ | ||
| 75 | CHARGER_INTR_OFFSET, /* Bit 20 CHRG_CTRL */ | ||
| 76 | CHARGER_INTR_OFFSET, /* Bit 21 EXT_CHRG */ | ||
| 77 | CHARGER_INTR_OFFSET, /* Bit 22 INT_CHRG */ | ||
| 78 | RSV_INTR_OFFSET, /* Bit 23 Reserved */ | ||
| 79 | }; | ||
| 80 | /*----------------------------------------------------------------------*/ | ||
| 81 | |||
| 82 | static unsigned twl6030_irq_base; | ||
| 83 | |||
| 84 | static struct completion irq_event; | ||
| 85 | |||
| 86 | /* | ||
| 87 | * This thread processes interrupts reported by the Primary Interrupt Handler. | ||
| 88 | */ | ||
| 89 | static int twl6030_irq_thread(void *data) | ||
| 90 | { | ||
| 91 | long irq = (long)data; | ||
| 92 | static unsigned i2c_errors; | ||
| 93 | static const unsigned max_i2c_errors = 100; | ||
| 94 | int ret; | ||
| 95 | |||
| 96 | current->flags |= PF_NOFREEZE; | ||
| 97 | |||
| 98 | while (!kthread_should_stop()) { | ||
| 99 | int i; | ||
| 100 | union { | ||
| 101 | u8 bytes[4]; | ||
| 102 | u32 int_sts; | ||
| 103 | } sts; | ||
| 104 | |||
| 105 | /* Wait for IRQ, then read PIH irq status (also blocking) */ | ||
| 106 | wait_for_completion_interruptible(&irq_event); | ||
| 107 | |||
| 108 | /* read INT_STS_A, B and C in one shot using a burst read */ | ||
| 109 | ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes, | ||
| 110 | REG_INT_STS_A, 3); | ||
| 111 | if (ret) { | ||
| 112 | pr_warning("twl6030: I2C error %d reading PIH ISR\n", | ||
| 113 | ret); | ||
| 114 | if (++i2c_errors >= max_i2c_errors) { | ||
| 115 | printk(KERN_ERR "Maximum I2C error count" | ||
| 116 | " exceeded. Terminating %s.\n", | ||
| 117 | __func__); | ||
| 118 | break; | ||
| 119 | } | ||
| 120 | complete(&irq_event); | ||
| 121 | continue; | ||
| 122 | } | ||
| 123 | |||
| 124 | |||
| 125 | |||
| 126 | sts.bytes[3] = 0; /* Only 24 bits are valid*/ | ||
| 127 | |||
| 128 | for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) { | ||
| 129 | local_irq_disable(); | ||
| 130 | if (sts.int_sts & 0x1) { | ||
| 131 | int module_irq = twl6030_irq_base + | ||
| 132 | twl6030_interrupt_mapping[i]; | ||
| 133 | struct irq_desc *d = irq_to_desc(module_irq); | ||
| 134 | |||
| 135 | if (!d) { | ||
| 136 | pr_err("twl6030: Invalid SIH IRQ: %d\n", | ||
| 137 | module_irq); | ||
| 138 | return -EINVAL; | ||
| 139 | } | ||
| 140 | |||
| 141 | /* These can't be masked ... always warn | ||
| 142 | * if we get any surprises. | ||
| 143 | */ | ||
| 144 | if (d->status & IRQ_DISABLED) | ||
| 145 | note_interrupt(module_irq, d, | ||
| 146 | IRQ_NONE); | ||
| 147 | else | ||
| 148 | d->handle_irq(module_irq, d); | ||
| 149 | |||
| 150 | } | ||
| 151 | local_irq_enable(); | ||
| 152 | } | ||
| 153 | ret = twl_i2c_write(TWL_MODULE_PIH, sts.bytes, | ||
| 154 | REG_INT_STS_A, 3); /* clear INT_STS_A */ | ||
| 155 | if (ret) | ||
| 156 | pr_warning("twl6030: I2C error in clearing PIH ISR\n"); | ||
| 157 | |||
| 158 | enable_irq(irq); | ||
| 159 | } | ||
| 160 | |||
| 161 | return 0; | ||
| 162 | } | ||
| 163 | |||
| 164 | /* | ||
| 165 | * handle_twl6030_int() is the desc->handle method for the twl6030 interrupt. | ||
| 166 | * This is a chained interrupt, so there is no desc->action method for it. | ||
| 167 | * Now we need to query the interrupt controller in the twl6030 to determine | ||
| 168 | * which module is generating the interrupt request. However, we can't do i2c | ||
| 169 | * transactions in interrupt context, so we must defer that work to a kernel | ||
| 170 | * thread. All we do here is acknowledge and mask the interrupt and wakeup | ||
| 171 | * the kernel thread. | ||
| 172 | */ | ||
| 173 | static irqreturn_t handle_twl6030_pih(int irq, void *devid) | ||
| 174 | { | ||
| 175 | disable_irq_nosync(irq); | ||
| 176 | complete(devid); | ||
| 177 | return IRQ_HANDLED; | ||
| 178 | } | ||
| 179 | |||
| 180 | /*----------------------------------------------------------------------*/ | ||
| 181 | |||
| 182 | static inline void activate_irq(int irq) | ||
| 183 | { | ||
| 184 | #ifdef CONFIG_ARM | ||
| 185 | /* ARM requires an extra step to clear IRQ_NOREQUEST, which it | ||
| 186 | * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE. | ||
| 187 | */ | ||
| 188 | set_irq_flags(irq, IRQF_VALID); | ||
| 189 | #else | ||
| 190 | /* same effect on other architectures */ | ||
| 191 | set_irq_noprobe(irq); | ||
| 192 | #endif | ||
| 193 | } | ||
| 194 | |||
| 195 | /*----------------------------------------------------------------------*/ | ||
| 196 | |||
| 197 | static unsigned twl6030_irq_next; | ||
| 198 | |||
| 199 | /*----------------------------------------------------------------------*/ | ||
| 200 | int twl6030_interrupt_unmask(u8 bit_mask, u8 offset) | ||
| 201 | { | ||
| 202 | int ret; | ||
| 203 | u8 unmask_value; | ||
| 204 | ret = twl_i2c_read_u8(TWL_MODULE_PIH, &unmask_value, | ||
| 205 | REG_INT_STS_A + offset); | ||
| 206 | unmask_value &= (~(bit_mask)); | ||
| 207 | ret |= twl_i2c_write_u8(TWL_MODULE_PIH, unmask_value, | ||
| 208 | REG_INT_STS_A + offset); /* unmask INT_MSK_A/B/C */ | ||
| 209 | return ret; | ||
| 210 | } | ||
| 211 | EXPORT_SYMBOL(twl6030_interrupt_unmask); | ||
| 212 | |||
| 213 | int twl6030_interrupt_mask(u8 bit_mask, u8 offset) | ||
| 214 | { | ||
| 215 | int ret; | ||
| 216 | u8 mask_value; | ||
| 217 | ret = twl_i2c_read_u8(TWL_MODULE_PIH, &mask_value, | ||
| 218 | REG_INT_STS_A + offset); | ||
| 219 | mask_value |= (bit_mask); | ||
| 220 | ret |= twl_i2c_write_u8(TWL_MODULE_PIH, mask_value, | ||
| 221 | REG_INT_STS_A + offset); /* mask INT_MSK_A/B/C */ | ||
| 222 | return ret; | ||
| 223 | } | ||
| 224 | EXPORT_SYMBOL(twl6030_interrupt_mask); | ||
| 225 | |||
| 226 | int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | ||
| 227 | { | ||
| 228 | |||
| 229 | int status = 0; | ||
| 230 | int i; | ||
| 231 | struct task_struct *task; | ||
| 232 | int ret; | ||
| 233 | u8 mask[4]; | ||
| 234 | |||
| 235 | static struct irq_chip twl6030_irq_chip; | ||
| 236 | mask[1] = 0xFF; | ||
| 237 | mask[2] = 0xFF; | ||
| 238 | mask[3] = 0xFF; | ||
| 239 | ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], | ||
| 240 | REG_INT_MSK_LINE_A, 3); /* MASK ALL INT LINES */ | ||
| 241 | ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], | ||
| 242 | REG_INT_MSK_STS_A, 3); /* MASK ALL INT STS */ | ||
| 243 | ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], | ||
| 244 | REG_INT_STS_A, 3); /* clear INT_STS_A,B,C */ | ||
| 245 | |||
| 246 | twl6030_irq_base = irq_base; | ||
| 247 | |||
| 248 | /* install an irq handler for each of the modules; | ||
| 249 | * clone dummy irq_chip since PIH can't *do* anything | ||
| 250 | */ | ||
| 251 | twl6030_irq_chip = dummy_irq_chip; | ||
| 252 | twl6030_irq_chip.name = "twl6030"; | ||
| 253 | twl6030_irq_chip.set_type = NULL; | ||
| 254 | |||
| 255 | for (i = irq_base; i < irq_end; i++) { | ||
| 256 | set_irq_chip_and_handler(i, &twl6030_irq_chip, | ||
| 257 | handle_simple_irq); | ||
| 258 | activate_irq(i); | ||
| 259 | } | ||
| 260 | |||
| 261 | twl6030_irq_next = i; | ||
| 262 | pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH", | ||
| 263 | irq_num, irq_base, twl6030_irq_next - 1); | ||
| 264 | |||
| 265 | /* install an irq handler to demultiplex the TWL6030 interrupt */ | ||
| 266 | init_completion(&irq_event); | ||
| 267 | task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq"); | ||
| 268 | if (IS_ERR(task)) { | ||
| 269 | pr_err("twl6030: could not create irq %d thread!\n", irq_num); | ||
| 270 | status = PTR_ERR(task); | ||
| 271 | goto fail_kthread; | ||
| 272 | } | ||
| 273 | |||
| 274 | status = request_irq(irq_num, handle_twl6030_pih, IRQF_DISABLED, | ||
| 275 | "TWL6030-PIH", &irq_event); | ||
| 276 | if (status < 0) { | ||
| 277 | pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status); | ||
| 278 | goto fail_irq; | ||
| 279 | } | ||
| 280 | return status; | ||
| 281 | fail_irq: | ||
| 282 | free_irq(irq_num, &irq_event); | ||
| 283 | |||
| 284 | fail_kthread: | ||
| 285 | for (i = irq_base; i < irq_end; i++) | ||
| 286 | set_irq_chip_and_handler(i, NULL, NULL); | ||
| 287 | return status; | ||
| 288 | } | ||
| 289 | |||
| 290 | int twl6030_exit_irq(void) | ||
| 291 | { | ||
| 292 | |||
| 293 | if (twl6030_irq_base) { | ||
| 294 | pr_err("twl6030: can't yet clean up IRQs?\n"); | ||
| 295 | return -ENOSYS; | ||
| 296 | } | ||
| 297 | return 0; | ||
| 298 | } | ||
| 299 | |||
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 7f27576ca046..223a90c7492f 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c | |||
| @@ -90,9 +90,10 @@ int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = { | |||
| 90 | EXPORT_SYMBOL_GPL(wm831x_isinkv_values); | 90 | EXPORT_SYMBOL_GPL(wm831x_isinkv_values); |
| 91 | 91 | ||
| 92 | enum wm831x_parent { | 92 | enum wm831x_parent { |
| 93 | WM8310 = 0, | 93 | WM8310 = 0x8310, |
| 94 | WM8311 = 1, | 94 | WM8311 = 0x8311, |
| 95 | WM8312 = 2, | 95 | WM8312 = 0x8312, |
| 96 | WM8320 = 0x8320, | ||
| 96 | }; | 97 | }; |
| 97 | 98 | ||
| 98 | static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg) | 99 | static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg) |
| @@ -478,6 +479,20 @@ static struct resource wm831x_dcdc4_resources[] = { | |||
| 478 | }, | 479 | }, |
| 479 | }; | 480 | }; |
| 480 | 481 | ||
| 482 | static struct resource wm8320_dcdc4_buck_resources[] = { | ||
| 483 | { | ||
| 484 | .start = WM831X_DC4_CONTROL, | ||
| 485 | .end = WM832X_DC4_SLEEP_CONTROL, | ||
| 486 | .flags = IORESOURCE_IO, | ||
| 487 | }, | ||
| 488 | { | ||
| 489 | .name = "UV", | ||
| 490 | .start = WM831X_IRQ_UV_DC4, | ||
| 491 | .end = WM831X_IRQ_UV_DC4, | ||
| 492 | .flags = IORESOURCE_IRQ, | ||
| 493 | }, | ||
| 494 | }; | ||
| 495 | |||
| 481 | static struct resource wm831x_gpio_resources[] = { | 496 | static struct resource wm831x_gpio_resources[] = { |
| 482 | { | 497 | { |
| 483 | .start = WM831X_IRQ_GPIO_1, | 498 | .start = WM831X_IRQ_GPIO_1, |
| @@ -1237,6 +1252,137 @@ static struct mfd_cell wm8312_devs[] = { | |||
| 1237 | }, | 1252 | }, |
| 1238 | }; | 1253 | }; |
| 1239 | 1254 | ||
| 1255 | static struct mfd_cell wm8320_devs[] = { | ||
| 1256 | { | ||
| 1257 | .name = "wm831x-backup", | ||
| 1258 | }, | ||
| 1259 | { | ||
| 1260 | .name = "wm831x-buckv", | ||
| 1261 | .id = 1, | ||
| 1262 | .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources), | ||
| 1263 | .resources = wm831x_dcdc1_resources, | ||
| 1264 | }, | ||
| 1265 | { | ||
| 1266 | .name = "wm831x-buckv", | ||
| 1267 | .id = 2, | ||
| 1268 | .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources), | ||
| 1269 | .resources = wm831x_dcdc2_resources, | ||
| 1270 | }, | ||
| 1271 | { | ||
| 1272 | .name = "wm831x-buckp", | ||
| 1273 | .id = 3, | ||
| 1274 | .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources), | ||
| 1275 | .resources = wm831x_dcdc3_resources, | ||
| 1276 | }, | ||
| 1277 | { | ||
| 1278 | .name = "wm831x-buckp", | ||
| 1279 | .id = 4, | ||
| 1280 | .num_resources = ARRAY_SIZE(wm8320_dcdc4_buck_resources), | ||
| 1281 | .resources = wm8320_dcdc4_buck_resources, | ||
| 1282 | }, | ||
| 1283 | { | ||
| 1284 | .name = "wm831x-gpio", | ||
| 1285 | .num_resources = ARRAY_SIZE(wm831x_gpio_resources), | ||
| 1286 | .resources = wm831x_gpio_resources, | ||
| 1287 | }, | ||
| 1288 | { | ||
| 1289 | .name = "wm831x-hwmon", | ||
| 1290 | }, | ||
| 1291 | { | ||
| 1292 | .name = "wm831x-ldo", | ||
| 1293 | .id = 1, | ||
| 1294 | .num_resources = ARRAY_SIZE(wm831x_ldo1_resources), | ||
| 1295 | .resources = wm831x_ldo1_resources, | ||
| 1296 | }, | ||
| 1297 | { | ||
| 1298 | .name = "wm831x-ldo", | ||
| 1299 | .id = 2, | ||
| 1300 | .num_resources = ARRAY_SIZE(wm831x_ldo2_resources), | ||
| 1301 | .resources = wm831x_ldo2_resources, | ||
| 1302 | }, | ||
| 1303 | { | ||
| 1304 | .name = "wm831x-ldo", | ||
| 1305 | .id = 3, | ||
| 1306 | .num_resources = ARRAY_SIZE(wm831x_ldo3_resources), | ||
| 1307 | .resources = wm831x_ldo3_resources, | ||
| 1308 | }, | ||
| 1309 | { | ||
| 1310 | .name = "wm831x-ldo", | ||
| 1311 | .id = 4, | ||
| 1312 | .num_resources = ARRAY_SIZE(wm831x_ldo4_resources), | ||
| 1313 | .resources = wm831x_ldo4_resources, | ||
| 1314 | }, | ||
| 1315 | { | ||
| 1316 | .name = "wm831x-ldo", | ||
| 1317 | .id = 5, | ||
| 1318 | .num_resources = ARRAY_SIZE(wm831x_ldo5_resources), | ||
| 1319 | .resources = wm831x_ldo5_resources, | ||
| 1320 | }, | ||
| 1321 | { | ||
| 1322 | .name = "wm831x-ldo", | ||
| 1323 | .id = 6, | ||
| 1324 | .num_resources = ARRAY_SIZE(wm831x_ldo6_resources), | ||
| 1325 | .resources = wm831x_ldo6_resources, | ||
| 1326 | }, | ||
| 1327 | { | ||
| 1328 | .name = "wm831x-aldo", | ||
| 1329 | .id = 7, | ||
| 1330 | .num_resources = ARRAY_SIZE(wm831x_ldo7_resources), | ||
| 1331 | .resources = wm831x_ldo7_resources, | ||
| 1332 | }, | ||
| 1333 | { | ||
| 1334 | .name = "wm831x-aldo", | ||
| 1335 | .id = 8, | ||
| 1336 | .num_resources = ARRAY_SIZE(wm831x_ldo8_resources), | ||
| 1337 | .resources = wm831x_ldo8_resources, | ||
| 1338 | }, | ||
| 1339 | { | ||
| 1340 | .name = "wm831x-aldo", | ||
| 1341 | .id = 9, | ||
| 1342 | .num_resources = ARRAY_SIZE(wm831x_ldo9_resources), | ||
| 1343 | .resources = wm831x_ldo9_resources, | ||
| 1344 | }, | ||
| 1345 | { | ||
| 1346 | .name = "wm831x-aldo", | ||
| 1347 | .id = 10, | ||
| 1348 | .num_resources = ARRAY_SIZE(wm831x_ldo10_resources), | ||
| 1349 | .resources = wm831x_ldo10_resources, | ||
| 1350 | }, | ||
| 1351 | { | ||
| 1352 | .name = "wm831x-alive-ldo", | ||
| 1353 | .id = 11, | ||
| 1354 | .num_resources = ARRAY_SIZE(wm831x_ldo11_resources), | ||
| 1355 | .resources = wm831x_ldo11_resources, | ||
| 1356 | }, | ||
| 1357 | { | ||
| 1358 | .name = "wm831x-on", | ||
| 1359 | .num_resources = ARRAY_SIZE(wm831x_on_resources), | ||
| 1360 | .resources = wm831x_on_resources, | ||
| 1361 | }, | ||
| 1362 | { | ||
| 1363 | .name = "wm831x-rtc", | ||
| 1364 | .num_resources = ARRAY_SIZE(wm831x_rtc_resources), | ||
| 1365 | .resources = wm831x_rtc_resources, | ||
| 1366 | }, | ||
| 1367 | { | ||
| 1368 | .name = "wm831x-status", | ||
| 1369 | .id = 1, | ||
| 1370 | .num_resources = ARRAY_SIZE(wm831x_status1_resources), | ||
| 1371 | .resources = wm831x_status1_resources, | ||
| 1372 | }, | ||
| 1373 | { | ||
| 1374 | .name = "wm831x-status", | ||
| 1375 | .id = 2, | ||
| 1376 | .num_resources = ARRAY_SIZE(wm831x_status2_resources), | ||
| 1377 | .resources = wm831x_status2_resources, | ||
| 1378 | }, | ||
| 1379 | { | ||
| 1380 | .name = "wm831x-watchdog", | ||
| 1381 | .num_resources = ARRAY_SIZE(wm831x_wdt_resources), | ||
| 1382 | .resources = wm831x_wdt_resources, | ||
| 1383 | }, | ||
| 1384 | }; | ||
| 1385 | |||
| 1240 | static struct mfd_cell backlight_devs[] = { | 1386 | static struct mfd_cell backlight_devs[] = { |
| 1241 | { | 1387 | { |
| 1242 | .name = "wm831x-backlight", | 1388 | .name = "wm831x-backlight", |
| @@ -1282,50 +1428,37 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
| 1282 | goto err; | 1428 | goto err; |
| 1283 | } | 1429 | } |
| 1284 | 1430 | ||
| 1431 | /* Some engineering samples do not have the ID set, rely on | ||
| 1432 | * the device being registered correctly. | ||
| 1433 | */ | ||
| 1434 | if (ret == 0) { | ||
| 1435 | dev_info(wm831x->dev, "Device is an engineering sample\n"); | ||
| 1436 | ret = id; | ||
| 1437 | } | ||
| 1438 | |||
| 1285 | switch (ret) { | 1439 | switch (ret) { |
| 1286 | case 0x8310: | 1440 | case WM8310: |
| 1287 | parent = WM8310; | 1441 | parent = WM8310; |
| 1288 | switch (rev) { | 1442 | wm831x->num_gpio = 16; |
| 1289 | case 0: | 1443 | dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev); |
| 1290 | dev_info(wm831x->dev, "WM8310 revision %c\n", | ||
| 1291 | 'A' + rev); | ||
| 1292 | break; | ||
| 1293 | } | ||
| 1294 | break; | 1444 | break; |
| 1295 | 1445 | ||
| 1296 | case 0x8311: | 1446 | case WM8311: |
| 1297 | parent = WM8311; | 1447 | parent = WM8311; |
| 1298 | switch (rev) { | 1448 | wm831x->num_gpio = 16; |
| 1299 | case 0: | 1449 | dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev); |
| 1300 | dev_info(wm831x->dev, "WM8311 revision %c\n", | ||
| 1301 | 'A' + rev); | ||
| 1302 | break; | ||
| 1303 | } | ||
| 1304 | break; | 1450 | break; |
| 1305 | 1451 | ||
| 1306 | case 0x8312: | 1452 | case WM8312: |
| 1307 | parent = WM8312; | 1453 | parent = WM8312; |
| 1308 | switch (rev) { | 1454 | wm831x->num_gpio = 16; |
| 1309 | case 0: | 1455 | dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev); |
| 1310 | dev_info(wm831x->dev, "WM8312 revision %c\n", | ||
| 1311 | 'A' + rev); | ||
| 1312 | break; | ||
| 1313 | } | ||
| 1314 | break; | 1456 | break; |
| 1315 | 1457 | ||
| 1316 | case 0: | 1458 | case WM8320: |
| 1317 | /* Some engineering samples do not have the ID set, | 1459 | parent = WM8320; |
| 1318 | * rely on the device being registered correctly. | 1460 | wm831x->num_gpio = 12; |
| 1319 | * This will need revisiting for future devices with | 1461 | dev_info(wm831x->dev, "WM8320 revision %c\n", 'A' + rev); |
| 1320 | * multiple dies. | ||
| 1321 | */ | ||
| 1322 | parent = id; | ||
| 1323 | switch (rev) { | ||
| 1324 | case 0: | ||
| 1325 | dev_info(wm831x->dev, "WM831%d ES revision %c\n", | ||
| 1326 | parent, 'A' + rev); | ||
| 1327 | break; | ||
| 1328 | } | ||
| 1329 | break; | 1462 | break; |
| 1330 | 1463 | ||
| 1331 | default: | 1464 | default: |
| @@ -1338,7 +1471,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
| 1338 | * current parts. | 1471 | * current parts. |
| 1339 | */ | 1472 | */ |
| 1340 | if (parent != id) | 1473 | if (parent != id) |
| 1341 | dev_warn(wm831x->dev, "Device was registered as a WM831%lu\n", | 1474 | dev_warn(wm831x->dev, "Device was registered as a WM%lx\n", |
| 1342 | id); | 1475 | id); |
| 1343 | 1476 | ||
| 1344 | /* Bootstrap the user key */ | 1477 | /* Bootstrap the user key */ |
| @@ -1371,18 +1504,24 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
| 1371 | case WM8310: | 1504 | case WM8310: |
| 1372 | ret = mfd_add_devices(wm831x->dev, -1, | 1505 | ret = mfd_add_devices(wm831x->dev, -1, |
| 1373 | wm8310_devs, ARRAY_SIZE(wm8310_devs), | 1506 | wm8310_devs, ARRAY_SIZE(wm8310_devs), |
| 1374 | NULL, 0); | 1507 | NULL, wm831x->irq_base); |
| 1375 | break; | 1508 | break; |
| 1376 | 1509 | ||
| 1377 | case WM8311: | 1510 | case WM8311: |
| 1378 | ret = mfd_add_devices(wm831x->dev, -1, | 1511 | ret = mfd_add_devices(wm831x->dev, -1, |
| 1379 | wm8311_devs, ARRAY_SIZE(wm8311_devs), | 1512 | wm8311_devs, ARRAY_SIZE(wm8311_devs), |
| 1380 | NULL, 0); | 1513 | NULL, wm831x->irq_base); |
| 1381 | break; | 1514 | break; |
| 1382 | 1515 | ||
| 1383 | case WM8312: | 1516 | case WM8312: |
| 1384 | ret = mfd_add_devices(wm831x->dev, -1, | 1517 | ret = mfd_add_devices(wm831x->dev, -1, |
| 1385 | wm8312_devs, ARRAY_SIZE(wm8312_devs), | 1518 | wm8312_devs, ARRAY_SIZE(wm8312_devs), |
| 1519 | NULL, wm831x->irq_base); | ||
| 1520 | break; | ||
| 1521 | |||
| 1522 | case WM8320: | ||
| 1523 | ret = mfd_add_devices(wm831x->dev, -1, | ||
| 1524 | wm8320_devs, ARRAY_SIZE(wm8320_devs), | ||
| 1386 | NULL, 0); | 1525 | NULL, 0); |
| 1387 | break; | 1526 | break; |
| 1388 | 1527 | ||
| @@ -1399,7 +1538,8 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
| 1399 | if (pdata && pdata->backlight) { | 1538 | if (pdata && pdata->backlight) { |
| 1400 | /* Treat errors as non-critical */ | 1539 | /* Treat errors as non-critical */ |
| 1401 | ret = mfd_add_devices(wm831x->dev, -1, backlight_devs, | 1540 | ret = mfd_add_devices(wm831x->dev, -1, backlight_devs, |
| 1402 | ARRAY_SIZE(backlight_devs), NULL, 0); | 1541 | ARRAY_SIZE(backlight_devs), NULL, |
| 1542 | wm831x->irq_base); | ||
| 1403 | if (ret < 0) | 1543 | if (ret < 0) |
| 1404 | dev_err(wm831x->dev, "Failed to add backlight: %d\n", | 1544 | dev_err(wm831x->dev, "Failed to add backlight: %d\n", |
| 1405 | ret); | 1545 | ret); |
| @@ -1511,6 +1651,7 @@ static const struct i2c_device_id wm831x_i2c_id[] = { | |||
| 1511 | { "wm8310", WM8310 }, | 1651 | { "wm8310", WM8310 }, |
| 1512 | { "wm8311", WM8311 }, | 1652 | { "wm8311", WM8311 }, |
| 1513 | { "wm8312", WM8312 }, | 1653 | { "wm8312", WM8312 }, |
| 1654 | { "wm8320", WM8320 }, | ||
| 1514 | { } | 1655 | { } |
| 1515 | }; | 1656 | }; |
| 1516 | MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id); | 1657 | MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id); |
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index ac056ea6b66e..301327697117 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
| 18 | #include <linux/irq.h> | ||
| 18 | #include <linux/mfd/core.h> | 19 | #include <linux/mfd/core.h> |
| 19 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
| 20 | 21 | ||
| @@ -339,110 +340,71 @@ static inline int irq_data_to_mask_reg(struct wm831x_irq_data *irq_data) | |||
| 339 | return WM831X_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg; | 340 | return WM831X_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg; |
| 340 | } | 341 | } |
| 341 | 342 | ||
| 342 | static void __wm831x_enable_irq(struct wm831x *wm831x, int irq) | 343 | static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x, |
| 344 | int irq) | ||
| 343 | { | 345 | { |
| 344 | struct wm831x_irq_data *irq_data = &wm831x_irqs[irq]; | 346 | return &wm831x_irqs[irq - wm831x->irq_base]; |
| 345 | |||
| 346 | wm831x->irq_masks[irq_data->reg - 1] &= ~irq_data->mask; | ||
| 347 | wm831x_reg_write(wm831x, irq_data_to_mask_reg(irq_data), | ||
| 348 | wm831x->irq_masks[irq_data->reg - 1]); | ||
| 349 | } | 347 | } |
| 350 | 348 | ||
| 351 | void wm831x_enable_irq(struct wm831x *wm831x, int irq) | 349 | static void wm831x_irq_lock(unsigned int irq) |
| 352 | { | 350 | { |
| 353 | mutex_lock(&wm831x->irq_lock); | 351 | struct wm831x *wm831x = get_irq_chip_data(irq); |
| 354 | __wm831x_enable_irq(wm831x, irq); | ||
| 355 | mutex_unlock(&wm831x->irq_lock); | ||
| 356 | } | ||
| 357 | EXPORT_SYMBOL_GPL(wm831x_enable_irq); | ||
| 358 | 352 | ||
| 359 | static void __wm831x_disable_irq(struct wm831x *wm831x, int irq) | ||
| 360 | { | ||
| 361 | struct wm831x_irq_data *irq_data = &wm831x_irqs[irq]; | ||
| 362 | |||
| 363 | wm831x->irq_masks[irq_data->reg - 1] |= irq_data->mask; | ||
| 364 | wm831x_reg_write(wm831x, irq_data_to_mask_reg(irq_data), | ||
| 365 | wm831x->irq_masks[irq_data->reg - 1]); | ||
| 366 | } | ||
| 367 | |||
| 368 | void wm831x_disable_irq(struct wm831x *wm831x, int irq) | ||
| 369 | { | ||
| 370 | mutex_lock(&wm831x->irq_lock); | 353 | mutex_lock(&wm831x->irq_lock); |
| 371 | __wm831x_disable_irq(wm831x, irq); | ||
| 372 | mutex_unlock(&wm831x->irq_lock); | ||
| 373 | } | 354 | } |
| 374 | EXPORT_SYMBOL_GPL(wm831x_disable_irq); | ||
| 375 | 355 | ||
| 376 | int wm831x_request_irq(struct wm831x *wm831x, | 356 | static void wm831x_irq_sync_unlock(unsigned int irq) |
| 377 | unsigned int irq, irq_handler_t handler, | ||
| 378 | unsigned long flags, const char *name, | ||
| 379 | void *dev) | ||
| 380 | { | 357 | { |
| 381 | int ret = 0; | 358 | struct wm831x *wm831x = get_irq_chip_data(irq); |
| 382 | 359 | int i; | |
| 383 | if (irq < 0 || irq >= WM831X_NUM_IRQS) | 360 | |
| 384 | return -EINVAL; | 361 | for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) { |
| 385 | 362 | /* If there's been a change in the mask write it back | |
| 386 | mutex_lock(&wm831x->irq_lock); | 363 | * to the hardware. */ |
| 387 | 364 | if (wm831x->irq_masks_cur[i] != wm831x->irq_masks_cache[i]) { | |
| 388 | if (wm831x_irqs[irq].handler) { | 365 | wm831x->irq_masks_cache[i] = wm831x->irq_masks_cur[i]; |
| 389 | dev_err(wm831x->dev, "Already have handler for IRQ %d\n", irq); | 366 | wm831x_reg_write(wm831x, |
| 390 | ret = -EINVAL; | 367 | WM831X_INTERRUPT_STATUS_1_MASK + i, |
| 391 | goto out; | 368 | wm831x->irq_masks_cur[i]); |
| 369 | } | ||
| 392 | } | 370 | } |
| 393 | 371 | ||
| 394 | wm831x_irqs[irq].handler = handler; | ||
| 395 | wm831x_irqs[irq].handler_data = dev; | ||
| 396 | |||
| 397 | __wm831x_enable_irq(wm831x, irq); | ||
| 398 | |||
| 399 | out: | ||
| 400 | mutex_unlock(&wm831x->irq_lock); | 372 | mutex_unlock(&wm831x->irq_lock); |
| 401 | |||
| 402 | return ret; | ||
| 403 | } | 373 | } |
| 404 | EXPORT_SYMBOL_GPL(wm831x_request_irq); | ||
| 405 | 374 | ||
| 406 | void wm831x_free_irq(struct wm831x *wm831x, unsigned int irq, void *data) | 375 | static void wm831x_irq_unmask(unsigned int irq) |
| 407 | { | 376 | { |
| 408 | if (irq < 0 || irq >= WM831X_NUM_IRQS) | 377 | struct wm831x *wm831x = get_irq_chip_data(irq); |
| 409 | return; | 378 | struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq); |
| 410 | |||
| 411 | mutex_lock(&wm831x->irq_lock); | ||
| 412 | 379 | ||
| 413 | wm831x_irqs[irq].handler = NULL; | 380 | wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; |
| 414 | wm831x_irqs[irq].handler_data = NULL; | ||
| 415 | |||
| 416 | __wm831x_disable_irq(wm831x, irq); | ||
| 417 | |||
| 418 | mutex_unlock(&wm831x->irq_lock); | ||
| 419 | } | 381 | } |
| 420 | EXPORT_SYMBOL_GPL(wm831x_free_irq); | ||
| 421 | 382 | ||
| 422 | 383 | static void wm831x_irq_mask(unsigned int irq) | |
| 423 | static void wm831x_handle_irq(struct wm831x *wm831x, int irq, int status) | ||
| 424 | { | 384 | { |
| 425 | struct wm831x_irq_data *irq_data = &wm831x_irqs[irq]; | 385 | struct wm831x *wm831x = get_irq_chip_data(irq); |
| 426 | 386 | struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq); | |
| 427 | if (irq_data->handler) { | 387 | |
| 428 | irq_data->handler(irq, irq_data->handler_data); | 388 | wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; |
| 429 | wm831x_reg_write(wm831x, irq_data_to_status_reg(irq_data), | ||
| 430 | irq_data->mask); | ||
| 431 | } else { | ||
| 432 | dev_err(wm831x->dev, "Unhandled IRQ %d, masking\n", irq); | ||
| 433 | __wm831x_disable_irq(wm831x, irq); | ||
| 434 | } | ||
| 435 | } | 389 | } |
| 436 | 390 | ||
| 437 | /* Main interrupt handling occurs in a workqueue since we need | 391 | static struct irq_chip wm831x_irq_chip = { |
| 438 | * interrupts enabled to interact with the chip. */ | 392 | .name = "wm831x", |
| 439 | static void wm831x_irq_worker(struct work_struct *work) | 393 | .bus_lock = wm831x_irq_lock, |
| 394 | .bus_sync_unlock = wm831x_irq_sync_unlock, | ||
| 395 | .mask = wm831x_irq_mask, | ||
| 396 | .unmask = wm831x_irq_unmask, | ||
| 397 | }; | ||
| 398 | |||
| 399 | /* The processing of the primary interrupt occurs in a thread so that | ||
| 400 | * we can interact with the device over I2C or SPI. */ | ||
| 401 | static irqreturn_t wm831x_irq_thread(int irq, void *data) | ||
| 440 | { | 402 | { |
| 441 | struct wm831x *wm831x = container_of(work, struct wm831x, irq_work); | 403 | struct wm831x *wm831x = data; |
| 442 | unsigned int i; | 404 | unsigned int i; |
| 443 | int primary; | 405 | int primary; |
| 444 | int status_regs[5]; | 406 | int status_regs[WM831X_NUM_IRQ_REGS] = { 0 }; |
| 445 | int read[5] = { 0 }; | 407 | int read[WM831X_NUM_IRQ_REGS] = { 0 }; |
| 446 | int *status; | 408 | int *status; |
| 447 | 409 | ||
| 448 | primary = wm831x_reg_read(wm831x, WM831X_SYSTEM_INTERRUPTS); | 410 | primary = wm831x_reg_read(wm831x, WM831X_SYSTEM_INTERRUPTS); |
| @@ -452,8 +414,6 @@ static void wm831x_irq_worker(struct work_struct *work) | |||
| 452 | goto out; | 414 | goto out; |
| 453 | } | 415 | } |
| 454 | 416 | ||
| 455 | mutex_lock(&wm831x->irq_lock); | ||
| 456 | |||
| 457 | for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { | 417 | for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { |
| 458 | int offset = wm831x_irqs[i].reg - 1; | 418 | int offset = wm831x_irqs[i].reg - 1; |
| 459 | 419 | ||
| @@ -471,41 +431,34 @@ static void wm831x_irq_worker(struct work_struct *work) | |||
| 471 | dev_err(wm831x->dev, | 431 | dev_err(wm831x->dev, |
| 472 | "Failed to read IRQ status: %d\n", | 432 | "Failed to read IRQ status: %d\n", |
| 473 | *status); | 433 | *status); |
| 474 | goto out_lock; | 434 | goto out; |
| 475 | } | 435 | } |
| 476 | 436 | ||
| 477 | /* Mask out the disabled IRQs */ | ||
| 478 | *status &= ~wm831x->irq_masks[offset]; | ||
| 479 | read[offset] = 1; | 437 | read[offset] = 1; |
| 480 | } | 438 | } |
| 481 | 439 | ||
| 482 | if (*status & wm831x_irqs[i].mask) | 440 | /* Report it if it isn't masked, or forget the status. */ |
| 483 | wm831x_handle_irq(wm831x, i, *status); | 441 | if ((*status & ~wm831x->irq_masks_cur[offset]) |
| 442 | & wm831x_irqs[i].mask) | ||
| 443 | handle_nested_irq(wm831x->irq_base + i); | ||
| 444 | else | ||
| 445 | *status &= ~wm831x_irqs[i].mask; | ||
| 484 | } | 446 | } |
| 485 | 447 | ||
| 486 | out_lock: | ||
| 487 | mutex_unlock(&wm831x->irq_lock); | ||
| 488 | out: | 448 | out: |
| 489 | enable_irq(wm831x->irq); | 449 | for (i = 0; i < ARRAY_SIZE(status_regs); i++) { |
| 490 | } | 450 | if (status_regs[i]) |
| 491 | 451 | wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1 + i, | |
| 492 | 452 | status_regs[i]); | |
| 493 | static irqreturn_t wm831x_cpu_irq(int irq, void *data) | 453 | } |
| 494 | { | ||
| 495 | struct wm831x *wm831x = data; | ||
| 496 | |||
| 497 | /* Shut the interrupt to the CPU up and schedule the actual | ||
| 498 | * handler; we can't check that the IRQ is asserted. */ | ||
| 499 | disable_irq_nosync(irq); | ||
| 500 | |||
| 501 | queue_work(wm831x->irq_wq, &wm831x->irq_work); | ||
| 502 | 454 | ||
| 503 | return IRQ_HANDLED; | 455 | return IRQ_HANDLED; |
| 504 | } | 456 | } |
| 505 | 457 | ||
| 506 | int wm831x_irq_init(struct wm831x *wm831x, int irq) | 458 | int wm831x_irq_init(struct wm831x *wm831x, int irq) |
| 507 | { | 459 | { |
| 508 | int i, ret; | 460 | struct wm831x_pdata *pdata = wm831x->dev->platform_data; |
| 461 | int i, cur_irq, ret; | ||
| 509 | 462 | ||
| 510 | mutex_init(&wm831x->irq_lock); | 463 | mutex_init(&wm831x->irq_lock); |
| 511 | 464 | ||
| @@ -515,41 +468,53 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) | |||
| 515 | return 0; | 468 | return 0; |
| 516 | } | 469 | } |
| 517 | 470 | ||
| 518 | 471 | if (!pdata || !pdata->irq_base) { | |
| 519 | wm831x->irq_wq = create_singlethread_workqueue("wm831x-irq"); | 472 | dev_err(wm831x->dev, |
| 520 | if (!wm831x->irq_wq) { | 473 | "No interrupt base specified, no interrupts\n"); |
| 521 | dev_err(wm831x->dev, "Failed to allocate IRQ worker\n"); | 474 | return 0; |
| 522 | return -ESRCH; | ||
| 523 | } | 475 | } |
| 524 | 476 | ||
| 525 | wm831x->irq = irq; | 477 | wm831x->irq = irq; |
| 526 | INIT_WORK(&wm831x->irq_work, wm831x_irq_worker); | 478 | wm831x->irq_base = pdata->irq_base; |
| 527 | 479 | ||
| 528 | /* Mask the individual interrupt sources */ | 480 | /* Mask the individual interrupt sources */ |
| 529 | for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks); i++) { | 481 | for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) { |
| 530 | wm831x->irq_masks[i] = 0xffff; | 482 | wm831x->irq_masks_cur[i] = 0xffff; |
| 483 | wm831x->irq_masks_cache[i] = 0xffff; | ||
| 531 | wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1_MASK + i, | 484 | wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1_MASK + i, |
| 532 | 0xffff); | 485 | 0xffff); |
| 533 | } | 486 | } |
| 534 | 487 | ||
| 535 | /* Enable top level interrupts, we mask at secondary level */ | 488 | /* Register them with genirq */ |
| 536 | wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0); | 489 | for (cur_irq = wm831x->irq_base; |
| 490 | cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base; | ||
| 491 | cur_irq++) { | ||
| 492 | set_irq_chip_data(cur_irq, wm831x); | ||
| 493 | set_irq_chip_and_handler(cur_irq, &wm831x_irq_chip, | ||
| 494 | handle_edge_irq); | ||
| 495 | set_irq_nested_thread(cur_irq, 1); | ||
| 496 | |||
| 497 | /* ARM needs us to explicitly flag the IRQ as valid | ||
| 498 | * and will set them noprobe when we do so. */ | ||
| 499 | #ifdef CONFIG_ARM | ||
| 500 | set_irq_flags(cur_irq, IRQF_VALID); | ||
| 501 | #else | ||
| 502 | set_irq_noprobe(cur_irq); | ||
| 503 | #endif | ||
| 504 | } | ||
| 537 | 505 | ||
| 538 | /* We're good to go. We set IRQF_SHARED since there's a | 506 | ret = request_threaded_irq(irq, NULL, wm831x_irq_thread, |
| 539 | * chance the driver will interoperate with another driver but | 507 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
| 540 | * the need to disable the IRQ while handing via I2C/SPI means | 508 | "wm831x", wm831x); |
| 541 | * that this may break and performance will be impacted. If | ||
| 542 | * this does happen it's a hardware design issue and the only | ||
| 543 | * other alternative would be polling. | ||
| 544 | */ | ||
| 545 | ret = request_irq(irq, wm831x_cpu_irq, IRQF_TRIGGER_LOW | IRQF_SHARED, | ||
| 546 | "wm831x", wm831x); | ||
| 547 | if (ret != 0) { | 509 | if (ret != 0) { |
| 548 | dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n", | 510 | dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n", |
| 549 | irq, ret); | 511 | irq, ret); |
| 550 | return ret; | 512 | return ret; |
| 551 | } | 513 | } |
| 552 | 514 | ||
| 515 | /* Enable top level interrupts, we mask at secondary level */ | ||
| 516 | wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0); | ||
| 517 | |||
| 553 | return 0; | 518 | return 0; |
| 554 | } | 519 | } |
| 555 | 520 | ||
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c index ba27c9dc1ad3..8485a7018060 100644 --- a/drivers/mfd/wm8350-core.c +++ b/drivers/mfd/wm8350-core.c | |||
| @@ -337,733 +337,6 @@ int wm8350_reg_unlock(struct wm8350 *wm8350) | |||
| 337 | } | 337 | } |
| 338 | EXPORT_SYMBOL_GPL(wm8350_reg_unlock); | 338 | EXPORT_SYMBOL_GPL(wm8350_reg_unlock); |
| 339 | 339 | ||
| 340 | static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq) | ||
| 341 | { | ||
| 342 | mutex_lock(&wm8350->irq_mutex); | ||
| 343 | |||
| 344 | if (wm8350->irq[irq].handler) | ||
| 345 | wm8350->irq[irq].handler(wm8350, irq, wm8350->irq[irq].data); | ||
| 346 | else { | ||
| 347 | dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n", | ||
| 348 | irq); | ||
| 349 | wm8350_mask_irq(wm8350, irq); | ||
| 350 | } | ||
| 351 | |||
| 352 | mutex_unlock(&wm8350->irq_mutex); | ||
| 353 | } | ||
| 354 | |||
| 355 | /* | ||
| 356 | * This is a threaded IRQ handler so can access I2C/SPI. Since all | ||
| 357 | * interrupts are clear on read the IRQ line will be reasserted and | ||
| 358 | * the physical IRQ will be handled again if another interrupt is | ||
| 359 | * asserted while we run - in the normal course of events this is a | ||
| 360 | * rare occurrence so we save I2C/SPI reads. | ||
| 361 | */ | ||
| 362 | static irqreturn_t wm8350_irq(int irq, void *data) | ||
| 363 | { | ||
| 364 | struct wm8350 *wm8350 = data; | ||
| 365 | u16 level_one, status1, status2, comp; | ||
| 366 | |||
| 367 | /* TODO: Use block reads to improve performance? */ | ||
| 368 | level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS) | ||
| 369 | & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK); | ||
| 370 | status1 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_1) | ||
| 371 | & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_1_MASK); | ||
| 372 | status2 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_2) | ||
| 373 | & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_2_MASK); | ||
| 374 | comp = wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS) | ||
| 375 | & ~wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK); | ||
| 376 | |||
| 377 | /* over current */ | ||
| 378 | if (level_one & WM8350_OC_INT) { | ||
| 379 | u16 oc; | ||
| 380 | |||
| 381 | oc = wm8350_reg_read(wm8350, WM8350_OVER_CURRENT_INT_STATUS); | ||
| 382 | oc &= ~wm8350_reg_read(wm8350, | ||
| 383 | WM8350_OVER_CURRENT_INT_STATUS_MASK); | ||
| 384 | |||
| 385 | if (oc & WM8350_OC_LS_EINT) /* limit switch */ | ||
| 386 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_OC_LS); | ||
| 387 | } | ||
| 388 | |||
| 389 | /* under voltage */ | ||
| 390 | if (level_one & WM8350_UV_INT) { | ||
| 391 | u16 uv; | ||
| 392 | |||
| 393 | uv = wm8350_reg_read(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS); | ||
| 394 | uv &= ~wm8350_reg_read(wm8350, | ||
| 395 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK); | ||
| 396 | |||
| 397 | if (uv & WM8350_UV_DC1_EINT) | ||
| 398 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC1); | ||
| 399 | if (uv & WM8350_UV_DC2_EINT) | ||
| 400 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC2); | ||
| 401 | if (uv & WM8350_UV_DC3_EINT) | ||
| 402 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC3); | ||
| 403 | if (uv & WM8350_UV_DC4_EINT) | ||
| 404 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC4); | ||
| 405 | if (uv & WM8350_UV_DC5_EINT) | ||
| 406 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC5); | ||
| 407 | if (uv & WM8350_UV_DC6_EINT) | ||
| 408 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC6); | ||
| 409 | if (uv & WM8350_UV_LDO1_EINT) | ||
| 410 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO1); | ||
| 411 | if (uv & WM8350_UV_LDO2_EINT) | ||
| 412 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO2); | ||
| 413 | if (uv & WM8350_UV_LDO3_EINT) | ||
| 414 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO3); | ||
| 415 | if (uv & WM8350_UV_LDO4_EINT) | ||
| 416 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO4); | ||
| 417 | } | ||
| 418 | |||
| 419 | /* charger, RTC */ | ||
| 420 | if (status1) { | ||
| 421 | if (status1 & WM8350_CHG_BAT_HOT_EINT) | ||
| 422 | wm8350_irq_call_handler(wm8350, | ||
| 423 | WM8350_IRQ_CHG_BAT_HOT); | ||
| 424 | if (status1 & WM8350_CHG_BAT_COLD_EINT) | ||
| 425 | wm8350_irq_call_handler(wm8350, | ||
| 426 | WM8350_IRQ_CHG_BAT_COLD); | ||
| 427 | if (status1 & WM8350_CHG_BAT_FAIL_EINT) | ||
| 428 | wm8350_irq_call_handler(wm8350, | ||
| 429 | WM8350_IRQ_CHG_BAT_FAIL); | ||
| 430 | if (status1 & WM8350_CHG_TO_EINT) | ||
| 431 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_TO); | ||
| 432 | if (status1 & WM8350_CHG_END_EINT) | ||
| 433 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_END); | ||
| 434 | if (status1 & WM8350_CHG_START_EINT) | ||
| 435 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_START); | ||
| 436 | if (status1 & WM8350_CHG_FAST_RDY_EINT) | ||
| 437 | wm8350_irq_call_handler(wm8350, | ||
| 438 | WM8350_IRQ_CHG_FAST_RDY); | ||
| 439 | if (status1 & WM8350_CHG_VBATT_LT_3P9_EINT) | ||
| 440 | wm8350_irq_call_handler(wm8350, | ||
| 441 | WM8350_IRQ_CHG_VBATT_LT_3P9); | ||
| 442 | if (status1 & WM8350_CHG_VBATT_LT_3P1_EINT) | ||
| 443 | wm8350_irq_call_handler(wm8350, | ||
| 444 | WM8350_IRQ_CHG_VBATT_LT_3P1); | ||
| 445 | if (status1 & WM8350_CHG_VBATT_LT_2P85_EINT) | ||
| 446 | wm8350_irq_call_handler(wm8350, | ||
| 447 | WM8350_IRQ_CHG_VBATT_LT_2P85); | ||
| 448 | if (status1 & WM8350_RTC_ALM_EINT) | ||
| 449 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_ALM); | ||
| 450 | if (status1 & WM8350_RTC_SEC_EINT) | ||
| 451 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_SEC); | ||
| 452 | if (status1 & WM8350_RTC_PER_EINT) | ||
| 453 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_PER); | ||
| 454 | } | ||
| 455 | |||
| 456 | /* current sink, system, aux adc */ | ||
| 457 | if (status2) { | ||
| 458 | if (status2 & WM8350_CS1_EINT) | ||
| 459 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS1); | ||
| 460 | if (status2 & WM8350_CS2_EINT) | ||
| 461 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS2); | ||
| 462 | |||
| 463 | if (status2 & WM8350_SYS_HYST_COMP_FAIL_EINT) | ||
| 464 | wm8350_irq_call_handler(wm8350, | ||
| 465 | WM8350_IRQ_SYS_HYST_COMP_FAIL); | ||
| 466 | if (status2 & WM8350_SYS_CHIP_GT115_EINT) | ||
| 467 | wm8350_irq_call_handler(wm8350, | ||
| 468 | WM8350_IRQ_SYS_CHIP_GT115); | ||
| 469 | if (status2 & WM8350_SYS_CHIP_GT140_EINT) | ||
| 470 | wm8350_irq_call_handler(wm8350, | ||
| 471 | WM8350_IRQ_SYS_CHIP_GT140); | ||
| 472 | if (status2 & WM8350_SYS_WDOG_TO_EINT) | ||
| 473 | wm8350_irq_call_handler(wm8350, | ||
| 474 | WM8350_IRQ_SYS_WDOG_TO); | ||
| 475 | |||
| 476 | if (status2 & WM8350_AUXADC_DATARDY_EINT) | ||
| 477 | wm8350_irq_call_handler(wm8350, | ||
| 478 | WM8350_IRQ_AUXADC_DATARDY); | ||
| 479 | if (status2 & WM8350_AUXADC_DCOMP4_EINT) | ||
| 480 | wm8350_irq_call_handler(wm8350, | ||
| 481 | WM8350_IRQ_AUXADC_DCOMP4); | ||
| 482 | if (status2 & WM8350_AUXADC_DCOMP3_EINT) | ||
| 483 | wm8350_irq_call_handler(wm8350, | ||
| 484 | WM8350_IRQ_AUXADC_DCOMP3); | ||
| 485 | if (status2 & WM8350_AUXADC_DCOMP2_EINT) | ||
| 486 | wm8350_irq_call_handler(wm8350, | ||
| 487 | WM8350_IRQ_AUXADC_DCOMP2); | ||
| 488 | if (status2 & WM8350_AUXADC_DCOMP1_EINT) | ||
| 489 | wm8350_irq_call_handler(wm8350, | ||
| 490 | WM8350_IRQ_AUXADC_DCOMP1); | ||
| 491 | |||
| 492 | if (status2 & WM8350_USB_LIMIT_EINT) | ||
| 493 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_USB_LIMIT); | ||
| 494 | } | ||
| 495 | |||
| 496 | /* wake, codec, ext */ | ||
| 497 | if (comp) { | ||
| 498 | if (comp & WM8350_WKUP_OFF_STATE_EINT) | ||
| 499 | wm8350_irq_call_handler(wm8350, | ||
| 500 | WM8350_IRQ_WKUP_OFF_STATE); | ||
| 501 | if (comp & WM8350_WKUP_HIB_STATE_EINT) | ||
| 502 | wm8350_irq_call_handler(wm8350, | ||
| 503 | WM8350_IRQ_WKUP_HIB_STATE); | ||
| 504 | if (comp & WM8350_WKUP_CONV_FAULT_EINT) | ||
| 505 | wm8350_irq_call_handler(wm8350, | ||
| 506 | WM8350_IRQ_WKUP_CONV_FAULT); | ||
| 507 | if (comp & WM8350_WKUP_WDOG_RST_EINT) | ||
| 508 | wm8350_irq_call_handler(wm8350, | ||
| 509 | WM8350_IRQ_WKUP_WDOG_RST); | ||
| 510 | if (comp & WM8350_WKUP_GP_PWR_ON_EINT) | ||
| 511 | wm8350_irq_call_handler(wm8350, | ||
| 512 | WM8350_IRQ_WKUP_GP_PWR_ON); | ||
| 513 | if (comp & WM8350_WKUP_ONKEY_EINT) | ||
| 514 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_WKUP_ONKEY); | ||
| 515 | if (comp & WM8350_WKUP_GP_WAKEUP_EINT) | ||
| 516 | wm8350_irq_call_handler(wm8350, | ||
| 517 | WM8350_IRQ_WKUP_GP_WAKEUP); | ||
| 518 | |||
| 519 | if (comp & WM8350_CODEC_JCK_DET_L_EINT) | ||
| 520 | wm8350_irq_call_handler(wm8350, | ||
| 521 | WM8350_IRQ_CODEC_JCK_DET_L); | ||
| 522 | if (comp & WM8350_CODEC_JCK_DET_R_EINT) | ||
| 523 | wm8350_irq_call_handler(wm8350, | ||
| 524 | WM8350_IRQ_CODEC_JCK_DET_R); | ||
| 525 | if (comp & WM8350_CODEC_MICSCD_EINT) | ||
| 526 | wm8350_irq_call_handler(wm8350, | ||
| 527 | WM8350_IRQ_CODEC_MICSCD); | ||
| 528 | if (comp & WM8350_CODEC_MICD_EINT) | ||
| 529 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_CODEC_MICD); | ||
| 530 | |||
| 531 | if (comp & WM8350_EXT_USB_FB_EINT) | ||
| 532 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_USB_FB); | ||
| 533 | if (comp & WM8350_EXT_WALL_FB_EINT) | ||
| 534 | wm8350_irq_call_handler(wm8350, | ||
| 535 | WM8350_IRQ_EXT_WALL_FB); | ||
| 536 | if (comp & WM8350_EXT_BAT_FB_EINT) | ||
| 537 | wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_BAT_FB); | ||
| 538 | } | ||
| 539 | |||
| 540 | if (level_one & WM8350_GP_INT) { | ||
| 541 | int i; | ||
| 542 | u16 gpio; | ||
| 543 | |||
| 544 | gpio = wm8350_reg_read(wm8350, WM8350_GPIO_INT_STATUS); | ||
| 545 | gpio &= ~wm8350_reg_read(wm8350, | ||
| 546 | WM8350_GPIO_INT_STATUS_MASK); | ||
| 547 | |||
| 548 | for (i = 0; i < 12; i++) { | ||
| 549 | if (gpio & (1 << i)) | ||
| 550 | wm8350_irq_call_handler(wm8350, | ||
| 551 | WM8350_IRQ_GPIO(i)); | ||
| 552 | } | ||
| 553 | } | ||
| 554 | |||
| 555 | return IRQ_HANDLED; | ||
| 556 | } | ||
| 557 | |||
| 558 | int wm8350_register_irq(struct wm8350 *wm8350, int irq, | ||
| 559 | void (*handler) (struct wm8350 *, int, void *), | ||
| 560 | void *data) | ||
| 561 | { | ||
| 562 | if (irq < 0 || irq > WM8350_NUM_IRQ || !handler) | ||
| 563 | return -EINVAL; | ||
| 564 | |||
| 565 | if (wm8350->irq[irq].handler) | ||
| 566 | return -EBUSY; | ||
| 567 | |||
| 568 | mutex_lock(&wm8350->irq_mutex); | ||
| 569 | wm8350->irq[irq].handler = handler; | ||
| 570 | wm8350->irq[irq].data = data; | ||
| 571 | mutex_unlock(&wm8350->irq_mutex); | ||
| 572 | |||
| 573 | return 0; | ||
| 574 | } | ||
| 575 | EXPORT_SYMBOL_GPL(wm8350_register_irq); | ||
| 576 | |||
| 577 | int wm8350_free_irq(struct wm8350 *wm8350, int irq) | ||
| 578 | { | ||
| 579 | if (irq < 0 || irq > WM8350_NUM_IRQ) | ||
| 580 | return -EINVAL; | ||
| 581 | |||
| 582 | mutex_lock(&wm8350->irq_mutex); | ||
| 583 | wm8350->irq[irq].handler = NULL; | ||
| 584 | mutex_unlock(&wm8350->irq_mutex); | ||
| 585 | return 0; | ||
| 586 | } | ||
| 587 | EXPORT_SYMBOL_GPL(wm8350_free_irq); | ||
| 588 | |||
| 589 | int wm8350_mask_irq(struct wm8350 *wm8350, int irq) | ||
| 590 | { | ||
| 591 | switch (irq) { | ||
| 592 | case WM8350_IRQ_CHG_BAT_HOT: | ||
| 593 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 594 | WM8350_IM_CHG_BAT_HOT_EINT); | ||
| 595 | case WM8350_IRQ_CHG_BAT_COLD: | ||
| 596 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 597 | WM8350_IM_CHG_BAT_COLD_EINT); | ||
| 598 | case WM8350_IRQ_CHG_BAT_FAIL: | ||
| 599 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 600 | WM8350_IM_CHG_BAT_FAIL_EINT); | ||
| 601 | case WM8350_IRQ_CHG_TO: | ||
| 602 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 603 | WM8350_IM_CHG_TO_EINT); | ||
| 604 | case WM8350_IRQ_CHG_END: | ||
| 605 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 606 | WM8350_IM_CHG_END_EINT); | ||
| 607 | case WM8350_IRQ_CHG_START: | ||
| 608 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 609 | WM8350_IM_CHG_START_EINT); | ||
| 610 | case WM8350_IRQ_CHG_FAST_RDY: | ||
| 611 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 612 | WM8350_IM_CHG_FAST_RDY_EINT); | ||
| 613 | case WM8350_IRQ_RTC_PER: | ||
| 614 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 615 | WM8350_IM_RTC_PER_EINT); | ||
| 616 | case WM8350_IRQ_RTC_SEC: | ||
| 617 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 618 | WM8350_IM_RTC_SEC_EINT); | ||
| 619 | case WM8350_IRQ_RTC_ALM: | ||
| 620 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 621 | WM8350_IM_RTC_ALM_EINT); | ||
| 622 | case WM8350_IRQ_CHG_VBATT_LT_3P9: | ||
| 623 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 624 | WM8350_IM_CHG_VBATT_LT_3P9_EINT); | ||
| 625 | case WM8350_IRQ_CHG_VBATT_LT_3P1: | ||
| 626 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 627 | WM8350_IM_CHG_VBATT_LT_3P1_EINT); | ||
| 628 | case WM8350_IRQ_CHG_VBATT_LT_2P85: | ||
| 629 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 630 | WM8350_IM_CHG_VBATT_LT_2P85_EINT); | ||
| 631 | case WM8350_IRQ_CS1: | ||
| 632 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 633 | WM8350_IM_CS1_EINT); | ||
| 634 | case WM8350_IRQ_CS2: | ||
| 635 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 636 | WM8350_IM_CS2_EINT); | ||
| 637 | case WM8350_IRQ_USB_LIMIT: | ||
| 638 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 639 | WM8350_IM_USB_LIMIT_EINT); | ||
| 640 | case WM8350_IRQ_AUXADC_DATARDY: | ||
| 641 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 642 | WM8350_IM_AUXADC_DATARDY_EINT); | ||
| 643 | case WM8350_IRQ_AUXADC_DCOMP4: | ||
| 644 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 645 | WM8350_IM_AUXADC_DCOMP4_EINT); | ||
| 646 | case WM8350_IRQ_AUXADC_DCOMP3: | ||
| 647 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 648 | WM8350_IM_AUXADC_DCOMP3_EINT); | ||
| 649 | case WM8350_IRQ_AUXADC_DCOMP2: | ||
| 650 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 651 | WM8350_IM_AUXADC_DCOMP2_EINT); | ||
| 652 | case WM8350_IRQ_AUXADC_DCOMP1: | ||
| 653 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 654 | WM8350_IM_AUXADC_DCOMP1_EINT); | ||
| 655 | case WM8350_IRQ_SYS_HYST_COMP_FAIL: | ||
| 656 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 657 | WM8350_IM_SYS_HYST_COMP_FAIL_EINT); | ||
| 658 | case WM8350_IRQ_SYS_CHIP_GT115: | ||
| 659 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 660 | WM8350_IM_SYS_CHIP_GT115_EINT); | ||
| 661 | case WM8350_IRQ_SYS_CHIP_GT140: | ||
| 662 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 663 | WM8350_IM_SYS_CHIP_GT140_EINT); | ||
| 664 | case WM8350_IRQ_SYS_WDOG_TO: | ||
| 665 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 666 | WM8350_IM_SYS_WDOG_TO_EINT); | ||
| 667 | case WM8350_IRQ_UV_LDO4: | ||
| 668 | return wm8350_set_bits(wm8350, | ||
| 669 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 670 | WM8350_IM_UV_LDO4_EINT); | ||
| 671 | case WM8350_IRQ_UV_LDO3: | ||
| 672 | return wm8350_set_bits(wm8350, | ||
| 673 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 674 | WM8350_IM_UV_LDO3_EINT); | ||
| 675 | case WM8350_IRQ_UV_LDO2: | ||
| 676 | return wm8350_set_bits(wm8350, | ||
| 677 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 678 | WM8350_IM_UV_LDO2_EINT); | ||
| 679 | case WM8350_IRQ_UV_LDO1: | ||
| 680 | return wm8350_set_bits(wm8350, | ||
| 681 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 682 | WM8350_IM_UV_LDO1_EINT); | ||
| 683 | case WM8350_IRQ_UV_DC6: | ||
| 684 | return wm8350_set_bits(wm8350, | ||
| 685 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 686 | WM8350_IM_UV_DC6_EINT); | ||
| 687 | case WM8350_IRQ_UV_DC5: | ||
| 688 | return wm8350_set_bits(wm8350, | ||
| 689 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 690 | WM8350_IM_UV_DC5_EINT); | ||
| 691 | case WM8350_IRQ_UV_DC4: | ||
| 692 | return wm8350_set_bits(wm8350, | ||
| 693 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 694 | WM8350_IM_UV_DC4_EINT); | ||
| 695 | case WM8350_IRQ_UV_DC3: | ||
| 696 | return wm8350_set_bits(wm8350, | ||
| 697 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 698 | WM8350_IM_UV_DC3_EINT); | ||
| 699 | case WM8350_IRQ_UV_DC2: | ||
| 700 | return wm8350_set_bits(wm8350, | ||
| 701 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 702 | WM8350_IM_UV_DC2_EINT); | ||
| 703 | case WM8350_IRQ_UV_DC1: | ||
| 704 | return wm8350_set_bits(wm8350, | ||
| 705 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 706 | WM8350_IM_UV_DC1_EINT); | ||
| 707 | case WM8350_IRQ_OC_LS: | ||
| 708 | return wm8350_set_bits(wm8350, | ||
| 709 | WM8350_OVER_CURRENT_INT_STATUS_MASK, | ||
| 710 | WM8350_IM_OC_LS_EINT); | ||
| 711 | case WM8350_IRQ_EXT_USB_FB: | ||
| 712 | return wm8350_set_bits(wm8350, | ||
| 713 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 714 | WM8350_IM_EXT_USB_FB_EINT); | ||
| 715 | case WM8350_IRQ_EXT_WALL_FB: | ||
| 716 | return wm8350_set_bits(wm8350, | ||
| 717 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 718 | WM8350_IM_EXT_WALL_FB_EINT); | ||
| 719 | case WM8350_IRQ_EXT_BAT_FB: | ||
| 720 | return wm8350_set_bits(wm8350, | ||
| 721 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 722 | WM8350_IM_EXT_BAT_FB_EINT); | ||
| 723 | case WM8350_IRQ_CODEC_JCK_DET_L: | ||
| 724 | return wm8350_set_bits(wm8350, | ||
| 725 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 726 | WM8350_IM_CODEC_JCK_DET_L_EINT); | ||
| 727 | case WM8350_IRQ_CODEC_JCK_DET_R: | ||
| 728 | return wm8350_set_bits(wm8350, | ||
| 729 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 730 | WM8350_IM_CODEC_JCK_DET_R_EINT); | ||
| 731 | case WM8350_IRQ_CODEC_MICSCD: | ||
| 732 | return wm8350_set_bits(wm8350, | ||
| 733 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 734 | WM8350_IM_CODEC_MICSCD_EINT); | ||
| 735 | case WM8350_IRQ_CODEC_MICD: | ||
| 736 | return wm8350_set_bits(wm8350, | ||
| 737 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 738 | WM8350_IM_CODEC_MICD_EINT); | ||
| 739 | case WM8350_IRQ_WKUP_OFF_STATE: | ||
| 740 | return wm8350_set_bits(wm8350, | ||
| 741 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 742 | WM8350_IM_WKUP_OFF_STATE_EINT); | ||
| 743 | case WM8350_IRQ_WKUP_HIB_STATE: | ||
| 744 | return wm8350_set_bits(wm8350, | ||
| 745 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 746 | WM8350_IM_WKUP_HIB_STATE_EINT); | ||
| 747 | case WM8350_IRQ_WKUP_CONV_FAULT: | ||
| 748 | return wm8350_set_bits(wm8350, | ||
| 749 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 750 | WM8350_IM_WKUP_CONV_FAULT_EINT); | ||
| 751 | case WM8350_IRQ_WKUP_WDOG_RST: | ||
| 752 | return wm8350_set_bits(wm8350, | ||
| 753 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 754 | WM8350_IM_WKUP_OFF_STATE_EINT); | ||
| 755 | case WM8350_IRQ_WKUP_GP_PWR_ON: | ||
| 756 | return wm8350_set_bits(wm8350, | ||
| 757 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 758 | WM8350_IM_WKUP_GP_PWR_ON_EINT); | ||
| 759 | case WM8350_IRQ_WKUP_ONKEY: | ||
| 760 | return wm8350_set_bits(wm8350, | ||
| 761 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 762 | WM8350_IM_WKUP_ONKEY_EINT); | ||
| 763 | case WM8350_IRQ_WKUP_GP_WAKEUP: | ||
| 764 | return wm8350_set_bits(wm8350, | ||
| 765 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 766 | WM8350_IM_WKUP_GP_WAKEUP_EINT); | ||
| 767 | case WM8350_IRQ_GPIO(0): | ||
| 768 | return wm8350_set_bits(wm8350, | ||
| 769 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 770 | WM8350_IM_GP0_EINT); | ||
| 771 | case WM8350_IRQ_GPIO(1): | ||
| 772 | return wm8350_set_bits(wm8350, | ||
| 773 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 774 | WM8350_IM_GP1_EINT); | ||
| 775 | case WM8350_IRQ_GPIO(2): | ||
| 776 | return wm8350_set_bits(wm8350, | ||
| 777 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 778 | WM8350_IM_GP2_EINT); | ||
| 779 | case WM8350_IRQ_GPIO(3): | ||
| 780 | return wm8350_set_bits(wm8350, | ||
| 781 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 782 | WM8350_IM_GP3_EINT); | ||
| 783 | case WM8350_IRQ_GPIO(4): | ||
| 784 | return wm8350_set_bits(wm8350, | ||
| 785 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 786 | WM8350_IM_GP4_EINT); | ||
| 787 | case WM8350_IRQ_GPIO(5): | ||
| 788 | return wm8350_set_bits(wm8350, | ||
| 789 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 790 | WM8350_IM_GP5_EINT); | ||
| 791 | case WM8350_IRQ_GPIO(6): | ||
| 792 | return wm8350_set_bits(wm8350, | ||
| 793 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 794 | WM8350_IM_GP6_EINT); | ||
| 795 | case WM8350_IRQ_GPIO(7): | ||
| 796 | return wm8350_set_bits(wm8350, | ||
| 797 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 798 | WM8350_IM_GP7_EINT); | ||
| 799 | case WM8350_IRQ_GPIO(8): | ||
| 800 | return wm8350_set_bits(wm8350, | ||
| 801 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 802 | WM8350_IM_GP8_EINT); | ||
| 803 | case WM8350_IRQ_GPIO(9): | ||
| 804 | return wm8350_set_bits(wm8350, | ||
| 805 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 806 | WM8350_IM_GP9_EINT); | ||
| 807 | case WM8350_IRQ_GPIO(10): | ||
| 808 | return wm8350_set_bits(wm8350, | ||
| 809 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 810 | WM8350_IM_GP10_EINT); | ||
| 811 | case WM8350_IRQ_GPIO(11): | ||
| 812 | return wm8350_set_bits(wm8350, | ||
| 813 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 814 | WM8350_IM_GP11_EINT); | ||
| 815 | case WM8350_IRQ_GPIO(12): | ||
| 816 | return wm8350_set_bits(wm8350, | ||
| 817 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 818 | WM8350_IM_GP12_EINT); | ||
| 819 | default: | ||
| 820 | dev_warn(wm8350->dev, "Attempting to mask unknown IRQ %d\n", | ||
| 821 | irq); | ||
| 822 | return -EINVAL; | ||
| 823 | } | ||
| 824 | return 0; | ||
| 825 | } | ||
| 826 | EXPORT_SYMBOL_GPL(wm8350_mask_irq); | ||
| 827 | |||
| 828 | int wm8350_unmask_irq(struct wm8350 *wm8350, int irq) | ||
| 829 | { | ||
| 830 | switch (irq) { | ||
| 831 | case WM8350_IRQ_CHG_BAT_HOT: | ||
| 832 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 833 | WM8350_IM_CHG_BAT_HOT_EINT); | ||
| 834 | case WM8350_IRQ_CHG_BAT_COLD: | ||
| 835 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 836 | WM8350_IM_CHG_BAT_COLD_EINT); | ||
| 837 | case WM8350_IRQ_CHG_BAT_FAIL: | ||
| 838 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 839 | WM8350_IM_CHG_BAT_FAIL_EINT); | ||
| 840 | case WM8350_IRQ_CHG_TO: | ||
| 841 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 842 | WM8350_IM_CHG_TO_EINT); | ||
| 843 | case WM8350_IRQ_CHG_END: | ||
| 844 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 845 | WM8350_IM_CHG_END_EINT); | ||
| 846 | case WM8350_IRQ_CHG_START: | ||
| 847 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 848 | WM8350_IM_CHG_START_EINT); | ||
| 849 | case WM8350_IRQ_CHG_FAST_RDY: | ||
| 850 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 851 | WM8350_IM_CHG_FAST_RDY_EINT); | ||
| 852 | case WM8350_IRQ_RTC_PER: | ||
| 853 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 854 | WM8350_IM_RTC_PER_EINT); | ||
| 855 | case WM8350_IRQ_RTC_SEC: | ||
| 856 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 857 | WM8350_IM_RTC_SEC_EINT); | ||
| 858 | case WM8350_IRQ_RTC_ALM: | ||
| 859 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 860 | WM8350_IM_RTC_ALM_EINT); | ||
| 861 | case WM8350_IRQ_CHG_VBATT_LT_3P9: | ||
| 862 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 863 | WM8350_IM_CHG_VBATT_LT_3P9_EINT); | ||
| 864 | case WM8350_IRQ_CHG_VBATT_LT_3P1: | ||
| 865 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 866 | WM8350_IM_CHG_VBATT_LT_3P1_EINT); | ||
| 867 | case WM8350_IRQ_CHG_VBATT_LT_2P85: | ||
| 868 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, | ||
| 869 | WM8350_IM_CHG_VBATT_LT_2P85_EINT); | ||
| 870 | case WM8350_IRQ_CS1: | ||
| 871 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 872 | WM8350_IM_CS1_EINT); | ||
| 873 | case WM8350_IRQ_CS2: | ||
| 874 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 875 | WM8350_IM_CS2_EINT); | ||
| 876 | case WM8350_IRQ_USB_LIMIT: | ||
| 877 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 878 | WM8350_IM_USB_LIMIT_EINT); | ||
| 879 | case WM8350_IRQ_AUXADC_DATARDY: | ||
| 880 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 881 | WM8350_IM_AUXADC_DATARDY_EINT); | ||
| 882 | case WM8350_IRQ_AUXADC_DCOMP4: | ||
| 883 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 884 | WM8350_IM_AUXADC_DCOMP4_EINT); | ||
| 885 | case WM8350_IRQ_AUXADC_DCOMP3: | ||
| 886 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 887 | WM8350_IM_AUXADC_DCOMP3_EINT); | ||
| 888 | case WM8350_IRQ_AUXADC_DCOMP2: | ||
| 889 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 890 | WM8350_IM_AUXADC_DCOMP2_EINT); | ||
| 891 | case WM8350_IRQ_AUXADC_DCOMP1: | ||
| 892 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 893 | WM8350_IM_AUXADC_DCOMP1_EINT); | ||
| 894 | case WM8350_IRQ_SYS_HYST_COMP_FAIL: | ||
| 895 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 896 | WM8350_IM_SYS_HYST_COMP_FAIL_EINT); | ||
| 897 | case WM8350_IRQ_SYS_CHIP_GT115: | ||
| 898 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 899 | WM8350_IM_SYS_CHIP_GT115_EINT); | ||
| 900 | case WM8350_IRQ_SYS_CHIP_GT140: | ||
| 901 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 902 | WM8350_IM_SYS_CHIP_GT140_EINT); | ||
| 903 | case WM8350_IRQ_SYS_WDOG_TO: | ||
| 904 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, | ||
| 905 | WM8350_IM_SYS_WDOG_TO_EINT); | ||
| 906 | case WM8350_IRQ_UV_LDO4: | ||
| 907 | return wm8350_clear_bits(wm8350, | ||
| 908 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 909 | WM8350_IM_UV_LDO4_EINT); | ||
| 910 | case WM8350_IRQ_UV_LDO3: | ||
| 911 | return wm8350_clear_bits(wm8350, | ||
| 912 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 913 | WM8350_IM_UV_LDO3_EINT); | ||
| 914 | case WM8350_IRQ_UV_LDO2: | ||
| 915 | return wm8350_clear_bits(wm8350, | ||
| 916 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 917 | WM8350_IM_UV_LDO2_EINT); | ||
| 918 | case WM8350_IRQ_UV_LDO1: | ||
| 919 | return wm8350_clear_bits(wm8350, | ||
| 920 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 921 | WM8350_IM_UV_LDO1_EINT); | ||
| 922 | case WM8350_IRQ_UV_DC6: | ||
| 923 | return wm8350_clear_bits(wm8350, | ||
| 924 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 925 | WM8350_IM_UV_DC6_EINT); | ||
| 926 | case WM8350_IRQ_UV_DC5: | ||
| 927 | return wm8350_clear_bits(wm8350, | ||
| 928 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 929 | WM8350_IM_UV_DC5_EINT); | ||
| 930 | case WM8350_IRQ_UV_DC4: | ||
| 931 | return wm8350_clear_bits(wm8350, | ||
| 932 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 933 | WM8350_IM_UV_DC4_EINT); | ||
| 934 | case WM8350_IRQ_UV_DC3: | ||
| 935 | return wm8350_clear_bits(wm8350, | ||
| 936 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 937 | WM8350_IM_UV_DC3_EINT); | ||
| 938 | case WM8350_IRQ_UV_DC2: | ||
| 939 | return wm8350_clear_bits(wm8350, | ||
| 940 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 941 | WM8350_IM_UV_DC2_EINT); | ||
| 942 | case WM8350_IRQ_UV_DC1: | ||
| 943 | return wm8350_clear_bits(wm8350, | ||
| 944 | WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, | ||
| 945 | WM8350_IM_UV_DC1_EINT); | ||
| 946 | case WM8350_IRQ_OC_LS: | ||
| 947 | return wm8350_clear_bits(wm8350, | ||
| 948 | WM8350_OVER_CURRENT_INT_STATUS_MASK, | ||
| 949 | WM8350_IM_OC_LS_EINT); | ||
| 950 | case WM8350_IRQ_EXT_USB_FB: | ||
| 951 | return wm8350_clear_bits(wm8350, | ||
| 952 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 953 | WM8350_IM_EXT_USB_FB_EINT); | ||
| 954 | case WM8350_IRQ_EXT_WALL_FB: | ||
| 955 | return wm8350_clear_bits(wm8350, | ||
| 956 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 957 | WM8350_IM_EXT_WALL_FB_EINT); | ||
| 958 | case WM8350_IRQ_EXT_BAT_FB: | ||
| 959 | return wm8350_clear_bits(wm8350, | ||
| 960 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 961 | WM8350_IM_EXT_BAT_FB_EINT); | ||
| 962 | case WM8350_IRQ_CODEC_JCK_DET_L: | ||
| 963 | return wm8350_clear_bits(wm8350, | ||
| 964 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 965 | WM8350_IM_CODEC_JCK_DET_L_EINT); | ||
| 966 | case WM8350_IRQ_CODEC_JCK_DET_R: | ||
| 967 | return wm8350_clear_bits(wm8350, | ||
| 968 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 969 | WM8350_IM_CODEC_JCK_DET_R_EINT); | ||
| 970 | case WM8350_IRQ_CODEC_MICSCD: | ||
| 971 | return wm8350_clear_bits(wm8350, | ||
| 972 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 973 | WM8350_IM_CODEC_MICSCD_EINT); | ||
| 974 | case WM8350_IRQ_CODEC_MICD: | ||
| 975 | return wm8350_clear_bits(wm8350, | ||
| 976 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 977 | WM8350_IM_CODEC_MICD_EINT); | ||
| 978 | case WM8350_IRQ_WKUP_OFF_STATE: | ||
| 979 | return wm8350_clear_bits(wm8350, | ||
| 980 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 981 | WM8350_IM_WKUP_OFF_STATE_EINT); | ||
| 982 | case WM8350_IRQ_WKUP_HIB_STATE: | ||
| 983 | return wm8350_clear_bits(wm8350, | ||
| 984 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 985 | WM8350_IM_WKUP_HIB_STATE_EINT); | ||
| 986 | case WM8350_IRQ_WKUP_CONV_FAULT: | ||
| 987 | return wm8350_clear_bits(wm8350, | ||
| 988 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 989 | WM8350_IM_WKUP_CONV_FAULT_EINT); | ||
| 990 | case WM8350_IRQ_WKUP_WDOG_RST: | ||
| 991 | return wm8350_clear_bits(wm8350, | ||
| 992 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 993 | WM8350_IM_WKUP_OFF_STATE_EINT); | ||
| 994 | case WM8350_IRQ_WKUP_GP_PWR_ON: | ||
| 995 | return wm8350_clear_bits(wm8350, | ||
| 996 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 997 | WM8350_IM_WKUP_GP_PWR_ON_EINT); | ||
| 998 | case WM8350_IRQ_WKUP_ONKEY: | ||
| 999 | return wm8350_clear_bits(wm8350, | ||
| 1000 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 1001 | WM8350_IM_WKUP_ONKEY_EINT); | ||
| 1002 | case WM8350_IRQ_WKUP_GP_WAKEUP: | ||
| 1003 | return wm8350_clear_bits(wm8350, | ||
| 1004 | WM8350_COMPARATOR_INT_STATUS_MASK, | ||
| 1005 | WM8350_IM_WKUP_GP_WAKEUP_EINT); | ||
| 1006 | case WM8350_IRQ_GPIO(0): | ||
| 1007 | return wm8350_clear_bits(wm8350, | ||
| 1008 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 1009 | WM8350_IM_GP0_EINT); | ||
| 1010 | case WM8350_IRQ_GPIO(1): | ||
| 1011 | return wm8350_clear_bits(wm8350, | ||
| 1012 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 1013 | WM8350_IM_GP1_EINT); | ||
| 1014 | case WM8350_IRQ_GPIO(2): | ||
| 1015 | return wm8350_clear_bits(wm8350, | ||
| 1016 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 1017 | WM8350_IM_GP2_EINT); | ||
| 1018 | case WM8350_IRQ_GPIO(3): | ||
| 1019 | return wm8350_clear_bits(wm8350, | ||
| 1020 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 1021 | WM8350_IM_GP3_EINT); | ||
| 1022 | case WM8350_IRQ_GPIO(4): | ||
| 1023 | return wm8350_clear_bits(wm8350, | ||
| 1024 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 1025 | WM8350_IM_GP4_EINT); | ||
| 1026 | case WM8350_IRQ_GPIO(5): | ||
| 1027 | return wm8350_clear_bits(wm8350, | ||
| 1028 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 1029 | WM8350_IM_GP5_EINT); | ||
| 1030 | case WM8350_IRQ_GPIO(6): | ||
| 1031 | return wm8350_clear_bits(wm8350, | ||
| 1032 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 1033 | WM8350_IM_GP6_EINT); | ||
| 1034 | case WM8350_IRQ_GPIO(7): | ||
| 1035 | return wm8350_clear_bits(wm8350, | ||
| 1036 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 1037 | WM8350_IM_GP7_EINT); | ||
| 1038 | case WM8350_IRQ_GPIO(8): | ||
| 1039 | return wm8350_clear_bits(wm8350, | ||
| 1040 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 1041 | WM8350_IM_GP8_EINT); | ||
| 1042 | case WM8350_IRQ_GPIO(9): | ||
| 1043 | return wm8350_clear_bits(wm8350, | ||
| 1044 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 1045 | WM8350_IM_GP9_EINT); | ||
| 1046 | case WM8350_IRQ_GPIO(10): | ||
| 1047 | return wm8350_clear_bits(wm8350, | ||
| 1048 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 1049 | WM8350_IM_GP10_EINT); | ||
| 1050 | case WM8350_IRQ_GPIO(11): | ||
| 1051 | return wm8350_clear_bits(wm8350, | ||
| 1052 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 1053 | WM8350_IM_GP11_EINT); | ||
| 1054 | case WM8350_IRQ_GPIO(12): | ||
| 1055 | return wm8350_clear_bits(wm8350, | ||
| 1056 | WM8350_GPIO_INT_STATUS_MASK, | ||
| 1057 | WM8350_IM_GP12_EINT); | ||
| 1058 | default: | ||
| 1059 | dev_warn(wm8350->dev, "Attempting to unmask unknown IRQ %d\n", | ||
| 1060 | irq); | ||
| 1061 | return -EINVAL; | ||
| 1062 | } | ||
| 1063 | return 0; | ||
| 1064 | } | ||
| 1065 | EXPORT_SYMBOL_GPL(wm8350_unmask_irq); | ||
| 1066 | |||
| 1067 | int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref) | 340 | int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref) |
| 1068 | { | 341 | { |
| 1069 | u16 reg, result = 0; | 342 | u16 reg, result = 0; |
| @@ -1264,7 +537,7 @@ static void wm8350_client_dev_register(struct wm8350 *wm8350, | |||
| 1264 | int ret; | 537 | int ret; |
| 1265 | 538 | ||
| 1266 | *pdev = platform_device_alloc(name, -1); | 539 | *pdev = platform_device_alloc(name, -1); |
| 1267 | if (pdev == NULL) { | 540 | if (*pdev == NULL) { |
| 1268 | dev_err(wm8350->dev, "Failed to allocate %s\n", name); | 541 | dev_err(wm8350->dev, "Failed to allocate %s\n", name); |
| 1269 | return; | 542 | return; |
| 1270 | } | 543 | } |
| @@ -1409,49 +682,18 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq, | |||
| 1409 | return ret; | 682 | return ret; |
| 1410 | } | 683 | } |
| 1411 | 684 | ||
| 1412 | wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF); | ||
| 1413 | wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF); | ||
| 1414 | wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF); | ||
| 1415 | wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF); | ||
| 1416 | wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF); | ||
| 1417 | wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF); | ||
| 1418 | |||
| 1419 | mutex_init(&wm8350->auxadc_mutex); | 685 | mutex_init(&wm8350->auxadc_mutex); |
| 1420 | mutex_init(&wm8350->irq_mutex); | ||
| 1421 | if (irq) { | ||
| 1422 | int flags = IRQF_ONESHOT; | ||
| 1423 | |||
| 1424 | if (pdata && pdata->irq_high) { | ||
| 1425 | flags |= IRQF_TRIGGER_HIGH; | ||
| 1426 | |||
| 1427 | wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1, | ||
| 1428 | WM8350_IRQ_POL); | ||
| 1429 | } else { | ||
| 1430 | flags |= IRQF_TRIGGER_LOW; | ||
| 1431 | |||
| 1432 | wm8350_clear_bits(wm8350, WM8350_SYSTEM_CONTROL_1, | ||
| 1433 | WM8350_IRQ_POL); | ||
| 1434 | } | ||
| 1435 | 686 | ||
| 1436 | ret = request_threaded_irq(irq, NULL, wm8350_irq, flags, | 687 | ret = wm8350_irq_init(wm8350, irq, pdata); |
| 1437 | "wm8350", wm8350); | 688 | if (ret < 0) |
| 1438 | if (ret != 0) { | ||
| 1439 | dev_err(wm8350->dev, "Failed to request IRQ: %d\n", | ||
| 1440 | ret); | ||
| 1441 | goto err; | ||
| 1442 | } | ||
| 1443 | } else { | ||
| 1444 | dev_err(wm8350->dev, "No IRQ configured\n"); | ||
| 1445 | goto err; | 689 | goto err; |
| 1446 | } | ||
| 1447 | wm8350->chip_irq = irq; | ||
| 1448 | 690 | ||
| 1449 | if (pdata && pdata->init) { | 691 | if (pdata && pdata->init) { |
| 1450 | ret = pdata->init(wm8350); | 692 | ret = pdata->init(wm8350); |
| 1451 | if (ret != 0) { | 693 | if (ret != 0) { |
| 1452 | dev_err(wm8350->dev, "Platform init() failed: %d\n", | 694 | dev_err(wm8350->dev, "Platform init() failed: %d\n", |
| 1453 | ret); | 695 | ret); |
| 1454 | goto err; | 696 | goto err_irq; |
| 1455 | } | 697 | } |
| 1456 | } | 698 | } |
| 1457 | 699 | ||
| @@ -1470,6 +712,8 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq, | |||
| 1470 | 712 | ||
| 1471 | return 0; | 713 | return 0; |
| 1472 | 714 | ||
| 715 | err_irq: | ||
| 716 | wm8350_irq_exit(wm8350); | ||
| 1473 | err: | 717 | err: |
| 1474 | kfree(wm8350->reg_cache); | 718 | kfree(wm8350->reg_cache); |
| 1475 | return ret; | 719 | return ret; |
| @@ -1493,7 +737,8 @@ void wm8350_device_exit(struct wm8350 *wm8350) | |||
| 1493 | platform_device_unregister(wm8350->gpio.pdev); | 737 | platform_device_unregister(wm8350->gpio.pdev); |
| 1494 | platform_device_unregister(wm8350->codec.pdev); | 738 | platform_device_unregister(wm8350->codec.pdev); |
| 1495 | 739 | ||
| 1496 | free_irq(wm8350->chip_irq, wm8350); | 740 | wm8350_irq_exit(wm8350); |
| 741 | |||
| 1497 | kfree(wm8350->reg_cache); | 742 | kfree(wm8350->reg_cache); |
| 1498 | } | 743 | } |
| 1499 | EXPORT_SYMBOL_GPL(wm8350_device_exit); | 744 | EXPORT_SYMBOL_GPL(wm8350_device_exit); |
diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c new file mode 100644 index 000000000000..c8df547c4747 --- /dev/null +++ b/drivers/mfd/wm8350-irq.c | |||
| @@ -0,0 +1,529 @@ | |||
| 1 | /* | ||
| 2 | * wm8350-irq.c -- IRQ support for Wolfson WM8350 | ||
| 3 | * | ||
| 4 | * Copyright 2007, 2008, 2009 Wolfson Microelectronics PLC. | ||
| 5 | * | ||
| 6 | * Author: Liam Girdwood, Mark Brown | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms of the GNU General Public License as published by the | ||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 11 | * option) any later version. | ||
| 12 | * | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/bug.h> | ||
| 19 | #include <linux/device.h> | ||
| 20 | #include <linux/interrupt.h> | ||
| 21 | #include <linux/workqueue.h> | ||
| 22 | |||
| 23 | #include <linux/mfd/wm8350/core.h> | ||
| 24 | #include <linux/mfd/wm8350/audio.h> | ||
| 25 | #include <linux/mfd/wm8350/comparator.h> | ||
| 26 | #include <linux/mfd/wm8350/gpio.h> | ||
| 27 | #include <linux/mfd/wm8350/pmic.h> | ||
| 28 | #include <linux/mfd/wm8350/rtc.h> | ||
| 29 | #include <linux/mfd/wm8350/supply.h> | ||
| 30 | #include <linux/mfd/wm8350/wdt.h> | ||
| 31 | |||
| 32 | #define WM8350_NUM_IRQ_REGS 7 | ||
| 33 | |||
| 34 | #define WM8350_INT_OFFSET_1 0 | ||
| 35 | #define WM8350_INT_OFFSET_2 1 | ||
| 36 | #define WM8350_POWER_UP_INT_OFFSET 2 | ||
| 37 | #define WM8350_UNDER_VOLTAGE_INT_OFFSET 3 | ||
| 38 | #define WM8350_OVER_CURRENT_INT_OFFSET 4 | ||
| 39 | #define WM8350_GPIO_INT_OFFSET 5 | ||
| 40 | #define WM8350_COMPARATOR_INT_OFFSET 6 | ||
| 41 | |||
| 42 | struct wm8350_irq_data { | ||
| 43 | int primary; | ||
| 44 | int reg; | ||
| 45 | int mask; | ||
| 46 | int primary_only; | ||
| 47 | }; | ||
| 48 | |||
| 49 | static struct wm8350_irq_data wm8350_irqs[] = { | ||
| 50 | [WM8350_IRQ_OC_LS] = { | ||
| 51 | .primary = WM8350_OC_INT, | ||
| 52 | .reg = WM8350_OVER_CURRENT_INT_OFFSET, | ||
| 53 | .mask = WM8350_OC_LS_EINT, | ||
| 54 | .primary_only = 1, | ||
| 55 | }, | ||
| 56 | [WM8350_IRQ_UV_DC1] = { | ||
| 57 | .primary = WM8350_UV_INT, | ||
| 58 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
| 59 | .mask = WM8350_UV_DC1_EINT, | ||
| 60 | }, | ||
| 61 | [WM8350_IRQ_UV_DC2] = { | ||
| 62 | .primary = WM8350_UV_INT, | ||
| 63 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
| 64 | .mask = WM8350_UV_DC2_EINT, | ||
| 65 | }, | ||
| 66 | [WM8350_IRQ_UV_DC3] = { | ||
| 67 | .primary = WM8350_UV_INT, | ||
| 68 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
| 69 | .mask = WM8350_UV_DC3_EINT, | ||
| 70 | }, | ||
| 71 | [WM8350_IRQ_UV_DC4] = { | ||
| 72 | .primary = WM8350_UV_INT, | ||
| 73 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
| 74 | .mask = WM8350_UV_DC4_EINT, | ||
| 75 | }, | ||
| 76 | [WM8350_IRQ_UV_DC5] = { | ||
| 77 | .primary = WM8350_UV_INT, | ||
| 78 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
| 79 | .mask = WM8350_UV_DC5_EINT, | ||
| 80 | }, | ||
| 81 | [WM8350_IRQ_UV_DC6] = { | ||
| 82 | .primary = WM8350_UV_INT, | ||
| 83 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
| 84 | .mask = WM8350_UV_DC6_EINT, | ||
| 85 | }, | ||
| 86 | [WM8350_IRQ_UV_LDO1] = { | ||
| 87 | .primary = WM8350_UV_INT, | ||
| 88 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
| 89 | .mask = WM8350_UV_LDO1_EINT, | ||
| 90 | }, | ||
| 91 | [WM8350_IRQ_UV_LDO2] = { | ||
| 92 | .primary = WM8350_UV_INT, | ||
| 93 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
| 94 | .mask = WM8350_UV_LDO2_EINT, | ||
| 95 | }, | ||
| 96 | [WM8350_IRQ_UV_LDO3] = { | ||
| 97 | .primary = WM8350_UV_INT, | ||
| 98 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
| 99 | .mask = WM8350_UV_LDO3_EINT, | ||
| 100 | }, | ||
| 101 | [WM8350_IRQ_UV_LDO4] = { | ||
| 102 | .primary = WM8350_UV_INT, | ||
| 103 | .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, | ||
| 104 | .mask = WM8350_UV_LDO4_EINT, | ||
| 105 | }, | ||
| 106 | [WM8350_IRQ_CHG_BAT_HOT] = { | ||
| 107 | .primary = WM8350_CHG_INT, | ||
| 108 | .reg = WM8350_INT_OFFSET_1, | ||
| 109 | .mask = WM8350_CHG_BAT_HOT_EINT, | ||
| 110 | }, | ||
| 111 | [WM8350_IRQ_CHG_BAT_COLD] = { | ||
| 112 | .primary = WM8350_CHG_INT, | ||
| 113 | .reg = WM8350_INT_OFFSET_1, | ||
| 114 | .mask = WM8350_CHG_BAT_COLD_EINT, | ||
| 115 | }, | ||
| 116 | [WM8350_IRQ_CHG_BAT_FAIL] = { | ||
| 117 | .primary = WM8350_CHG_INT, | ||
| 118 | .reg = WM8350_INT_OFFSET_1, | ||
| 119 | .mask = WM8350_CHG_BAT_FAIL_EINT, | ||
| 120 | }, | ||
| 121 | [WM8350_IRQ_CHG_TO] = { | ||
| 122 | .primary = WM8350_CHG_INT, | ||
| 123 | .reg = WM8350_INT_OFFSET_1, | ||
| 124 | .mask = WM8350_CHG_TO_EINT, | ||
| 125 | }, | ||
| 126 | [WM8350_IRQ_CHG_END] = { | ||
| 127 | .primary = WM8350_CHG_INT, | ||
| 128 | .reg = WM8350_INT_OFFSET_1, | ||
| 129 | .mask = WM8350_CHG_END_EINT, | ||
| 130 | }, | ||
| 131 | [WM8350_IRQ_CHG_START] = { | ||
| 132 | .primary = WM8350_CHG_INT, | ||
| 133 | .reg = WM8350_INT_OFFSET_1, | ||
| 134 | .mask = WM8350_CHG_START_EINT, | ||
| 135 | }, | ||
| 136 | [WM8350_IRQ_CHG_FAST_RDY] = { | ||
| 137 | .primary = WM8350_CHG_INT, | ||
| 138 | .reg = WM8350_INT_OFFSET_1, | ||
| 139 | .mask = WM8350_CHG_FAST_RDY_EINT, | ||
| 140 | }, | ||
| 141 | [WM8350_IRQ_CHG_VBATT_LT_3P9] = { | ||
| 142 | .primary = WM8350_CHG_INT, | ||
| 143 | .reg = WM8350_INT_OFFSET_1, | ||
| 144 | .mask = WM8350_CHG_VBATT_LT_3P9_EINT, | ||
| 145 | }, | ||
| 146 | [WM8350_IRQ_CHG_VBATT_LT_3P1] = { | ||
| 147 | .primary = WM8350_CHG_INT, | ||
| 148 | .reg = WM8350_INT_OFFSET_1, | ||
| 149 | .mask = WM8350_CHG_VBATT_LT_3P1_EINT, | ||
| 150 | }, | ||
| 151 | [WM8350_IRQ_CHG_VBATT_LT_2P85] = { | ||
| 152 | .primary = WM8350_CHG_INT, | ||
| 153 | .reg = WM8350_INT_OFFSET_1, | ||
| 154 | .mask = WM8350_CHG_VBATT_LT_2P85_EINT, | ||
| 155 | }, | ||
| 156 | [WM8350_IRQ_RTC_ALM] = { | ||
| 157 | .primary = WM8350_RTC_INT, | ||
| 158 | .reg = WM8350_INT_OFFSET_1, | ||
| 159 | .mask = WM8350_RTC_ALM_EINT, | ||
| 160 | }, | ||
| 161 | [WM8350_IRQ_RTC_SEC] = { | ||
| 162 | .primary = WM8350_RTC_INT, | ||
| 163 | .reg = WM8350_INT_OFFSET_1, | ||
| 164 | .mask = WM8350_RTC_SEC_EINT, | ||
| 165 | }, | ||
| 166 | [WM8350_IRQ_RTC_PER] = { | ||
| 167 | .primary = WM8350_RTC_INT, | ||
| 168 | .reg = WM8350_INT_OFFSET_1, | ||
| 169 | .mask = WM8350_RTC_PER_EINT, | ||
| 170 | }, | ||
| 171 | [WM8350_IRQ_CS1] = { | ||
| 172 | .primary = WM8350_CS_INT, | ||
| 173 | .reg = WM8350_INT_OFFSET_2, | ||
| 174 | .mask = WM8350_CS1_EINT, | ||
| 175 | }, | ||
| 176 | [WM8350_IRQ_CS2] = { | ||
| 177 | .primary = WM8350_CS_INT, | ||
| 178 | .reg = WM8350_INT_OFFSET_2, | ||
| 179 | .mask = WM8350_CS2_EINT, | ||
| 180 | }, | ||
| 181 | [WM8350_IRQ_SYS_HYST_COMP_FAIL] = { | ||
| 182 | .primary = WM8350_SYS_INT, | ||
| 183 | .reg = WM8350_INT_OFFSET_2, | ||
| 184 | .mask = WM8350_SYS_HYST_COMP_FAIL_EINT, | ||
| 185 | }, | ||
| 186 | [WM8350_IRQ_SYS_CHIP_GT115] = { | ||
| 187 | .primary = WM8350_SYS_INT, | ||
| 188 | .reg = WM8350_INT_OFFSET_2, | ||
| 189 | .mask = WM8350_SYS_CHIP_GT115_EINT, | ||
| 190 | }, | ||
| 191 | [WM8350_IRQ_SYS_CHIP_GT140] = { | ||
| 192 | .primary = WM8350_SYS_INT, | ||
| 193 | .reg = WM8350_INT_OFFSET_2, | ||
| 194 | .mask = WM8350_SYS_CHIP_GT140_EINT, | ||
| 195 | }, | ||
| 196 | [WM8350_IRQ_SYS_WDOG_TO] = { | ||
| 197 | .primary = WM8350_SYS_INT, | ||
| 198 | .reg = WM8350_INT_OFFSET_2, | ||
| 199 | .mask = WM8350_SYS_WDOG_TO_EINT, | ||
| 200 | }, | ||
| 201 | [WM8350_IRQ_AUXADC_DATARDY] = { | ||
| 202 | .primary = WM8350_AUXADC_INT, | ||
| 203 | .reg = WM8350_INT_OFFSET_2, | ||
| 204 | .mask = WM8350_AUXADC_DATARDY_EINT, | ||
| 205 | }, | ||
| 206 | [WM8350_IRQ_AUXADC_DCOMP4] = { | ||
| 207 | .primary = WM8350_AUXADC_INT, | ||
| 208 | .reg = WM8350_INT_OFFSET_2, | ||
| 209 | .mask = WM8350_AUXADC_DCOMP4_EINT, | ||
| 210 | }, | ||
| 211 | [WM8350_IRQ_AUXADC_DCOMP3] = { | ||
| 212 | .primary = WM8350_AUXADC_INT, | ||
| 213 | .reg = WM8350_INT_OFFSET_2, | ||
| 214 | .mask = WM8350_AUXADC_DCOMP3_EINT, | ||
| 215 | }, | ||
| 216 | [WM8350_IRQ_AUXADC_DCOMP2] = { | ||
| 217 | .primary = WM8350_AUXADC_INT, | ||
| 218 | .reg = WM8350_INT_OFFSET_2, | ||
| 219 | .mask = WM8350_AUXADC_DCOMP2_EINT, | ||
| 220 | }, | ||
| 221 | [WM8350_IRQ_AUXADC_DCOMP1] = { | ||
| 222 | .primary = WM8350_AUXADC_INT, | ||
| 223 | .reg = WM8350_INT_OFFSET_2, | ||
| 224 | .mask = WM8350_AUXADC_DCOMP1_EINT, | ||
| 225 | }, | ||
| 226 | [WM8350_IRQ_USB_LIMIT] = { | ||
| 227 | .primary = WM8350_USB_INT, | ||
| 228 | .reg = WM8350_INT_OFFSET_2, | ||
| 229 | .mask = WM8350_USB_LIMIT_EINT, | ||
| 230 | .primary_only = 1, | ||
| 231 | }, | ||
| 232 | [WM8350_IRQ_WKUP_OFF_STATE] = { | ||
| 233 | .primary = WM8350_WKUP_INT, | ||
| 234 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
| 235 | .mask = WM8350_WKUP_OFF_STATE_EINT, | ||
| 236 | }, | ||
| 237 | [WM8350_IRQ_WKUP_HIB_STATE] = { | ||
| 238 | .primary = WM8350_WKUP_INT, | ||
| 239 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
| 240 | .mask = WM8350_WKUP_HIB_STATE_EINT, | ||
| 241 | }, | ||
| 242 | [WM8350_IRQ_WKUP_CONV_FAULT] = { | ||
| 243 | .primary = WM8350_WKUP_INT, | ||
| 244 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
| 245 | .mask = WM8350_WKUP_CONV_FAULT_EINT, | ||
| 246 | }, | ||
| 247 | [WM8350_IRQ_WKUP_WDOG_RST] = { | ||
| 248 | .primary = WM8350_WKUP_INT, | ||
| 249 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
| 250 | .mask = WM8350_WKUP_WDOG_RST_EINT, | ||
| 251 | }, | ||
| 252 | [WM8350_IRQ_WKUP_GP_PWR_ON] = { | ||
| 253 | .primary = WM8350_WKUP_INT, | ||
| 254 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
| 255 | .mask = WM8350_WKUP_GP_PWR_ON_EINT, | ||
| 256 | }, | ||
| 257 | [WM8350_IRQ_WKUP_ONKEY] = { | ||
| 258 | .primary = WM8350_WKUP_INT, | ||
| 259 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
| 260 | .mask = WM8350_WKUP_ONKEY_EINT, | ||
| 261 | }, | ||
| 262 | [WM8350_IRQ_WKUP_GP_WAKEUP] = { | ||
| 263 | .primary = WM8350_WKUP_INT, | ||
| 264 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
| 265 | .mask = WM8350_WKUP_GP_WAKEUP_EINT, | ||
| 266 | }, | ||
| 267 | [WM8350_IRQ_CODEC_JCK_DET_L] = { | ||
| 268 | .primary = WM8350_CODEC_INT, | ||
| 269 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
| 270 | .mask = WM8350_CODEC_JCK_DET_L_EINT, | ||
| 271 | }, | ||
| 272 | [WM8350_IRQ_CODEC_JCK_DET_R] = { | ||
| 273 | .primary = WM8350_CODEC_INT, | ||
| 274 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
| 275 | .mask = WM8350_CODEC_JCK_DET_R_EINT, | ||
| 276 | }, | ||
| 277 | [WM8350_IRQ_CODEC_MICSCD] = { | ||
| 278 | .primary = WM8350_CODEC_INT, | ||
| 279 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
| 280 | .mask = WM8350_CODEC_MICSCD_EINT, | ||
| 281 | }, | ||
| 282 | [WM8350_IRQ_CODEC_MICD] = { | ||
| 283 | .primary = WM8350_CODEC_INT, | ||
| 284 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
| 285 | .mask = WM8350_CODEC_MICD_EINT, | ||
| 286 | }, | ||
| 287 | [WM8350_IRQ_EXT_USB_FB] = { | ||
| 288 | .primary = WM8350_EXT_INT, | ||
| 289 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
| 290 | .mask = WM8350_EXT_USB_FB_EINT, | ||
| 291 | }, | ||
| 292 | [WM8350_IRQ_EXT_WALL_FB] = { | ||
| 293 | .primary = WM8350_EXT_INT, | ||
| 294 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
| 295 | .mask = WM8350_EXT_WALL_FB_EINT, | ||
| 296 | }, | ||
| 297 | [WM8350_IRQ_EXT_BAT_FB] = { | ||
| 298 | .primary = WM8350_EXT_INT, | ||
| 299 | .reg = WM8350_COMPARATOR_INT_OFFSET, | ||
| 300 | .mask = WM8350_EXT_BAT_FB_EINT, | ||
| 301 | }, | ||
| 302 | [WM8350_IRQ_GPIO(0)] = { | ||
| 303 | .primary = WM8350_GP_INT, | ||
| 304 | .reg = WM8350_GPIO_INT_OFFSET, | ||
| 305 | .mask = WM8350_GP0_EINT, | ||
| 306 | }, | ||
| 307 | [WM8350_IRQ_GPIO(1)] = { | ||
| 308 | .primary = WM8350_GP_INT, | ||
| 309 | .reg = WM8350_GPIO_INT_OFFSET, | ||
| 310 | .mask = WM8350_GP1_EINT, | ||
| 311 | }, | ||
| 312 | [WM8350_IRQ_GPIO(2)] = { | ||
| 313 | .primary = WM8350_GP_INT, | ||
| 314 | .reg = WM8350_GPIO_INT_OFFSET, | ||
| 315 | .mask = WM8350_GP2_EINT, | ||
| 316 | }, | ||
| 317 | [WM8350_IRQ_GPIO(3)] = { | ||
| 318 | .primary = WM8350_GP_INT, | ||
| 319 | .reg = WM8350_GPIO_INT_OFFSET, | ||
| 320 | .mask = WM8350_GP3_EINT, | ||
| 321 | }, | ||
| 322 | [WM8350_IRQ_GPIO(4)] = { | ||
| 323 | .primary = WM8350_GP_INT, | ||
| 324 | .reg = WM8350_GPIO_INT_OFFSET, | ||
| 325 | .mask = WM8350_GP4_EINT, | ||
| 326 | }, | ||
| 327 | [WM8350_IRQ_GPIO(5)] = { | ||
| 328 | .primary = WM8350_GP_INT, | ||
| 329 | .reg = WM8350_GPIO_INT_OFFSET, | ||
| 330 | .mask = WM8350_GP5_EINT, | ||
| 331 | }, | ||
| 332 | [WM8350_IRQ_GPIO(6)] = { | ||
| 333 | .primary = WM8350_GP_INT, | ||
| 334 | .reg = WM8350_GPIO_INT_OFFSET, | ||
| 335 | .mask = WM8350_GP6_EINT, | ||
| 336 | }, | ||
| 337 | [WM8350_IRQ_GPIO(7)] = { | ||
| 338 | .primary = WM8350_GP_INT, | ||
| 339 | .reg = WM8350_GPIO_INT_OFFSET, | ||
| 340 | .mask = WM8350_GP7_EINT, | ||
| 341 | }, | ||
| 342 | [WM8350_IRQ_GPIO(8)] = { | ||
| 343 | .primary = WM8350_GP_INT, | ||
| 344 | .reg = WM8350_GPIO_INT_OFFSET, | ||
| 345 | .mask = WM8350_GP8_EINT, | ||
| 346 | }, | ||
| 347 | [WM8350_IRQ_GPIO(9)] = { | ||
| 348 | .primary = WM8350_GP_INT, | ||
| 349 | .reg = WM8350_GPIO_INT_OFFSET, | ||
| 350 | .mask = WM8350_GP9_EINT, | ||
| 351 | }, | ||
| 352 | [WM8350_IRQ_GPIO(10)] = { | ||
| 353 | .primary = WM8350_GP_INT, | ||
| 354 | .reg = WM8350_GPIO_INT_OFFSET, | ||
| 355 | .mask = WM8350_GP10_EINT, | ||
| 356 | }, | ||
| 357 | [WM8350_IRQ_GPIO(11)] = { | ||
| 358 | .primary = WM8350_GP_INT, | ||
| 359 | .reg = WM8350_GPIO_INT_OFFSET, | ||
| 360 | .mask = WM8350_GP11_EINT, | ||
| 361 | }, | ||
| 362 | [WM8350_IRQ_GPIO(12)] = { | ||
| 363 | .primary = WM8350_GP_INT, | ||
| 364 | .reg = WM8350_GPIO_INT_OFFSET, | ||
| 365 | .mask = WM8350_GP12_EINT, | ||
| 366 | }, | ||
| 367 | }; | ||
| 368 | |||
| 369 | static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq) | ||
| 370 | { | ||
| 371 | mutex_lock(&wm8350->irq_mutex); | ||
| 372 | |||
| 373 | if (wm8350->irq[irq].handler) | ||
| 374 | wm8350->irq[irq].handler(irq, wm8350->irq[irq].data); | ||
| 375 | else { | ||
| 376 | dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n", | ||
| 377 | irq); | ||
| 378 | wm8350_mask_irq(wm8350, irq); | ||
| 379 | } | ||
| 380 | |||
| 381 | mutex_unlock(&wm8350->irq_mutex); | ||
| 382 | } | ||
| 383 | |||
| 384 | /* | ||
| 385 | * This is a threaded IRQ handler so can access I2C/SPI. Since all | ||
| 386 | * interrupts are clear on read the IRQ line will be reasserted and | ||
| 387 | * the physical IRQ will be handled again if another interrupt is | ||
| 388 | * asserted while we run - in the normal course of events this is a | ||
| 389 | * rare occurrence so we save I2C/SPI reads. | ||
| 390 | */ | ||
| 391 | static irqreturn_t wm8350_irq(int irq, void *irq_data) | ||
| 392 | { | ||
| 393 | struct wm8350 *wm8350 = irq_data; | ||
| 394 | u16 level_one; | ||
| 395 | u16 sub_reg[WM8350_NUM_IRQ_REGS]; | ||
| 396 | int read_done[WM8350_NUM_IRQ_REGS]; | ||
| 397 | struct wm8350_irq_data *data; | ||
| 398 | int i; | ||
| 399 | |||
| 400 | /* TODO: Use block reads to improve performance? */ | ||
| 401 | level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS) | ||
| 402 | & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK); | ||
| 403 | |||
| 404 | if (!level_one) | ||
| 405 | return IRQ_NONE; | ||
| 406 | |||
| 407 | memset(&read_done, 0, sizeof(read_done)); | ||
| 408 | |||
| 409 | for (i = 0; i < ARRAY_SIZE(wm8350_irqs); i++) { | ||
| 410 | data = &wm8350_irqs[i]; | ||
| 411 | |||
| 412 | if (!(level_one & data->primary)) | ||
| 413 | continue; | ||
| 414 | |||
| 415 | if (!read_done[data->reg]) { | ||
| 416 | sub_reg[data->reg] = | ||
| 417 | wm8350_reg_read(wm8350, WM8350_INT_STATUS_1 + | ||
| 418 | data->reg); | ||
| 419 | sub_reg[data->reg] &= | ||
| 420 | ~wm8350_reg_read(wm8350, | ||
| 421 | WM8350_INT_STATUS_1_MASK + | ||
| 422 | data->reg); | ||
| 423 | read_done[data->reg] = 1; | ||
| 424 | } | ||
| 425 | |||
| 426 | if (sub_reg[data->reg] & data->mask) | ||
| 427 | wm8350_irq_call_handler(wm8350, i); | ||
| 428 | } | ||
| 429 | |||
| 430 | return IRQ_HANDLED; | ||
| 431 | } | ||
| 432 | |||
| 433 | int wm8350_register_irq(struct wm8350 *wm8350, int irq, | ||
| 434 | irq_handler_t handler, unsigned long flags, | ||
| 435 | const char *name, void *data) | ||
| 436 | { | ||
| 437 | if (irq < 0 || irq > WM8350_NUM_IRQ || !handler) | ||
| 438 | return -EINVAL; | ||
| 439 | |||
| 440 | if (wm8350->irq[irq].handler) | ||
| 441 | return -EBUSY; | ||
| 442 | |||
| 443 | mutex_lock(&wm8350->irq_mutex); | ||
| 444 | wm8350->irq[irq].handler = handler; | ||
| 445 | wm8350->irq[irq].data = data; | ||
| 446 | mutex_unlock(&wm8350->irq_mutex); | ||
| 447 | |||
| 448 | wm8350_unmask_irq(wm8350, irq); | ||
| 449 | |||
| 450 | return 0; | ||
| 451 | } | ||
| 452 | EXPORT_SYMBOL_GPL(wm8350_register_irq); | ||
| 453 | |||
| 454 | int wm8350_free_irq(struct wm8350 *wm8350, int irq) | ||
| 455 | { | ||
| 456 | if (irq < 0 || irq > WM8350_NUM_IRQ) | ||
| 457 | return -EINVAL; | ||
| 458 | |||
| 459 | wm8350_mask_irq(wm8350, irq); | ||
| 460 | |||
| 461 | mutex_lock(&wm8350->irq_mutex); | ||
| 462 | wm8350->irq[irq].handler = NULL; | ||
| 463 | mutex_unlock(&wm8350->irq_mutex); | ||
| 464 | return 0; | ||
| 465 | } | ||
| 466 | EXPORT_SYMBOL_GPL(wm8350_free_irq); | ||
| 467 | |||
| 468 | int wm8350_mask_irq(struct wm8350 *wm8350, int irq) | ||
| 469 | { | ||
| 470 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK + | ||
| 471 | wm8350_irqs[irq].reg, | ||
| 472 | wm8350_irqs[irq].mask); | ||
| 473 | } | ||
| 474 | EXPORT_SYMBOL_GPL(wm8350_mask_irq); | ||
| 475 | |||
| 476 | int wm8350_unmask_irq(struct wm8350 *wm8350, int irq) | ||
| 477 | { | ||
| 478 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK + | ||
| 479 | wm8350_irqs[irq].reg, | ||
| 480 | wm8350_irqs[irq].mask); | ||
| 481 | } | ||
| 482 | EXPORT_SYMBOL_GPL(wm8350_unmask_irq); | ||
| 483 | |||
| 484 | int wm8350_irq_init(struct wm8350 *wm8350, int irq, | ||
| 485 | struct wm8350_platform_data *pdata) | ||
| 486 | { | ||
| 487 | int ret; | ||
| 488 | int flags = IRQF_ONESHOT; | ||
| 489 | |||
| 490 | if (!irq) { | ||
| 491 | dev_err(wm8350->dev, "No IRQ configured\n"); | ||
| 492 | return -EINVAL; | ||
| 493 | } | ||
| 494 | |||
| 495 | wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF); | ||
| 496 | wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF); | ||
| 497 | wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF); | ||
| 498 | wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF); | ||
| 499 | wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF); | ||
| 500 | wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF); | ||
| 501 | |||
| 502 | mutex_init(&wm8350->irq_mutex); | ||
| 503 | wm8350->chip_irq = irq; | ||
| 504 | |||
| 505 | if (pdata && pdata->irq_high) { | ||
| 506 | flags |= IRQF_TRIGGER_HIGH; | ||
| 507 | |||
| 508 | wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1, | ||
| 509 | WM8350_IRQ_POL); | ||
| 510 | } else { | ||
| 511 | flags |= IRQF_TRIGGER_LOW; | ||
| 512 | |||
| 513 | wm8350_clear_bits(wm8350, WM8350_SYSTEM_CONTROL_1, | ||
| 514 | WM8350_IRQ_POL); | ||
| 515 | } | ||
| 516 | |||
| 517 | ret = request_threaded_irq(irq, NULL, wm8350_irq, flags, | ||
| 518 | "wm8350", wm8350); | ||
| 519 | if (ret != 0) | ||
| 520 | dev_err(wm8350->dev, "Failed to request IRQ: %d\n", ret); | ||
| 521 | |||
| 522 | return ret; | ||
| 523 | } | ||
| 524 | |||
| 525 | int wm8350_irq_exit(struct wm8350 *wm8350) | ||
| 526 | { | ||
| 527 | free_irq(wm8350->chip_irq, wm8350); | ||
| 528 | return 0; | ||
| 529 | } | ||
diff --git a/drivers/mfd/wm8350-regmap.c b/drivers/mfd/wm8350-regmap.c index 7ccc1eab98ab..e965139e5cd5 100644 --- a/drivers/mfd/wm8350-regmap.c +++ b/drivers/mfd/wm8350-regmap.c | |||
| @@ -3170,14 +3170,6 @@ const u16 wm8352_mode3_defaults[] = { | |||
| 3170 | }; | 3170 | }; |
| 3171 | #endif | 3171 | #endif |
| 3172 | 3172 | ||
| 3173 | /* The register defaults for the config mode used must be compiled in but | ||
| 3174 | * due to the impact on kernel size it is possible to disable | ||
| 3175 | */ | ||
| 3176 | #ifndef WM8350_HAVE_CONFIG_MODE | ||
| 3177 | #warning No WM8350 config modes supported - select at least one of the | ||
| 3178 | #warning MFD_WM8350_CONFIG_MODE_n options from the board driver. | ||
| 3179 | #endif | ||
| 3180 | |||
| 3181 | /* | 3173 | /* |
| 3182 | * Access masks. | 3174 | * Access masks. |
| 3183 | */ | 3175 | */ |
diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c index e8b278f71781..6a84a8eb8d7a 100644 --- a/drivers/power/pcf50633-charger.c +++ b/drivers/power/pcf50633-charger.c | |||
| @@ -303,7 +303,6 @@ static const u8 mbc_irq_handlers[] = { | |||
| 303 | static int __devinit pcf50633_mbc_probe(struct platform_device *pdev) | 303 | static int __devinit pcf50633_mbc_probe(struct platform_device *pdev) |
| 304 | { | 304 | { |
| 305 | struct pcf50633_mbc *mbc; | 305 | struct pcf50633_mbc *mbc; |
| 306 | struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data; | ||
| 307 | int ret; | 306 | int ret; |
| 308 | int i; | 307 | int i; |
| 309 | u8 mbcs1; | 308 | u8 mbcs1; |
| @@ -313,7 +312,7 @@ static int __devinit pcf50633_mbc_probe(struct platform_device *pdev) | |||
| 313 | return -ENOMEM; | 312 | return -ENOMEM; |
| 314 | 313 | ||
| 315 | platform_set_drvdata(pdev, mbc); | 314 | platform_set_drvdata(pdev, mbc); |
| 316 | mbc->pcf = pdata->pcf; | 315 | mbc->pcf = dev_to_pcf50633(pdev->dev.parent); |
| 317 | 316 | ||
| 318 | /* Set up IRQ handlers */ | 317 | /* Set up IRQ handlers */ |
| 319 | for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++) | 318 | for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++) |
diff --git a/drivers/power/wm8350_power.c b/drivers/power/wm8350_power.c index 28b0299c0043..ad4f071e1287 100644 --- a/drivers/power/wm8350_power.c +++ b/drivers/power/wm8350_power.c | |||
| @@ -184,8 +184,9 @@ static ssize_t charger_state_show(struct device *dev, | |||
| 184 | 184 | ||
| 185 | static DEVICE_ATTR(charger_state, 0444, charger_state_show, NULL); | 185 | static DEVICE_ATTR(charger_state, 0444, charger_state_show, NULL); |
| 186 | 186 | ||
| 187 | static void wm8350_charger_handler(struct wm8350 *wm8350, int irq, void *data) | 187 | static irqreturn_t wm8350_charger_handler(int irq, void *data) |
| 188 | { | 188 | { |
| 189 | struct wm8350 *wm8350 = data; | ||
| 189 | struct wm8350_power *power = &wm8350->power; | 190 | struct wm8350_power *power = &wm8350->power; |
| 190 | struct wm8350_charger_policy *policy = power->policy; | 191 | struct wm8350_charger_policy *policy = power->policy; |
| 191 | 192 | ||
| @@ -238,6 +239,8 @@ static void wm8350_charger_handler(struct wm8350 *wm8350, int irq, void *data) | |||
| 238 | default: | 239 | default: |
| 239 | dev_err(wm8350->dev, "Unknown interrupt %d\n", irq); | 240 | dev_err(wm8350->dev, "Unknown interrupt %d\n", irq); |
| 240 | } | 241 | } |
| 242 | |||
| 243 | return IRQ_HANDLED; | ||
| 241 | } | 244 | } |
| 242 | 245 | ||
| 243 | /********************************************************************* | 246 | /********************************************************************* |
| @@ -387,73 +390,55 @@ static void wm8350_init_charger(struct wm8350 *wm8350) | |||
| 387 | { | 390 | { |
| 388 | /* register our interest in charger events */ | 391 | /* register our interest in charger events */ |
| 389 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, | 392 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, |
| 390 | wm8350_charger_handler, NULL); | 393 | wm8350_charger_handler, 0, "Battery hot", wm8350); |
| 391 | wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT); | ||
| 392 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, | 394 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, |
| 393 | wm8350_charger_handler, NULL); | 395 | wm8350_charger_handler, 0, "Battery cold", wm8350); |
| 394 | wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD); | ||
| 395 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, | 396 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, |
| 396 | wm8350_charger_handler, NULL); | 397 | wm8350_charger_handler, 0, "Battery fail", wm8350); |
| 397 | wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL); | ||
| 398 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO, | 398 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO, |
| 399 | wm8350_charger_handler, NULL); | 399 | wm8350_charger_handler, 0, |
| 400 | wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_TO); | 400 | "Charger timeout", wm8350); |
| 401 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END, | 401 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END, |
| 402 | wm8350_charger_handler, NULL); | 402 | wm8350_charger_handler, 0, |
| 403 | wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_END); | 403 | "Charge end", wm8350); |
| 404 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START, | 404 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START, |
| 405 | wm8350_charger_handler, NULL); | 405 | wm8350_charger_handler, 0, |
| 406 | wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_START); | 406 | "Charge start", wm8350); |
| 407 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, | 407 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, |
| 408 | wm8350_charger_handler, NULL); | 408 | wm8350_charger_handler, 0, |
| 409 | wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY); | 409 | "Fast charge ready", wm8350); |
| 410 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, | 410 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, |
| 411 | wm8350_charger_handler, NULL); | 411 | wm8350_charger_handler, 0, |
| 412 | wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9); | 412 | "Battery <3.9V", wm8350); |
| 413 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, | 413 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, |
| 414 | wm8350_charger_handler, NULL); | 414 | wm8350_charger_handler, 0, |
| 415 | wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1); | 415 | "Battery <3.1V", wm8350); |
| 416 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, | 416 | wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, |
| 417 | wm8350_charger_handler, NULL); | 417 | wm8350_charger_handler, 0, |
| 418 | wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85); | 418 | "Battery <2.85V", wm8350); |
| 419 | 419 | ||
| 420 | /* and supply change events */ | 420 | /* and supply change events */ |
| 421 | wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB, | 421 | wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB, |
| 422 | wm8350_charger_handler, NULL); | 422 | wm8350_charger_handler, 0, "USB", wm8350); |
| 423 | wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_USB_FB); | ||
| 424 | wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, | 423 | wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, |
| 425 | wm8350_charger_handler, NULL); | 424 | wm8350_charger_handler, 0, "Wall", wm8350); |
| 426 | wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_WALL_FB); | ||
| 427 | wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, | 425 | wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, |
| 428 | wm8350_charger_handler, NULL); | 426 | wm8350_charger_handler, 0, "Battery", wm8350); |
| 429 | wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_BAT_FB); | ||
| 430 | } | 427 | } |
| 431 | 428 | ||
| 432 | static void free_charger_irq(struct wm8350 *wm8350) | 429 | static void free_charger_irq(struct wm8350 *wm8350) |
| 433 | { | 430 | { |
| 434 | wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT); | ||
| 435 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT); | 431 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT); |
| 436 | wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD); | ||
| 437 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD); | 432 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD); |
| 438 | wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL); | ||
| 439 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL); | 433 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL); |
| 440 | wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_TO); | ||
| 441 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO); | 434 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO); |
| 442 | wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_END); | ||
| 443 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END); | 435 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END); |
| 444 | wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_START); | ||
| 445 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START); | 436 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START); |
| 446 | wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9); | ||
| 447 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9); | 437 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9); |
| 448 | wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1); | ||
| 449 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1); | 438 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1); |
| 450 | wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85); | ||
| 451 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85); | 439 | wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85); |
| 452 | wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_USB_FB); | ||
| 453 | wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB); | 440 | wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB); |
| 454 | wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_WALL_FB); | ||
| 455 | wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB); | 441 | wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB); |
| 456 | wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_BAT_FB); | ||
| 457 | wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB); | 442 | wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB); |
| 458 | } | 443 | } |
| 459 | 444 | ||
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index bcbb161bde0b..7cfdd65bebb4 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig | |||
| @@ -70,7 +70,7 @@ config REGULATOR_MAX1586 | |||
| 70 | for PXA27x chips to control VCC_CORE and VCC_USIM voltages. | 70 | for PXA27x chips to control VCC_CORE and VCC_USIM voltages. |
| 71 | 71 | ||
| 72 | config REGULATOR_TWL4030 | 72 | config REGULATOR_TWL4030 |
| 73 | bool "TI TWL4030/TWL5030/TPS695x0 PMIC" | 73 | bool "TI TWL4030/TWL5030/TWL6030/TPS695x0 PMIC" |
| 74 | depends on TWL4030_CORE | 74 | depends on TWL4030_CORE |
| 75 | help | 75 | help |
| 76 | This driver supports the voltage regulators provided by | 76 | This driver supports the voltage regulators provided by |
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 4257a8683778..9ae3cc44e668 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile | |||
| @@ -11,7 +11,7 @@ obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o | |||
| 11 | obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o | 11 | obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o |
| 12 | obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o | 12 | obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o |
| 13 | obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o | 13 | obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o |
| 14 | obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o | 14 | obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o |
| 15 | obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o | 15 | obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o |
| 16 | obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o | 16 | obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o |
| 17 | obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o | 17 | obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o |
diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index 0803ffe6236d..c8f41dc05b76 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c | |||
| @@ -314,13 +314,15 @@ static int __devinit pcf50633_regulator_probe(struct platform_device *pdev) | |||
| 314 | struct pcf50633 *pcf; | 314 | struct pcf50633 *pcf; |
| 315 | 315 | ||
| 316 | /* Already set by core driver */ | 316 | /* Already set by core driver */ |
| 317 | pcf = platform_get_drvdata(pdev); | 317 | pcf = dev_to_pcf50633(pdev->dev.parent); |
| 318 | 318 | ||
| 319 | rdev = regulator_register(®ulators[pdev->id], &pdev->dev, | 319 | rdev = regulator_register(®ulators[pdev->id], &pdev->dev, |
| 320 | pdev->dev.platform_data, pcf); | 320 | pdev->dev.platform_data, pcf); |
| 321 | if (IS_ERR(rdev)) | 321 | if (IS_ERR(rdev)) |
| 322 | return PTR_ERR(rdev); | 322 | return PTR_ERR(rdev); |
| 323 | 323 | ||
| 324 | platform_set_drvdata(pdev, rdev); | ||
| 325 | |||
| 324 | if (pcf->pdata->regulator_registered) | 326 | if (pcf->pdata->regulator_registered) |
| 325 | pcf->pdata->regulator_registered(pcf, pdev->id); | 327 | pcf->pdata->regulator_registered(pcf, pdev->id); |
| 326 | 328 | ||
| @@ -331,6 +333,7 @@ static int __devexit pcf50633_regulator_remove(struct platform_device *pdev) | |||
| 331 | { | 333 | { |
| 332 | struct regulator_dev *rdev = platform_get_drvdata(pdev); | 334 | struct regulator_dev *rdev = platform_get_drvdata(pdev); |
| 333 | 335 | ||
| 336 | platform_set_drvdata(pdev, NULL); | ||
| 334 | regulator_unregister(rdev); | 337 | regulator_unregister(rdev); |
| 335 | 338 | ||
| 336 | return 0; | 339 | return 0; |
diff --git a/drivers/regulator/twl4030-regulator.c b/drivers/regulator/twl-regulator.c index e2032fb60b55..7ea1c3a31081 100644 --- a/drivers/regulator/twl4030-regulator.c +++ b/drivers/regulator/twl-regulator.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * twl4030-regulator.c -- support regulators in twl4030 family chips | 2 | * twl-regulator.c -- support regulators in twl4030/twl6030 family chips |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2008 David Brownell | 4 | * Copyright (C) 2008 David Brownell |
| 5 | * | 5 | * |
| @@ -15,11 +15,11 @@ | |||
| 15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
| 16 | #include <linux/regulator/driver.h> | 16 | #include <linux/regulator/driver.h> |
| 17 | #include <linux/regulator/machine.h> | 17 | #include <linux/regulator/machine.h> |
| 18 | #include <linux/i2c/twl4030.h> | 18 | #include <linux/i2c/twl.h> |
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | /* | 21 | /* |
| 22 | * The TWL4030/TW5030/TPS659x0 family chips include power management, a | 22 | * The TWL4030/TW5030/TPS659x0/TWL6030 family chips include power management, a |
| 23 | * USB OTG transceiver, an RTC, ADC, PWM, and lots more. Some versions | 23 | * USB OTG transceiver, an RTC, ADC, PWM, and lots more. Some versions |
| 24 | * include an audio codec, battery charger, and more voltage regulators. | 24 | * include an audio codec, battery charger, and more voltage regulators. |
| 25 | * These chips are often used in OMAP-based systems. | 25 | * These chips are often used in OMAP-based systems. |
| @@ -33,7 +33,7 @@ struct twlreg_info { | |||
| 33 | /* start of regulator's PM_RECEIVER control register bank */ | 33 | /* start of regulator's PM_RECEIVER control register bank */ |
| 34 | u8 base; | 34 | u8 base; |
| 35 | 35 | ||
| 36 | /* twl4030 resource ID, for resource control state machine */ | 36 | /* twl resource ID, for resource control state machine */ |
| 37 | u8 id; | 37 | u8 id; |
| 38 | 38 | ||
| 39 | /* voltage in mV = table[VSEL]; table_len must be a power-of-two */ | 39 | /* voltage in mV = table[VSEL]; table_len must be a power-of-two */ |
| @@ -52,27 +52,38 @@ struct twlreg_info { | |||
| 52 | * The first three registers of all power resource banks help hardware to | 52 | * The first three registers of all power resource banks help hardware to |
| 53 | * manage the various resource groups. | 53 | * manage the various resource groups. |
| 54 | */ | 54 | */ |
| 55 | /* Common offset in TWL4030/6030 */ | ||
| 55 | #define VREG_GRP 0 | 56 | #define VREG_GRP 0 |
| 57 | /* TWL4030 register offsets */ | ||
| 56 | #define VREG_TYPE 1 | 58 | #define VREG_TYPE 1 |
| 57 | #define VREG_REMAP 2 | 59 | #define VREG_REMAP 2 |
| 58 | #define VREG_DEDICATED 3 /* LDO control */ | 60 | #define VREG_DEDICATED 3 /* LDO control */ |
| 59 | 61 | /* TWL6030 register offsets */ | |
| 62 | #define VREG_TRANS 1 | ||
| 63 | #define VREG_STATE 2 | ||
| 64 | #define VREG_VOLTAGE 3 | ||
| 65 | /* TWL6030 Misc register offsets */ | ||
| 66 | #define VREG_BC_ALL 1 | ||
| 67 | #define VREG_BC_REF 2 | ||
| 68 | #define VREG_BC_PROC 3 | ||
| 69 | #define VREG_BC_CLK_RST 4 | ||
| 60 | 70 | ||
| 61 | static inline int | 71 | static inline int |
| 62 | twl4030reg_read(struct twlreg_info *info, unsigned offset) | 72 | twlreg_read(struct twlreg_info *info, unsigned slave_subgp, unsigned offset) |
| 63 | { | 73 | { |
| 64 | u8 value; | 74 | u8 value; |
| 65 | int status; | 75 | int status; |
| 66 | 76 | ||
| 67 | status = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, | 77 | status = twl_i2c_read_u8(slave_subgp, |
| 68 | &value, info->base + offset); | 78 | &value, info->base + offset); |
| 69 | return (status < 0) ? status : value; | 79 | return (status < 0) ? status : value; |
| 70 | } | 80 | } |
| 71 | 81 | ||
| 72 | static inline int | 82 | static inline int |
| 73 | twl4030reg_write(struct twlreg_info *info, unsigned offset, u8 value) | 83 | twlreg_write(struct twlreg_info *info, unsigned slave_subgp, unsigned offset, |
| 84 | u8 value) | ||
| 74 | { | 85 | { |
| 75 | return twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, | 86 | return twl_i2c_write_u8(slave_subgp, |
| 76 | value, info->base + offset); | 87 | value, info->base + offset); |
| 77 | } | 88 | } |
| 78 | 89 | ||
| @@ -80,59 +91,79 @@ twl4030reg_write(struct twlreg_info *info, unsigned offset, u8 value) | |||
| 80 | 91 | ||
| 81 | /* generic power resource operations, which work on all regulators */ | 92 | /* generic power resource operations, which work on all regulators */ |
| 82 | 93 | ||
| 83 | static int twl4030reg_grp(struct regulator_dev *rdev) | 94 | static int twlreg_grp(struct regulator_dev *rdev) |
| 84 | { | 95 | { |
| 85 | return twl4030reg_read(rdev_get_drvdata(rdev), VREG_GRP); | 96 | return twlreg_read(rdev_get_drvdata(rdev), TWL_MODULE_PM_RECEIVER, |
| 97 | VREG_GRP); | ||
| 86 | } | 98 | } |
| 87 | 99 | ||
| 88 | /* | 100 | /* |
| 89 | * Enable/disable regulators by joining/leaving the P1 (processor) group. | 101 | * Enable/disable regulators by joining/leaving the P1 (processor) group. |
| 90 | * We assume nobody else is updating the DEV_GRP registers. | 102 | * We assume nobody else is updating the DEV_GRP registers. |
| 91 | */ | 103 | */ |
| 92 | 104 | /* definition for 4030 family */ | |
| 93 | #define P3_GRP BIT(7) /* "peripherals" */ | 105 | #define P3_GRP_4030 BIT(7) /* "peripherals" */ |
| 94 | #define P2_GRP BIT(6) /* secondary processor, modem, etc */ | 106 | #define P2_GRP_4030 BIT(6) /* secondary processor, modem, etc */ |
| 95 | #define P1_GRP BIT(5) /* CPU/Linux */ | 107 | #define P1_GRP_4030 BIT(5) /* CPU/Linux */ |
| 96 | 108 | /* definition for 6030 family */ | |
| 97 | static int twl4030reg_is_enabled(struct regulator_dev *rdev) | 109 | #define P3_GRP_6030 BIT(2) /* secondary processor, modem, etc */ |
| 110 | #define P2_GRP_6030 BIT(1) /* "peripherals" */ | ||
| 111 | #define P1_GRP_6030 BIT(0) /* CPU/Linux */ | ||
| 112 | |||
| 113 | static int twlreg_is_enabled(struct regulator_dev *rdev) | ||
| 98 | { | 114 | { |
| 99 | int state = twl4030reg_grp(rdev); | 115 | int state = twlreg_grp(rdev); |
| 100 | 116 | ||
| 101 | if (state < 0) | 117 | if (state < 0) |
| 102 | return state; | 118 | return state; |
| 103 | 119 | ||
| 104 | return (state & P1_GRP) != 0; | 120 | if (twl_class_is_4030()) |
| 121 | state &= P1_GRP_4030; | ||
| 122 | else | ||
| 123 | state &= P1_GRP_6030; | ||
| 124 | return state; | ||
| 105 | } | 125 | } |
| 106 | 126 | ||
| 107 | static int twl4030reg_enable(struct regulator_dev *rdev) | 127 | static int twlreg_enable(struct regulator_dev *rdev) |
| 108 | { | 128 | { |
| 109 | struct twlreg_info *info = rdev_get_drvdata(rdev); | 129 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
| 110 | int grp; | 130 | int grp; |
| 111 | 131 | ||
| 112 | grp = twl4030reg_read(info, VREG_GRP); | 132 | grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP); |
| 113 | if (grp < 0) | 133 | if (grp < 0) |
| 114 | return grp; | 134 | return grp; |
| 115 | 135 | ||
| 116 | grp |= P1_GRP; | 136 | if (twl_class_is_4030()) |
| 117 | return twl4030reg_write(info, VREG_GRP, grp); | 137 | grp |= P1_GRP_4030; |
| 138 | else | ||
| 139 | grp |= P1_GRP_6030; | ||
| 140 | |||
| 141 | return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp); | ||
| 118 | } | 142 | } |
| 119 | 143 | ||
| 120 | static int twl4030reg_disable(struct regulator_dev *rdev) | 144 | static int twlreg_disable(struct regulator_dev *rdev) |
| 121 | { | 145 | { |
| 122 | struct twlreg_info *info = rdev_get_drvdata(rdev); | 146 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
| 123 | int grp; | 147 | int grp; |
| 124 | 148 | ||
| 125 | grp = twl4030reg_read(info, VREG_GRP); | 149 | grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP); |
| 126 | if (grp < 0) | 150 | if (grp < 0) |
| 127 | return grp; | 151 | return grp; |
| 128 | 152 | ||
| 129 | grp &= ~P1_GRP; | 153 | if (twl_class_is_4030()) |
| 130 | return twl4030reg_write(info, VREG_GRP, grp); | 154 | grp &= ~P1_GRP_4030; |
| 155 | else | ||
| 156 | grp &= ~P1_GRP_6030; | ||
| 157 | |||
| 158 | return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp); | ||
| 131 | } | 159 | } |
| 132 | 160 | ||
| 133 | static int twl4030reg_get_status(struct regulator_dev *rdev) | 161 | static int twlreg_get_status(struct regulator_dev *rdev) |
| 134 | { | 162 | { |
| 135 | int state = twl4030reg_grp(rdev); | 163 | int state = twlreg_grp(rdev); |
| 164 | |||
| 165 | if (twl_class_is_6030()) | ||
| 166 | return 0; /* FIXME return for 6030 regulator */ | ||
| 136 | 167 | ||
| 137 | if (state < 0) | 168 | if (state < 0) |
| 138 | return state; | 169 | return state; |
| @@ -146,12 +177,15 @@ static int twl4030reg_get_status(struct regulator_dev *rdev) | |||
| 146 | : REGULATOR_STATUS_STANDBY; | 177 | : REGULATOR_STATUS_STANDBY; |
| 147 | } | 178 | } |
| 148 | 179 | ||
| 149 | static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode) | 180 | static int twlreg_set_mode(struct regulator_dev *rdev, unsigned mode) |
| 150 | { | 181 | { |
| 151 | struct twlreg_info *info = rdev_get_drvdata(rdev); | 182 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
| 152 | unsigned message; | 183 | unsigned message; |
| 153 | int status; | 184 | int status; |
| 154 | 185 | ||
| 186 | if (twl_class_is_6030()) | ||
| 187 | return 0; /* FIXME return for 6030 regulator */ | ||
| 188 | |||
| 155 | /* We can only set the mode through state machine commands... */ | 189 | /* We can only set the mode through state machine commands... */ |
| 156 | switch (mode) { | 190 | switch (mode) { |
| 157 | case REGULATOR_MODE_NORMAL: | 191 | case REGULATOR_MODE_NORMAL: |
| @@ -165,18 +199,18 @@ static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode) | |||
| 165 | } | 199 | } |
| 166 | 200 | ||
| 167 | /* Ensure the resource is associated with some group */ | 201 | /* Ensure the resource is associated with some group */ |
| 168 | status = twl4030reg_grp(rdev); | 202 | status = twlreg_grp(rdev); |
| 169 | if (status < 0) | 203 | if (status < 0) |
| 170 | return status; | 204 | return status; |
| 171 | if (!(status & (P3_GRP | P2_GRP | P1_GRP))) | 205 | if (!(status & (P3_GRP_4030 | P2_GRP_4030 | P1_GRP_4030))) |
| 172 | return -EACCES; | 206 | return -EACCES; |
| 173 | 207 | ||
| 174 | status = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, | 208 | status = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, |
| 175 | message >> 8, 0x15 /* PB_WORD_MSB */ ); | 209 | message >> 8, 0x15 /* PB_WORD_MSB */ ); |
| 176 | if (status >= 0) | 210 | if (status >= 0) |
| 177 | return status; | 211 | return status; |
| 178 | 212 | ||
| 179 | return twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, | 213 | return twl_i2c_write_u8(TWL_MODULE_PM_MASTER, |
| 180 | message, 0x16 /* PB_WORD_LSB */ ); | 214 | message, 0x16 /* PB_WORD_LSB */ ); |
| 181 | } | 215 | } |
| 182 | 216 | ||
| @@ -260,9 +294,31 @@ static const u16 VSIM_VSEL_table[] = { | |||
| 260 | static const u16 VDAC_VSEL_table[] = { | 294 | static const u16 VDAC_VSEL_table[] = { |
| 261 | 1200, 1300, 1800, 1800, | 295 | 1200, 1300, 1800, 1800, |
| 262 | }; | 296 | }; |
| 297 | static const u16 VAUX1_6030_VSEL_table[] = { | ||
| 298 | 1000, 1300, 1800, 2500, | ||
| 299 | 2800, 2900, 3000, 3000, | ||
| 300 | }; | ||
| 301 | static const u16 VAUX2_6030_VSEL_table[] = { | ||
| 302 | 1200, 1800, 2500, 2750, | ||
| 303 | 2800, 2800, 2800, 2800, | ||
| 304 | }; | ||
| 305 | static const u16 VAUX3_6030_VSEL_table[] = { | ||
| 306 | 1000, 1200, 1300, 1800, | ||
| 307 | 2500, 2800, 3000, 3000, | ||
| 308 | }; | ||
| 309 | static const u16 VMMC_VSEL_table[] = { | ||
| 310 | 1200, 1800, 2800, 2900, | ||
| 311 | 3000, 3000, 3000, 3000, | ||
| 312 | }; | ||
| 313 | static const u16 VPP_VSEL_table[] = { | ||
| 314 | 1800, 1900, 2000, 2100, | ||
| 315 | 2200, 2300, 2400, 2500, | ||
| 316 | }; | ||
| 317 | static const u16 VUSIM_VSEL_table[] = { | ||
| 318 | 1200, 1800, 2500, 2900, | ||
| 319 | }; | ||
| 263 | 320 | ||
| 264 | 321 | static int twlldo_list_voltage(struct regulator_dev *rdev, unsigned index) | |
| 265 | static int twl4030ldo_list_voltage(struct regulator_dev *rdev, unsigned index) | ||
| 266 | { | 322 | { |
| 267 | struct twlreg_info *info = rdev_get_drvdata(rdev); | 323 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
| 268 | int mV = info->table[index]; | 324 | int mV = info->table[index]; |
| @@ -271,7 +327,7 @@ static int twl4030ldo_list_voltage(struct regulator_dev *rdev, unsigned index) | |||
| 271 | } | 327 | } |
| 272 | 328 | ||
| 273 | static int | 329 | static int |
| 274 | twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) | 330 | twlldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) |
| 275 | { | 331 | { |
| 276 | struct twlreg_info *info = rdev_get_drvdata(rdev); | 332 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
| 277 | int vsel; | 333 | int vsel; |
| @@ -288,16 +344,18 @@ twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) | |||
| 288 | 344 | ||
| 289 | /* use the first in-range value */ | 345 | /* use the first in-range value */ |
| 290 | if (min_uV <= uV && uV <= max_uV) | 346 | if (min_uV <= uV && uV <= max_uV) |
| 291 | return twl4030reg_write(info, VREG_DEDICATED, vsel); | 347 | return twlreg_write(info, TWL_MODULE_PM_RECEIVER, |
| 348 | VREG_VOLTAGE, vsel); | ||
| 292 | } | 349 | } |
| 293 | 350 | ||
| 294 | return -EDOM; | 351 | return -EDOM; |
| 295 | } | 352 | } |
| 296 | 353 | ||
| 297 | static int twl4030ldo_get_voltage(struct regulator_dev *rdev) | 354 | static int twlldo_get_voltage(struct regulator_dev *rdev) |
| 298 | { | 355 | { |
| 299 | struct twlreg_info *info = rdev_get_drvdata(rdev); | 356 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
| 300 | int vsel = twl4030reg_read(info, VREG_DEDICATED); | 357 | int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, |
| 358 | VREG_VOLTAGE); | ||
| 301 | 359 | ||
| 302 | if (vsel < 0) | 360 | if (vsel < 0) |
| 303 | return vsel; | 361 | return vsel; |
| @@ -306,19 +364,19 @@ static int twl4030ldo_get_voltage(struct regulator_dev *rdev) | |||
| 306 | return LDO_MV(info->table[vsel]) * 1000; | 364 | return LDO_MV(info->table[vsel]) * 1000; |
| 307 | } | 365 | } |
| 308 | 366 | ||
| 309 | static struct regulator_ops twl4030ldo_ops = { | 367 | static struct regulator_ops twlldo_ops = { |
| 310 | .list_voltage = twl4030ldo_list_voltage, | 368 | .list_voltage = twlldo_list_voltage, |
| 311 | 369 | ||
| 312 | .set_voltage = twl4030ldo_set_voltage, | 370 | .set_voltage = twlldo_set_voltage, |
| 313 | .get_voltage = twl4030ldo_get_voltage, | 371 | .get_voltage = twlldo_get_voltage, |
| 314 | 372 | ||
| 315 | .enable = twl4030reg_enable, | 373 | .enable = twlreg_enable, |
| 316 | .disable = twl4030reg_disable, | 374 | .disable = twlreg_disable, |
| 317 | .is_enabled = twl4030reg_is_enabled, | 375 | .is_enabled = twlreg_is_enabled, |
| 318 | 376 | ||
| 319 | .set_mode = twl4030reg_set_mode, | 377 | .set_mode = twlreg_set_mode, |
| 320 | 378 | ||
| 321 | .get_status = twl4030reg_get_status, | 379 | .get_status = twlreg_get_status, |
| 322 | }; | 380 | }; |
| 323 | 381 | ||
| 324 | /*----------------------------------------------------------------------*/ | 382 | /*----------------------------------------------------------------------*/ |
| @@ -326,60 +384,69 @@ static struct regulator_ops twl4030ldo_ops = { | |||
| 326 | /* | 384 | /* |
| 327 | * Fixed voltage LDOs don't have a VSEL field to update. | 385 | * Fixed voltage LDOs don't have a VSEL field to update. |
| 328 | */ | 386 | */ |
| 329 | static int twl4030fixed_list_voltage(struct regulator_dev *rdev, unsigned index) | 387 | static int twlfixed_list_voltage(struct regulator_dev *rdev, unsigned index) |
| 330 | { | 388 | { |
| 331 | struct twlreg_info *info = rdev_get_drvdata(rdev); | 389 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
| 332 | 390 | ||
| 333 | return info->min_mV * 1000; | 391 | return info->min_mV * 1000; |
| 334 | } | 392 | } |
| 335 | 393 | ||
| 336 | static int twl4030fixed_get_voltage(struct regulator_dev *rdev) | 394 | static int twlfixed_get_voltage(struct regulator_dev *rdev) |
| 337 | { | 395 | { |
| 338 | struct twlreg_info *info = rdev_get_drvdata(rdev); | 396 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
| 339 | 397 | ||
| 340 | return info->min_mV * 1000; | 398 | return info->min_mV * 1000; |
| 341 | } | 399 | } |
| 342 | 400 | ||
| 343 | static struct regulator_ops twl4030fixed_ops = { | 401 | static struct regulator_ops twlfixed_ops = { |
| 344 | .list_voltage = twl4030fixed_list_voltage, | 402 | .list_voltage = twlfixed_list_voltage, |
| 345 | 403 | ||
| 346 | .get_voltage = twl4030fixed_get_voltage, | 404 | .get_voltage = twlfixed_get_voltage, |
| 347 | 405 | ||
| 348 | .enable = twl4030reg_enable, | 406 | .enable = twlreg_enable, |
| 349 | .disable = twl4030reg_disable, | 407 | .disable = twlreg_disable, |
| 350 | .is_enabled = twl4030reg_is_enabled, | 408 | .is_enabled = twlreg_is_enabled, |
| 351 | 409 | ||
| 352 | .set_mode = twl4030reg_set_mode, | 410 | .set_mode = twlreg_set_mode, |
| 353 | 411 | ||
| 354 | .get_status = twl4030reg_get_status, | 412 | .get_status = twlreg_get_status, |
| 355 | }; | 413 | }; |
| 356 | 414 | ||
| 357 | /*----------------------------------------------------------------------*/ | 415 | /*----------------------------------------------------------------------*/ |
| 358 | 416 | ||
| 359 | #define TWL_ADJUSTABLE_LDO(label, offset, num) { \ | 417 | #define TWL4030_ADJUSTABLE_LDO(label, offset, num) \ |
| 418 | TWL_ADJUSTABLE_LDO(label, offset, num, TWL4030) | ||
| 419 | #define TWL4030_FIXED_LDO(label, offset, mVolts, num) \ | ||
| 420 | TWL_FIXED_LDO(label, offset, mVolts, num, TWL4030) | ||
| 421 | #define TWL6030_ADJUSTABLE_LDO(label, offset, num) \ | ||
| 422 | TWL_ADJUSTABLE_LDO(label, offset, num, TWL6030) | ||
| 423 | #define TWL6030_FIXED_LDO(label, offset, mVolts, num) \ | ||
| 424 | TWL_FIXED_LDO(label, offset, mVolts, num, TWL6030) | ||
| 425 | |||
| 426 | #define TWL_ADJUSTABLE_LDO(label, offset, num, family) { \ | ||
| 360 | .base = offset, \ | 427 | .base = offset, \ |
| 361 | .id = num, \ | 428 | .id = num, \ |
| 362 | .table_len = ARRAY_SIZE(label##_VSEL_table), \ | 429 | .table_len = ARRAY_SIZE(label##_VSEL_table), \ |
| 363 | .table = label##_VSEL_table, \ | 430 | .table = label##_VSEL_table, \ |
| 364 | .desc = { \ | 431 | .desc = { \ |
| 365 | .name = #label, \ | 432 | .name = #label, \ |
| 366 | .id = TWL4030_REG_##label, \ | 433 | .id = family##_REG_##label, \ |
| 367 | .n_voltages = ARRAY_SIZE(label##_VSEL_table), \ | 434 | .n_voltages = ARRAY_SIZE(label##_VSEL_table), \ |
| 368 | .ops = &twl4030ldo_ops, \ | 435 | .ops = &twlldo_ops, \ |
| 369 | .type = REGULATOR_VOLTAGE, \ | 436 | .type = REGULATOR_VOLTAGE, \ |
| 370 | .owner = THIS_MODULE, \ | 437 | .owner = THIS_MODULE, \ |
| 371 | }, \ | 438 | }, \ |
| 372 | } | 439 | } |
| 373 | 440 | ||
| 374 | #define TWL_FIXED_LDO(label, offset, mVolts, num) { \ | 441 | #define TWL_FIXED_LDO(label, offset, mVolts, num, family) { \ |
| 375 | .base = offset, \ | 442 | .base = offset, \ |
| 376 | .id = num, \ | 443 | .id = num, \ |
| 377 | .min_mV = mVolts, \ | 444 | .min_mV = mVolts, \ |
| 378 | .desc = { \ | 445 | .desc = { \ |
| 379 | .name = #label, \ | 446 | .name = #label, \ |
| 380 | .id = TWL4030_REG_##label, \ | 447 | .id = family##_REG_##label, \ |
| 381 | .n_voltages = 1, \ | 448 | .n_voltages = 1, \ |
| 382 | .ops = &twl4030fixed_ops, \ | 449 | .ops = &twlfixed_ops, \ |
| 383 | .type = REGULATOR_VOLTAGE, \ | 450 | .type = REGULATOR_VOLTAGE, \ |
| 384 | .owner = THIS_MODULE, \ | 451 | .owner = THIS_MODULE, \ |
| 385 | }, \ | 452 | }, \ |
| @@ -389,35 +456,47 @@ static struct regulator_ops twl4030fixed_ops = { | |||
| 389 | * We list regulators here if systems need some level of | 456 | * We list regulators here if systems need some level of |
| 390 | * software control over them after boot. | 457 | * software control over them after boot. |
| 391 | */ | 458 | */ |
| 392 | static struct twlreg_info twl4030_regs[] = { | 459 | static struct twlreg_info twl_regs[] = { |
| 393 | TWL_ADJUSTABLE_LDO(VAUX1, 0x17, 1), | 460 | TWL4030_ADJUSTABLE_LDO(VAUX1, 0x17, 1), |
| 394 | TWL_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2), | 461 | TWL4030_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2), |
| 395 | TWL_ADJUSTABLE_LDO(VAUX2, 0x1b, 2), | 462 | TWL4030_ADJUSTABLE_LDO(VAUX2, 0x1b, 2), |
| 396 | TWL_ADJUSTABLE_LDO(VAUX3, 0x1f, 3), | 463 | TWL4030_ADJUSTABLE_LDO(VAUX3, 0x1f, 3), |
| 397 | TWL_ADJUSTABLE_LDO(VAUX4, 0x23, 4), | 464 | TWL4030_ADJUSTABLE_LDO(VAUX4, 0x23, 4), |
| 398 | TWL_ADJUSTABLE_LDO(VMMC1, 0x27, 5), | 465 | TWL4030_ADJUSTABLE_LDO(VMMC1, 0x27, 5), |
| 399 | TWL_ADJUSTABLE_LDO(VMMC2, 0x2b, 6), | 466 | TWL4030_ADJUSTABLE_LDO(VMMC2, 0x2b, 6), |
| 400 | /* | 467 | /* |
| 401 | TWL_ADJUSTABLE_LDO(VPLL1, 0x2f, 7), | 468 | TWL4030_ADJUSTABLE_LDO(VPLL1, 0x2f, 7), |
| 402 | */ | 469 | */ |
| 403 | TWL_ADJUSTABLE_LDO(VPLL2, 0x33, 8), | 470 | TWL4030_ADJUSTABLE_LDO(VPLL2, 0x33, 8), |
| 404 | TWL_ADJUSTABLE_LDO(VSIM, 0x37, 9), | 471 | TWL4030_ADJUSTABLE_LDO(VSIM, 0x37, 9), |
| 405 | TWL_ADJUSTABLE_LDO(VDAC, 0x3b, 10), | 472 | TWL4030_ADJUSTABLE_LDO(VDAC, 0x3b, 10), |
| 406 | /* | 473 | /* |
| 407 | TWL_ADJUSTABLE_LDO(VINTANA1, 0x3f, 11), | 474 | TWL4030_ADJUSTABLE_LDO(VINTANA1, 0x3f, 11), |
| 408 | TWL_ADJUSTABLE_LDO(VINTANA2, 0x43, 12), | 475 | TWL4030_ADJUSTABLE_LDO(VINTANA2, 0x43, 12), |
| 409 | TWL_ADJUSTABLE_LDO(VINTDIG, 0x47, 13), | 476 | TWL4030_ADJUSTABLE_LDO(VINTDIG, 0x47, 13), |
| 410 | TWL_SMPS(VIO, 0x4b, 14), | 477 | TWL4030_SMPS(VIO, 0x4b, 14), |
| 411 | TWL_SMPS(VDD1, 0x55, 15), | 478 | TWL4030_SMPS(VDD1, 0x55, 15), |
| 412 | TWL_SMPS(VDD2, 0x63, 16), | 479 | TWL4030_SMPS(VDD2, 0x63, 16), |
| 413 | */ | 480 | */ |
| 414 | TWL_FIXED_LDO(VUSB1V5, 0x71, 1500, 17), | 481 | TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17), |
| 415 | TWL_FIXED_LDO(VUSB1V8, 0x74, 1800, 18), | 482 | TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18), |
| 416 | TWL_FIXED_LDO(VUSB3V1, 0x77, 3100, 19), | 483 | TWL4030_FIXED_LDO(VUSB3V1, 0x77, 3100, 19), |
| 417 | /* VUSBCP is managed *only* by the USB subchip */ | 484 | /* VUSBCP is managed *only* by the USB subchip */ |
| 485 | |||
| 486 | /* 6030 REG with base as PMC Slave Misc : 0x0030 */ | ||
| 487 | TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1), | ||
| 488 | TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 2), | ||
| 489 | TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 3), | ||
| 490 | TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 4), | ||
| 491 | TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 5), | ||
| 492 | TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 7), | ||
| 493 | TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15), | ||
| 494 | TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16), | ||
| 495 | TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17), | ||
| 496 | TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18) | ||
| 418 | }; | 497 | }; |
| 419 | 498 | ||
| 420 | static int twl4030reg_probe(struct platform_device *pdev) | 499 | static int twlreg_probe(struct platform_device *pdev) |
| 421 | { | 500 | { |
| 422 | int i; | 501 | int i; |
| 423 | struct twlreg_info *info; | 502 | struct twlreg_info *info; |
| @@ -425,10 +504,10 @@ static int twl4030reg_probe(struct platform_device *pdev) | |||
| 425 | struct regulation_constraints *c; | 504 | struct regulation_constraints *c; |
| 426 | struct regulator_dev *rdev; | 505 | struct regulator_dev *rdev; |
| 427 | 506 | ||
| 428 | for (i = 0, info = NULL; i < ARRAY_SIZE(twl4030_regs); i++) { | 507 | for (i = 0, info = NULL; i < ARRAY_SIZE(twl_regs); i++) { |
| 429 | if (twl4030_regs[i].desc.id != pdev->id) | 508 | if (twl_regs[i].desc.id != pdev->id) |
| 430 | continue; | 509 | continue; |
| 431 | info = twl4030_regs + i; | 510 | info = twl_regs + i; |
| 432 | break; | 511 | break; |
| 433 | } | 512 | } |
| 434 | if (!info) | 513 | if (!info) |
| @@ -466,35 +545,35 @@ static int twl4030reg_probe(struct platform_device *pdev) | |||
| 466 | return 0; | 545 | return 0; |
| 467 | } | 546 | } |
| 468 | 547 | ||
| 469 | static int __devexit twl4030reg_remove(struct platform_device *pdev) | 548 | static int __devexit twlreg_remove(struct platform_device *pdev) |
| 470 | { | 549 | { |
| 471 | regulator_unregister(platform_get_drvdata(pdev)); | 550 | regulator_unregister(platform_get_drvdata(pdev)); |
| 472 | return 0; | 551 | return 0; |
| 473 | } | 552 | } |
| 474 | 553 | ||
| 475 | MODULE_ALIAS("platform:twl4030_reg"); | 554 | MODULE_ALIAS("platform:twl_reg"); |
| 476 | 555 | ||
| 477 | static struct platform_driver twl4030reg_driver = { | 556 | static struct platform_driver twlreg_driver = { |
| 478 | .probe = twl4030reg_probe, | 557 | .probe = twlreg_probe, |
| 479 | .remove = __devexit_p(twl4030reg_remove), | 558 | .remove = __devexit_p(twlreg_remove), |
| 480 | /* NOTE: short name, to work around driver model truncation of | 559 | /* NOTE: short name, to work around driver model truncation of |
| 481 | * "twl4030_regulator.12" (and friends) to "twl4030_regulator.1". | 560 | * "twl_regulator.12" (and friends) to "twl_regulator.1". |
| 482 | */ | 561 | */ |
| 483 | .driver.name = "twl4030_reg", | 562 | .driver.name = "twl_reg", |
| 484 | .driver.owner = THIS_MODULE, | 563 | .driver.owner = THIS_MODULE, |
| 485 | }; | 564 | }; |
| 486 | 565 | ||
| 487 | static int __init twl4030reg_init(void) | 566 | static int __init twlreg_init(void) |
| 488 | { | 567 | { |
| 489 | return platform_driver_register(&twl4030reg_driver); | 568 | return platform_driver_register(&twlreg_driver); |
| 490 | } | 569 | } |
| 491 | subsys_initcall(twl4030reg_init); | 570 | subsys_initcall(twlreg_init); |
| 492 | 571 | ||
| 493 | static void __exit twl4030reg_exit(void) | 572 | static void __exit twlreg_exit(void) |
| 494 | { | 573 | { |
| 495 | platform_driver_unregister(&twl4030reg_driver); | 574 | platform_driver_unregister(&twlreg_driver); |
| 496 | } | 575 | } |
| 497 | module_exit(twl4030reg_exit) | 576 | module_exit(twlreg_exit) |
| 498 | 577 | ||
| 499 | MODULE_DESCRIPTION("TWL4030 regulator driver"); | 578 | MODULE_DESCRIPTION("TWL regulator driver"); |
| 500 | MODULE_LICENSE("GPL"); | 579 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 768bd0e5b48b..1bbff099a546 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c | |||
| @@ -1330,9 +1330,10 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { | |||
| 1330 | }, | 1330 | }, |
| 1331 | }; | 1331 | }; |
| 1332 | 1332 | ||
| 1333 | static void pmic_uv_handler(struct wm8350 *wm8350, int irq, void *data) | 1333 | static irqreturn_t pmic_uv_handler(int irq, void *data) |
| 1334 | { | 1334 | { |
| 1335 | struct regulator_dev *rdev = (struct regulator_dev *)data; | 1335 | struct regulator_dev *rdev = (struct regulator_dev *)data; |
| 1336 | struct wm8350 *wm8350 = rdev_get_drvdata(rdev); | ||
| 1336 | 1337 | ||
| 1337 | mutex_lock(&rdev->mutex); | 1338 | mutex_lock(&rdev->mutex); |
| 1338 | if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2) | 1339 | if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2) |
| @@ -1344,6 +1345,8 @@ static void pmic_uv_handler(struct wm8350 *wm8350, int irq, void *data) | |||
| 1344 | REGULATOR_EVENT_UNDER_VOLTAGE, | 1345 | REGULATOR_EVENT_UNDER_VOLTAGE, |
| 1345 | wm8350); | 1346 | wm8350); |
| 1346 | mutex_unlock(&rdev->mutex); | 1347 | mutex_unlock(&rdev->mutex); |
| 1348 | |||
| 1349 | return IRQ_HANDLED; | ||
| 1347 | } | 1350 | } |
| 1348 | 1351 | ||
| 1349 | static int wm8350_regulator_probe(struct platform_device *pdev) | 1352 | static int wm8350_regulator_probe(struct platform_device *pdev) |
| @@ -1388,7 +1391,7 @@ static int wm8350_regulator_probe(struct platform_device *pdev) | |||
| 1388 | 1391 | ||
| 1389 | /* register regulator IRQ */ | 1392 | /* register regulator IRQ */ |
| 1390 | ret = wm8350_register_irq(wm8350, wm8350_reg[pdev->id].irq, | 1393 | ret = wm8350_register_irq(wm8350, wm8350_reg[pdev->id].irq, |
| 1391 | pmic_uv_handler, rdev); | 1394 | pmic_uv_handler, 0, "UV", rdev); |
| 1392 | if (ret < 0) { | 1395 | if (ret < 0) { |
| 1393 | regulator_unregister(rdev); | 1396 | regulator_unregister(rdev); |
| 1394 | dev_err(&pdev->dev, "failed to register regulator %s IRQ\n", | 1397 | dev_err(&pdev->dev, "failed to register regulator %s IRQ\n", |
| @@ -1396,8 +1399,6 @@ static int wm8350_regulator_probe(struct platform_device *pdev) | |||
| 1396 | return ret; | 1399 | return ret; |
| 1397 | } | 1400 | } |
| 1398 | 1401 | ||
| 1399 | wm8350_unmask_irq(wm8350, wm8350_reg[pdev->id].irq); | ||
| 1400 | |||
| 1401 | return 0; | 1402 | return 0; |
| 1402 | } | 1403 | } |
| 1403 | 1404 | ||
| @@ -1406,7 +1407,6 @@ static int wm8350_regulator_remove(struct platform_device *pdev) | |||
| 1406 | struct regulator_dev *rdev = platform_get_drvdata(pdev); | 1407 | struct regulator_dev *rdev = platform_get_drvdata(pdev); |
| 1407 | struct wm8350 *wm8350 = rdev_get_drvdata(rdev); | 1408 | struct wm8350 *wm8350 = rdev_get_drvdata(rdev); |
| 1408 | 1409 | ||
| 1409 | wm8350_mask_irq(wm8350, wm8350_reg[pdev->id].irq); | ||
| 1410 | wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq); | 1410 | wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq); |
| 1411 | 1411 | ||
| 1412 | regulator_unregister(rdev); | 1412 | regulator_unregister(rdev); |
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index f2e1004d12c7..71fbd6e8edf7 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
| @@ -258,14 +258,14 @@ config RTC_DRV_TWL92330 | |||
| 258 | the Menelaus driver; it's not separate module. | 258 | the Menelaus driver; it's not separate module. |
| 259 | 259 | ||
| 260 | config RTC_DRV_TWL4030 | 260 | config RTC_DRV_TWL4030 |
| 261 | tristate "TI TWL4030/TWL5030/TPS659x0" | 261 | tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0" |
| 262 | depends on RTC_CLASS && TWL4030_CORE | 262 | depends on RTC_CLASS && TWL4030_CORE |
| 263 | help | 263 | help |
| 264 | If you say yes here you get support for the RTC on the | 264 | If you say yes here you get support for the RTC on the |
| 265 | TWL4030 family chips, used mostly with OMAP3 platforms. | 265 | TWL4030/TWL5030/TWL6030 family chips, used mostly with OMAP3 platforms. |
| 266 | 266 | ||
| 267 | This driver can also be built as a module. If so, the module | 267 | This driver can also be built as a module. If so, the module |
| 268 | will be called rtc-twl4030. | 268 | will be called rtc-twl. |
| 269 | 269 | ||
| 270 | config RTC_DRV_S35390A | 270 | config RTC_DRV_S35390A |
| 271 | tristate "Seiko Instruments S-35390A" | 271 | tristate "Seiko Instruments S-35390A" |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index af1ba7ae2857..7da6efb3e953 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
| @@ -80,7 +80,7 @@ obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o | |||
| 80 | obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o | 80 | obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o |
| 81 | obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o | 81 | obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o |
| 82 | obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o | 82 | obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o |
| 83 | obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl4030.o | 83 | obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o |
| 84 | obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o | 84 | obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o |
| 85 | obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o | 85 | obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o |
| 86 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o | 86 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o |
diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c index 4c5d5d0c4cfc..9b74e9c9151c 100644 --- a/drivers/rtc/rtc-pcf50633.c +++ b/drivers/rtc/rtc-pcf50633.c | |||
| @@ -277,16 +277,13 @@ static void pcf50633_rtc_irq(int irq, void *data) | |||
| 277 | 277 | ||
| 278 | static int __devinit pcf50633_rtc_probe(struct platform_device *pdev) | 278 | static int __devinit pcf50633_rtc_probe(struct platform_device *pdev) |
| 279 | { | 279 | { |
| 280 | struct pcf50633_subdev_pdata *pdata; | ||
| 281 | struct pcf50633_rtc *rtc; | 280 | struct pcf50633_rtc *rtc; |
| 282 | 281 | ||
| 283 | |||
| 284 | rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); | 282 | rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); |
| 285 | if (!rtc) | 283 | if (!rtc) |
| 286 | return -ENOMEM; | 284 | return -ENOMEM; |
| 287 | 285 | ||
| 288 | pdata = pdev->dev.platform_data; | 286 | rtc->pcf = dev_to_pcf50633(pdev->dev.parent); |
| 289 | rtc->pcf = pdata->pcf; | ||
| 290 | platform_set_drvdata(pdev, rtc); | 287 | platform_set_drvdata(pdev, rtc); |
| 291 | rtc->rtc_dev = rtc_device_register("pcf50633-rtc", &pdev->dev, | 288 | rtc->rtc_dev = rtc_device_register("pcf50633-rtc", &pdev->dev, |
| 292 | &pcf50633_rtc_ops, THIS_MODULE); | 289 | &pcf50633_rtc_ops, THIS_MODULE); |
diff --git a/drivers/rtc/rtc-twl4030.c b/drivers/rtc/rtc-twl.c index 9c8c70c497dc..c6a83a2a722c 100644 --- a/drivers/rtc/rtc-twl4030.c +++ b/drivers/rtc/rtc-twl.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * rtc-twl4030.c -- TWL4030 Real Time Clock interface | 2 | * rtc-twl.c -- TWL Real Time Clock interface |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2007 MontaVista Software, Inc | 4 | * Copyright (C) 2007 MontaVista Software, Inc |
| 5 | * Author: Alexandre Rusev <source@mvista.com> | 5 | * Author: Alexandre Rusev <source@mvista.com> |
| @@ -28,33 +28,81 @@ | |||
| 28 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
| 29 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
| 30 | 30 | ||
| 31 | #include <linux/i2c/twl4030.h> | 31 | #include <linux/i2c/twl.h> |
| 32 | 32 | ||
| 33 | 33 | ||
| 34 | /* | 34 | /* |
| 35 | * RTC block register offsets (use TWL_MODULE_RTC) | 35 | * RTC block register offsets (use TWL_MODULE_RTC) |
| 36 | */ | 36 | */ |
| 37 | #define REG_SECONDS_REG 0x00 | 37 | enum { |
| 38 | #define REG_MINUTES_REG 0x01 | 38 | REG_SECONDS_REG = 0, |
| 39 | #define REG_HOURS_REG 0x02 | 39 | REG_MINUTES_REG, |
| 40 | #define REG_DAYS_REG 0x03 | 40 | REG_HOURS_REG, |
| 41 | #define REG_MONTHS_REG 0x04 | 41 | REG_DAYS_REG, |
| 42 | #define REG_YEARS_REG 0x05 | 42 | REG_MONTHS_REG, |
| 43 | #define REG_WEEKS_REG 0x06 | 43 | REG_YEARS_REG, |
| 44 | 44 | REG_WEEKS_REG, | |
| 45 | #define REG_ALARM_SECONDS_REG 0x07 | 45 | |
| 46 | #define REG_ALARM_MINUTES_REG 0x08 | 46 | REG_ALARM_SECONDS_REG, |
| 47 | #define REG_ALARM_HOURS_REG 0x09 | 47 | REG_ALARM_MINUTES_REG, |
| 48 | #define REG_ALARM_DAYS_REG 0x0A | 48 | REG_ALARM_HOURS_REG, |
| 49 | #define REG_ALARM_MONTHS_REG 0x0B | 49 | REG_ALARM_DAYS_REG, |
| 50 | #define REG_ALARM_YEARS_REG 0x0C | 50 | REG_ALARM_MONTHS_REG, |
| 51 | 51 | REG_ALARM_YEARS_REG, | |
| 52 | #define REG_RTC_CTRL_REG 0x0D | 52 | |
| 53 | #define REG_RTC_STATUS_REG 0x0E | 53 | REG_RTC_CTRL_REG, |
| 54 | #define REG_RTC_INTERRUPTS_REG 0x0F | 54 | REG_RTC_STATUS_REG, |
| 55 | 55 | REG_RTC_INTERRUPTS_REG, | |
| 56 | #define REG_RTC_COMP_LSB_REG 0x10 | 56 | |
| 57 | #define REG_RTC_COMP_MSB_REG 0x11 | 57 | REG_RTC_COMP_LSB_REG, |
| 58 | REG_RTC_COMP_MSB_REG, | ||
| 59 | }; | ||
| 60 | const static u8 twl4030_rtc_reg_map[] = { | ||
| 61 | [REG_SECONDS_REG] = 0x00, | ||
| 62 | [REG_MINUTES_REG] = 0x01, | ||
| 63 | [REG_HOURS_REG] = 0x02, | ||
| 64 | [REG_DAYS_REG] = 0x03, | ||
| 65 | [REG_MONTHS_REG] = 0x04, | ||
| 66 | [REG_YEARS_REG] = 0x05, | ||
| 67 | [REG_WEEKS_REG] = 0x06, | ||
| 68 | |||
| 69 | [REG_ALARM_SECONDS_REG] = 0x07, | ||
| 70 | [REG_ALARM_MINUTES_REG] = 0x08, | ||
| 71 | [REG_ALARM_HOURS_REG] = 0x09, | ||
| 72 | [REG_ALARM_DAYS_REG] = 0x0A, | ||
| 73 | [REG_ALARM_MONTHS_REG] = 0x0B, | ||
| 74 | [REG_ALARM_YEARS_REG] = 0x0C, | ||
| 75 | |||
| 76 | [REG_RTC_CTRL_REG] = 0x0D, | ||
| 77 | [REG_RTC_STATUS_REG] = 0x0E, | ||
| 78 | [REG_RTC_INTERRUPTS_REG] = 0x0F, | ||
| 79 | |||
| 80 | [REG_RTC_COMP_LSB_REG] = 0x10, | ||
| 81 | [REG_RTC_COMP_MSB_REG] = 0x11, | ||
| 82 | }; | ||
| 83 | const static u8 twl6030_rtc_reg_map[] = { | ||
| 84 | [REG_SECONDS_REG] = 0x00, | ||
| 85 | [REG_MINUTES_REG] = 0x01, | ||
| 86 | [REG_HOURS_REG] = 0x02, | ||
| 87 | [REG_DAYS_REG] = 0x03, | ||
| 88 | [REG_MONTHS_REG] = 0x04, | ||
| 89 | [REG_YEARS_REG] = 0x05, | ||
| 90 | [REG_WEEKS_REG] = 0x06, | ||
| 91 | |||
| 92 | [REG_ALARM_SECONDS_REG] = 0x08, | ||
| 93 | [REG_ALARM_MINUTES_REG] = 0x09, | ||
| 94 | [REG_ALARM_HOURS_REG] = 0x0A, | ||
| 95 | [REG_ALARM_DAYS_REG] = 0x0B, | ||
| 96 | [REG_ALARM_MONTHS_REG] = 0x0C, | ||
| 97 | [REG_ALARM_YEARS_REG] = 0x0D, | ||
| 98 | |||
| 99 | [REG_RTC_CTRL_REG] = 0x10, | ||
| 100 | [REG_RTC_STATUS_REG] = 0x11, | ||
| 101 | [REG_RTC_INTERRUPTS_REG] = 0x12, | ||
| 102 | |||
| 103 | [REG_RTC_COMP_LSB_REG] = 0x13, | ||
| 104 | [REG_RTC_COMP_MSB_REG] = 0x14, | ||
| 105 | }; | ||
| 58 | 106 | ||
| 59 | /* RTC_CTRL_REG bitfields */ | 107 | /* RTC_CTRL_REG bitfields */ |
| 60 | #define BIT_RTC_CTRL_REG_STOP_RTC_M 0x01 | 108 | #define BIT_RTC_CTRL_REG_STOP_RTC_M 0x01 |
| @@ -84,31 +132,32 @@ | |||
| 84 | #define ALL_TIME_REGS 6 | 132 | #define ALL_TIME_REGS 6 |
| 85 | 133 | ||
| 86 | /*----------------------------------------------------------------------*/ | 134 | /*----------------------------------------------------------------------*/ |
| 135 | static u8 *rtc_reg_map; | ||
| 87 | 136 | ||
| 88 | /* | 137 | /* |
| 89 | * Supports 1 byte read from TWL4030 RTC register. | 138 | * Supports 1 byte read from TWL RTC register. |
| 90 | */ | 139 | */ |
| 91 | static int twl4030_rtc_read_u8(u8 *data, u8 reg) | 140 | static int twl_rtc_read_u8(u8 *data, u8 reg) |
| 92 | { | 141 | { |
| 93 | int ret; | 142 | int ret; |
| 94 | 143 | ||
| 95 | ret = twl4030_i2c_read_u8(TWL4030_MODULE_RTC, data, reg); | 144 | ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg])); |
| 96 | if (ret < 0) | 145 | if (ret < 0) |
| 97 | pr_err("twl4030_rtc: Could not read TWL4030" | 146 | pr_err("twl_rtc: Could not read TWL" |
| 98 | "register %X - error %d\n", reg, ret); | 147 | "register %X - error %d\n", reg, ret); |
| 99 | return ret; | 148 | return ret; |
| 100 | } | 149 | } |
| 101 | 150 | ||
| 102 | /* | 151 | /* |
| 103 | * Supports 1 byte write to TWL4030 RTC registers. | 152 | * Supports 1 byte write to TWL RTC registers. |
| 104 | */ | 153 | */ |
| 105 | static int twl4030_rtc_write_u8(u8 data, u8 reg) | 154 | static int twl_rtc_write_u8(u8 data, u8 reg) |
| 106 | { | 155 | { |
| 107 | int ret; | 156 | int ret; |
| 108 | 157 | ||
| 109 | ret = twl4030_i2c_write_u8(TWL4030_MODULE_RTC, data, reg); | 158 | ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg])); |
| 110 | if (ret < 0) | 159 | if (ret < 0) |
| 111 | pr_err("twl4030_rtc: Could not write TWL4030" | 160 | pr_err("twl_rtc: Could not write TWL" |
| 112 | "register %X - error %d\n", reg, ret); | 161 | "register %X - error %d\n", reg, ret); |
| 113 | return ret; | 162 | return ret; |
| 114 | } | 163 | } |
| @@ -129,7 +178,7 @@ static int set_rtc_irq_bit(unsigned char bit) | |||
| 129 | 178 | ||
| 130 | val = rtc_irq_bits | bit; | 179 | val = rtc_irq_bits | bit; |
| 131 | val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M; | 180 | val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M; |
| 132 | ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); | 181 | ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); |
| 133 | if (ret == 0) | 182 | if (ret == 0) |
| 134 | rtc_irq_bits = val; | 183 | rtc_irq_bits = val; |
| 135 | 184 | ||
| @@ -145,14 +194,14 @@ static int mask_rtc_irq_bit(unsigned char bit) | |||
| 145 | int ret; | 194 | int ret; |
| 146 | 195 | ||
| 147 | val = rtc_irq_bits & ~bit; | 196 | val = rtc_irq_bits & ~bit; |
| 148 | ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); | 197 | ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); |
| 149 | if (ret == 0) | 198 | if (ret == 0) |
| 150 | rtc_irq_bits = val; | 199 | rtc_irq_bits = val; |
| 151 | 200 | ||
| 152 | return ret; | 201 | return ret; |
| 153 | } | 202 | } |
| 154 | 203 | ||
| 155 | static int twl4030_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) | 204 | static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) |
| 156 | { | 205 | { |
| 157 | int ret; | 206 | int ret; |
| 158 | 207 | ||
| @@ -164,7 +213,7 @@ static int twl4030_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) | |||
| 164 | return ret; | 213 | return ret; |
| 165 | } | 214 | } |
| 166 | 215 | ||
| 167 | static int twl4030_rtc_update_irq_enable(struct device *dev, unsigned enabled) | 216 | static int twl_rtc_update_irq_enable(struct device *dev, unsigned enabled) |
| 168 | { | 217 | { |
| 169 | int ret; | 218 | int ret; |
| 170 | 219 | ||
| @@ -177,7 +226,7 @@ static int twl4030_rtc_update_irq_enable(struct device *dev, unsigned enabled) | |||
| 177 | } | 226 | } |
| 178 | 227 | ||
| 179 | /* | 228 | /* |
| 180 | * Gets current TWL4030 RTC time and date parameters. | 229 | * Gets current TWL RTC time and date parameters. |
| 181 | * | 230 | * |
| 182 | * The RTC's time/alarm representation is not what gmtime(3) requires | 231 | * The RTC's time/alarm representation is not what gmtime(3) requires |
| 183 | * Linux to use: | 232 | * Linux to use: |
| @@ -185,24 +234,24 @@ static int twl4030_rtc_update_irq_enable(struct device *dev, unsigned enabled) | |||
| 185 | * - Months are 1..12 vs Linux 0-11 | 234 | * - Months are 1..12 vs Linux 0-11 |
| 186 | * - Years are 0..99 vs Linux 1900..N (we assume 21st century) | 235 | * - Years are 0..99 vs Linux 1900..N (we assume 21st century) |
| 187 | */ | 236 | */ |
| 188 | static int twl4030_rtc_read_time(struct device *dev, struct rtc_time *tm) | 237 | static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) |
| 189 | { | 238 | { |
| 190 | unsigned char rtc_data[ALL_TIME_REGS + 1]; | 239 | unsigned char rtc_data[ALL_TIME_REGS + 1]; |
| 191 | int ret; | 240 | int ret; |
| 192 | u8 save_control; | 241 | u8 save_control; |
| 193 | 242 | ||
| 194 | ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); | 243 | ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); |
| 195 | if (ret < 0) | 244 | if (ret < 0) |
| 196 | return ret; | 245 | return ret; |
| 197 | 246 | ||
| 198 | save_control |= BIT_RTC_CTRL_REG_GET_TIME_M; | 247 | save_control |= BIT_RTC_CTRL_REG_GET_TIME_M; |
| 199 | 248 | ||
| 200 | ret = twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG); | 249 | ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); |
| 201 | if (ret < 0) | 250 | if (ret < 0) |
| 202 | return ret; | 251 | return ret; |
| 203 | 252 | ||
| 204 | ret = twl4030_i2c_read(TWL4030_MODULE_RTC, rtc_data, | 253 | ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, |
| 205 | REG_SECONDS_REG, ALL_TIME_REGS); | 254 | (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS); |
| 206 | 255 | ||
| 207 | if (ret < 0) { | 256 | if (ret < 0) { |
| 208 | dev_err(dev, "rtc_read_time error %d\n", ret); | 257 | dev_err(dev, "rtc_read_time error %d\n", ret); |
| @@ -219,7 +268,7 @@ static int twl4030_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
| 219 | return ret; | 268 | return ret; |
| 220 | } | 269 | } |
| 221 | 270 | ||
| 222 | static int twl4030_rtc_set_time(struct device *dev, struct rtc_time *tm) | 271 | static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm) |
| 223 | { | 272 | { |
| 224 | unsigned char save_control; | 273 | unsigned char save_control; |
| 225 | unsigned char rtc_data[ALL_TIME_REGS + 1]; | 274 | unsigned char rtc_data[ALL_TIME_REGS + 1]; |
| @@ -233,18 +282,18 @@ static int twl4030_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
| 233 | rtc_data[6] = bin2bcd(tm->tm_year - 100); | 282 | rtc_data[6] = bin2bcd(tm->tm_year - 100); |
| 234 | 283 | ||
| 235 | /* Stop RTC while updating the TC registers */ | 284 | /* Stop RTC while updating the TC registers */ |
| 236 | ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); | 285 | ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); |
| 237 | if (ret < 0) | 286 | if (ret < 0) |
| 238 | goto out; | 287 | goto out; |
| 239 | 288 | ||
| 240 | save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M; | 289 | save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M; |
| 241 | twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG); | 290 | twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); |
| 242 | if (ret < 0) | 291 | if (ret < 0) |
| 243 | goto out; | 292 | goto out; |
| 244 | 293 | ||
| 245 | /* update all the time registers in one shot */ | 294 | /* update all the time registers in one shot */ |
| 246 | ret = twl4030_i2c_write(TWL4030_MODULE_RTC, rtc_data, | 295 | ret = twl_i2c_write(TWL_MODULE_RTC, rtc_data, |
| 247 | REG_SECONDS_REG, ALL_TIME_REGS); | 296 | (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS); |
| 248 | if (ret < 0) { | 297 | if (ret < 0) { |
| 249 | dev_err(dev, "rtc_set_time error %d\n", ret); | 298 | dev_err(dev, "rtc_set_time error %d\n", ret); |
| 250 | goto out; | 299 | goto out; |
| @@ -252,22 +301,22 @@ static int twl4030_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
| 252 | 301 | ||
| 253 | /* Start back RTC */ | 302 | /* Start back RTC */ |
| 254 | save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M; | 303 | save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M; |
| 255 | ret = twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG); | 304 | ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); |
| 256 | 305 | ||
| 257 | out: | 306 | out: |
| 258 | return ret; | 307 | return ret; |
| 259 | } | 308 | } |
| 260 | 309 | ||
| 261 | /* | 310 | /* |
| 262 | * Gets current TWL4030 RTC alarm time. | 311 | * Gets current TWL RTC alarm time. |
| 263 | */ | 312 | */ |
| 264 | static int twl4030_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) | 313 | static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) |
| 265 | { | 314 | { |
| 266 | unsigned char rtc_data[ALL_TIME_REGS + 1]; | 315 | unsigned char rtc_data[ALL_TIME_REGS + 1]; |
| 267 | int ret; | 316 | int ret; |
| 268 | 317 | ||
| 269 | ret = twl4030_i2c_read(TWL4030_MODULE_RTC, rtc_data, | 318 | ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, |
| 270 | REG_ALARM_SECONDS_REG, ALL_TIME_REGS); | 319 | (rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS); |
| 271 | if (ret < 0) { | 320 | if (ret < 0) { |
| 272 | dev_err(dev, "rtc_read_alarm error %d\n", ret); | 321 | dev_err(dev, "rtc_read_alarm error %d\n", ret); |
| 273 | return ret; | 322 | return ret; |
| @@ -288,12 +337,12 @@ static int twl4030_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) | |||
| 288 | return ret; | 337 | return ret; |
| 289 | } | 338 | } |
| 290 | 339 | ||
| 291 | static int twl4030_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) | 340 | static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) |
| 292 | { | 341 | { |
| 293 | unsigned char alarm_data[ALL_TIME_REGS + 1]; | 342 | unsigned char alarm_data[ALL_TIME_REGS + 1]; |
| 294 | int ret; | 343 | int ret; |
| 295 | 344 | ||
| 296 | ret = twl4030_rtc_alarm_irq_enable(dev, 0); | 345 | ret = twl_rtc_alarm_irq_enable(dev, 0); |
| 297 | if (ret) | 346 | if (ret) |
| 298 | goto out; | 347 | goto out; |
| 299 | 348 | ||
| @@ -305,20 +354,20 @@ static int twl4030_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) | |||
| 305 | alarm_data[6] = bin2bcd(alm->time.tm_year - 100); | 354 | alarm_data[6] = bin2bcd(alm->time.tm_year - 100); |
| 306 | 355 | ||
| 307 | /* update all the alarm registers in one shot */ | 356 | /* update all the alarm registers in one shot */ |
| 308 | ret = twl4030_i2c_write(TWL4030_MODULE_RTC, alarm_data, | 357 | ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data, |
| 309 | REG_ALARM_SECONDS_REG, ALL_TIME_REGS); | 358 | (rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS); |
| 310 | if (ret) { | 359 | if (ret) { |
| 311 | dev_err(dev, "rtc_set_alarm error %d\n", ret); | 360 | dev_err(dev, "rtc_set_alarm error %d\n", ret); |
| 312 | goto out; | 361 | goto out; |
| 313 | } | 362 | } |
| 314 | 363 | ||
| 315 | if (alm->enabled) | 364 | if (alm->enabled) |
| 316 | ret = twl4030_rtc_alarm_irq_enable(dev, 1); | 365 | ret = twl_rtc_alarm_irq_enable(dev, 1); |
| 317 | out: | 366 | out: |
| 318 | return ret; | 367 | return ret; |
| 319 | } | 368 | } |
| 320 | 369 | ||
| 321 | static irqreturn_t twl4030_rtc_interrupt(int irq, void *rtc) | 370 | static irqreturn_t twl_rtc_interrupt(int irq, void *rtc) |
| 322 | { | 371 | { |
| 323 | unsigned long events = 0; | 372 | unsigned long events = 0; |
| 324 | int ret = IRQ_NONE; | 373 | int ret = IRQ_NONE; |
| @@ -333,7 +382,7 @@ static irqreturn_t twl4030_rtc_interrupt(int irq, void *rtc) | |||
| 333 | local_irq_enable(); | 382 | local_irq_enable(); |
| 334 | #endif | 383 | #endif |
| 335 | 384 | ||
| 336 | res = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); | 385 | res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); |
| 337 | if (res) | 386 | if (res) |
| 338 | goto out; | 387 | goto out; |
| 339 | /* | 388 | /* |
| @@ -347,26 +396,28 @@ static irqreturn_t twl4030_rtc_interrupt(int irq, void *rtc) | |||
| 347 | else | 396 | else |
| 348 | events |= RTC_IRQF | RTC_UF; | 397 | events |= RTC_IRQF | RTC_UF; |
| 349 | 398 | ||
| 350 | res = twl4030_rtc_write_u8(rd_reg | BIT_RTC_STATUS_REG_ALARM_M, | 399 | res = twl_rtc_write_u8(rd_reg | BIT_RTC_STATUS_REG_ALARM_M, |
| 351 | REG_RTC_STATUS_REG); | 400 | REG_RTC_STATUS_REG); |
| 352 | if (res) | 401 | if (res) |
| 353 | goto out; | 402 | goto out; |
| 354 | 403 | ||
| 355 | /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1 | 404 | if (twl_class_is_4030()) { |
| 356 | * needs 2 reads to clear the interrupt. One read is done in | 405 | /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1 |
| 357 | * do_twl4030_pwrirq(). Doing the second read, to clear | 406 | * needs 2 reads to clear the interrupt. One read is done in |
| 358 | * the bit. | 407 | * do_twl_pwrirq(). Doing the second read, to clear |
| 359 | * | 408 | * the bit. |
| 360 | * FIXME the reason PWR_ISR1 needs an extra read is that | 409 | * |
| 361 | * RTC_IF retriggered until we cleared REG_ALARM_M above. | 410 | * FIXME the reason PWR_ISR1 needs an extra read is that |
| 362 | * But re-reading like this is a bad hack; by doing so we | 411 | * RTC_IF retriggered until we cleared REG_ALARM_M above. |
| 363 | * risk wrongly clearing status for some other IRQ (losing | 412 | * But re-reading like this is a bad hack; by doing so we |
| 364 | * the interrupt). Be smarter about handling RTC_UF ... | 413 | * risk wrongly clearing status for some other IRQ (losing |
| 365 | */ | 414 | * the interrupt). Be smarter about handling RTC_UF ... |
| 366 | res = twl4030_i2c_read_u8(TWL4030_MODULE_INT, | 415 | */ |
| 416 | res = twl_i2c_read_u8(TWL4030_MODULE_INT, | ||
| 367 | &rd_reg, TWL4030_INT_PWR_ISR1); | 417 | &rd_reg, TWL4030_INT_PWR_ISR1); |
| 368 | if (res) | 418 | if (res) |
| 369 | goto out; | 419 | goto out; |
| 420 | } | ||
| 370 | 421 | ||
| 371 | /* Notify RTC core on event */ | 422 | /* Notify RTC core on event */ |
| 372 | rtc_update_irq(rtc, 1, events); | 423 | rtc_update_irq(rtc, 1, events); |
| @@ -376,18 +427,18 @@ out: | |||
| 376 | return ret; | 427 | return ret; |
| 377 | } | 428 | } |
| 378 | 429 | ||
| 379 | static struct rtc_class_ops twl4030_rtc_ops = { | 430 | static struct rtc_class_ops twl_rtc_ops = { |
| 380 | .read_time = twl4030_rtc_read_time, | 431 | .read_time = twl_rtc_read_time, |
| 381 | .set_time = twl4030_rtc_set_time, | 432 | .set_time = twl_rtc_set_time, |
| 382 | .read_alarm = twl4030_rtc_read_alarm, | 433 | .read_alarm = twl_rtc_read_alarm, |
| 383 | .set_alarm = twl4030_rtc_set_alarm, | 434 | .set_alarm = twl_rtc_set_alarm, |
| 384 | .alarm_irq_enable = twl4030_rtc_alarm_irq_enable, | 435 | .alarm_irq_enable = twl_rtc_alarm_irq_enable, |
| 385 | .update_irq_enable = twl4030_rtc_update_irq_enable, | 436 | .update_irq_enable = twl_rtc_update_irq_enable, |
| 386 | }; | 437 | }; |
| 387 | 438 | ||
| 388 | /*----------------------------------------------------------------------*/ | 439 | /*----------------------------------------------------------------------*/ |
| 389 | 440 | ||
| 390 | static int __devinit twl4030_rtc_probe(struct platform_device *pdev) | 441 | static int __devinit twl_rtc_probe(struct platform_device *pdev) |
| 391 | { | 442 | { |
| 392 | struct rtc_device *rtc; | 443 | struct rtc_device *rtc; |
| 393 | int ret = 0; | 444 | int ret = 0; |
| @@ -398,7 +449,7 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev) | |||
| 398 | return -EINVAL; | 449 | return -EINVAL; |
| 399 | 450 | ||
| 400 | rtc = rtc_device_register(pdev->name, | 451 | rtc = rtc_device_register(pdev->name, |
| 401 | &pdev->dev, &twl4030_rtc_ops, THIS_MODULE); | 452 | &pdev->dev, &twl_rtc_ops, THIS_MODULE); |
| 402 | if (IS_ERR(rtc)) { | 453 | if (IS_ERR(rtc)) { |
| 403 | ret = PTR_ERR(rtc); | 454 | ret = PTR_ERR(rtc); |
| 404 | dev_err(&pdev->dev, "can't register RTC device, err %ld\n", | 455 | dev_err(&pdev->dev, "can't register RTC device, err %ld\n", |
| @@ -409,7 +460,7 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev) | |||
| 409 | 460 | ||
| 410 | platform_set_drvdata(pdev, rtc); | 461 | platform_set_drvdata(pdev, rtc); |
| 411 | 462 | ||
| 412 | ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); | 463 | ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); |
| 413 | if (ret < 0) | 464 | if (ret < 0) |
| 414 | goto out1; | 465 | goto out1; |
| 415 | 466 | ||
| @@ -420,11 +471,11 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev) | |||
| 420 | dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n"); | 471 | dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n"); |
| 421 | 472 | ||
| 422 | /* Clear RTC Power up reset and pending alarm interrupts */ | 473 | /* Clear RTC Power up reset and pending alarm interrupts */ |
| 423 | ret = twl4030_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG); | 474 | ret = twl_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG); |
| 424 | if (ret < 0) | 475 | if (ret < 0) |
| 425 | goto out1; | 476 | goto out1; |
| 426 | 477 | ||
| 427 | ret = request_irq(irq, twl4030_rtc_interrupt, | 478 | ret = request_irq(irq, twl_rtc_interrupt, |
| 428 | IRQF_TRIGGER_RISING, | 479 | IRQF_TRIGGER_RISING, |
| 429 | dev_name(&rtc->dev), rtc); | 480 | dev_name(&rtc->dev), rtc); |
| 430 | if (ret < 0) { | 481 | if (ret < 0) { |
| @@ -432,21 +483,28 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev) | |||
| 432 | goto out1; | 483 | goto out1; |
| 433 | } | 484 | } |
| 434 | 485 | ||
| 486 | if (twl_class_is_6030()) { | ||
| 487 | twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, | ||
| 488 | REG_INT_MSK_LINE_A); | ||
| 489 | twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, | ||
| 490 | REG_INT_MSK_STS_A); | ||
| 491 | } | ||
| 492 | |||
| 435 | /* Check RTC module status, Enable if it is off */ | 493 | /* Check RTC module status, Enable if it is off */ |
| 436 | ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG); | 494 | ret = twl_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG); |
| 437 | if (ret < 0) | 495 | if (ret < 0) |
| 438 | goto out2; | 496 | goto out2; |
| 439 | 497 | ||
| 440 | if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) { | 498 | if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) { |
| 441 | dev_info(&pdev->dev, "Enabling TWL4030-RTC.\n"); | 499 | dev_info(&pdev->dev, "Enabling TWL-RTC.\n"); |
| 442 | rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M; | 500 | rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M; |
| 443 | ret = twl4030_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG); | 501 | ret = twl_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG); |
| 444 | if (ret < 0) | 502 | if (ret < 0) |
| 445 | goto out2; | 503 | goto out2; |
| 446 | } | 504 | } |
| 447 | 505 | ||
| 448 | /* init cached IRQ enable bits */ | 506 | /* init cached IRQ enable bits */ |
| 449 | ret = twl4030_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG); | 507 | ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG); |
| 450 | if (ret < 0) | 508 | if (ret < 0) |
| 451 | goto out2; | 509 | goto out2; |
| 452 | 510 | ||
| @@ -461,10 +519,10 @@ out0: | |||
| 461 | } | 519 | } |
| 462 | 520 | ||
| 463 | /* | 521 | /* |
| 464 | * Disable all TWL4030 RTC module interrupts. | 522 | * Disable all TWL RTC module interrupts. |
| 465 | * Sets status flag to free. | 523 | * Sets status flag to free. |
| 466 | */ | 524 | */ |
| 467 | static int __devexit twl4030_rtc_remove(struct platform_device *pdev) | 525 | static int __devexit twl_rtc_remove(struct platform_device *pdev) |
| 468 | { | 526 | { |
| 469 | /* leave rtc running, but disable irqs */ | 527 | /* leave rtc running, but disable irqs */ |
| 470 | struct rtc_device *rtc = platform_get_drvdata(pdev); | 528 | struct rtc_device *rtc = platform_get_drvdata(pdev); |
| @@ -472,6 +530,13 @@ static int __devexit twl4030_rtc_remove(struct platform_device *pdev) | |||
| 472 | 530 | ||
| 473 | mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); | 531 | mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); |
| 474 | mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); | 532 | mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); |
| 533 | if (twl_class_is_6030()) { | ||
| 534 | twl6030_interrupt_mask(TWL6030_RTC_INT_MASK, | ||
| 535 | REG_INT_MSK_LINE_A); | ||
| 536 | twl6030_interrupt_mask(TWL6030_RTC_INT_MASK, | ||
| 537 | REG_INT_MSK_STS_A); | ||
| 538 | } | ||
| 539 | |||
| 475 | 540 | ||
| 476 | free_irq(irq, rtc); | 541 | free_irq(irq, rtc); |
| 477 | 542 | ||
| @@ -480,7 +545,7 @@ static int __devexit twl4030_rtc_remove(struct platform_device *pdev) | |||
| 480 | return 0; | 545 | return 0; |
| 481 | } | 546 | } |
| 482 | 547 | ||
| 483 | static void twl4030_rtc_shutdown(struct platform_device *pdev) | 548 | static void twl_rtc_shutdown(struct platform_device *pdev) |
| 484 | { | 549 | { |
| 485 | /* mask timer interrupts, but leave alarm interrupts on to enable | 550 | /* mask timer interrupts, but leave alarm interrupts on to enable |
| 486 | power-on when alarm is triggered */ | 551 | power-on when alarm is triggered */ |
| @@ -491,7 +556,7 @@ static void twl4030_rtc_shutdown(struct platform_device *pdev) | |||
| 491 | 556 | ||
| 492 | static unsigned char irqstat; | 557 | static unsigned char irqstat; |
| 493 | 558 | ||
| 494 | static int twl4030_rtc_suspend(struct platform_device *pdev, pm_message_t state) | 559 | static int twl_rtc_suspend(struct platform_device *pdev, pm_message_t state) |
| 495 | { | 560 | { |
| 496 | irqstat = rtc_irq_bits; | 561 | irqstat = rtc_irq_bits; |
| 497 | 562 | ||
| @@ -499,42 +564,47 @@ static int twl4030_rtc_suspend(struct platform_device *pdev, pm_message_t state) | |||
| 499 | return 0; | 564 | return 0; |
| 500 | } | 565 | } |
| 501 | 566 | ||
| 502 | static int twl4030_rtc_resume(struct platform_device *pdev) | 567 | static int twl_rtc_resume(struct platform_device *pdev) |
| 503 | { | 568 | { |
| 504 | set_rtc_irq_bit(irqstat); | 569 | set_rtc_irq_bit(irqstat); |
| 505 | return 0; | 570 | return 0; |
| 506 | } | 571 | } |
| 507 | 572 | ||
| 508 | #else | 573 | #else |
| 509 | #define twl4030_rtc_suspend NULL | 574 | #define twl_rtc_suspend NULL |
| 510 | #define twl4030_rtc_resume NULL | 575 | #define twl_rtc_resume NULL |
| 511 | #endif | 576 | #endif |
| 512 | 577 | ||
| 513 | MODULE_ALIAS("platform:twl4030_rtc"); | 578 | MODULE_ALIAS("platform:twl_rtc"); |
| 514 | 579 | ||
| 515 | static struct platform_driver twl4030rtc_driver = { | 580 | static struct platform_driver twl4030rtc_driver = { |
| 516 | .probe = twl4030_rtc_probe, | 581 | .probe = twl_rtc_probe, |
| 517 | .remove = __devexit_p(twl4030_rtc_remove), | 582 | .remove = __devexit_p(twl_rtc_remove), |
| 518 | .shutdown = twl4030_rtc_shutdown, | 583 | .shutdown = twl_rtc_shutdown, |
| 519 | .suspend = twl4030_rtc_suspend, | 584 | .suspend = twl_rtc_suspend, |
| 520 | .resume = twl4030_rtc_resume, | 585 | .resume = twl_rtc_resume, |
| 521 | .driver = { | 586 | .driver = { |
| 522 | .owner = THIS_MODULE, | 587 | .owner = THIS_MODULE, |
| 523 | .name = "twl4030_rtc", | 588 | .name = "twl_rtc", |
| 524 | }, | 589 | }, |
| 525 | }; | 590 | }; |
| 526 | 591 | ||
| 527 | static int __init twl4030_rtc_init(void) | 592 | static int __init twl_rtc_init(void) |
| 528 | { | 593 | { |
| 594 | if (twl_class_is_4030()) | ||
| 595 | rtc_reg_map = (u8 *) twl4030_rtc_reg_map; | ||
| 596 | else | ||
| 597 | rtc_reg_map = (u8 *) twl6030_rtc_reg_map; | ||
| 598 | |||
| 529 | return platform_driver_register(&twl4030rtc_driver); | 599 | return platform_driver_register(&twl4030rtc_driver); |
| 530 | } | 600 | } |
| 531 | module_init(twl4030_rtc_init); | 601 | module_init(twl_rtc_init); |
| 532 | 602 | ||
| 533 | static void __exit twl4030_rtc_exit(void) | 603 | static void __exit twl_rtc_exit(void) |
| 534 | { | 604 | { |
| 535 | platform_driver_unregister(&twl4030rtc_driver); | 605 | platform_driver_unregister(&twl4030rtc_driver); |
| 536 | } | 606 | } |
| 537 | module_exit(twl4030_rtc_exit); | 607 | module_exit(twl_rtc_exit); |
| 538 | 608 | ||
| 539 | MODULE_AUTHOR("Texas Instruments, MontaVista Software"); | 609 | MODULE_AUTHOR("Texas Instruments, MontaVista Software"); |
| 540 | MODULE_LICENSE("GPL"); | 610 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c index c91edc572eb6..f16486635a8e 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c | |||
| @@ -315,9 +315,9 @@ static int wm8350_rtc_update_irq_enable(struct device *dev, | |||
| 315 | return 0; | 315 | return 0; |
| 316 | } | 316 | } |
| 317 | 317 | ||
| 318 | static void wm8350_rtc_alarm_handler(struct wm8350 *wm8350, int irq, | 318 | static irqreturn_t wm8350_rtc_alarm_handler(int irq, void *data) |
| 319 | void *data) | ||
| 320 | { | 319 | { |
| 320 | struct wm8350 *wm8350 = data; | ||
| 321 | struct rtc_device *rtc = wm8350->rtc.rtc; | 321 | struct rtc_device *rtc = wm8350->rtc.rtc; |
| 322 | int ret; | 322 | int ret; |
| 323 | 323 | ||
| @@ -330,14 +330,18 @@ static void wm8350_rtc_alarm_handler(struct wm8350 *wm8350, int irq, | |||
| 330 | dev_err(&(wm8350->rtc.pdev->dev), | 330 | dev_err(&(wm8350->rtc.pdev->dev), |
| 331 | "Failed to disable alarm: %d\n", ret); | 331 | "Failed to disable alarm: %d\n", ret); |
| 332 | } | 332 | } |
| 333 | |||
| 334 | return IRQ_HANDLED; | ||
| 333 | } | 335 | } |
| 334 | 336 | ||
| 335 | static void wm8350_rtc_update_handler(struct wm8350 *wm8350, int irq, | 337 | static irqreturn_t wm8350_rtc_update_handler(int irq, void *data) |
| 336 | void *data) | ||
| 337 | { | 338 | { |
| 339 | struct wm8350 *wm8350 = data; | ||
| 338 | struct rtc_device *rtc = wm8350->rtc.rtc; | 340 | struct rtc_device *rtc = wm8350->rtc.rtc; |
| 339 | 341 | ||
| 340 | rtc_update_irq(rtc, 1, RTC_IRQF | RTC_UF); | 342 | rtc_update_irq(rtc, 1, RTC_IRQF | RTC_UF); |
| 343 | |||
| 344 | return IRQ_HANDLED; | ||
| 341 | } | 345 | } |
| 342 | 346 | ||
| 343 | static const struct rtc_class_ops wm8350_rtc_ops = { | 347 | static const struct rtc_class_ops wm8350_rtc_ops = { |
| @@ -455,15 +459,14 @@ static int wm8350_rtc_probe(struct platform_device *pdev) | |||
| 455 | return ret; | 459 | return ret; |
| 456 | } | 460 | } |
| 457 | 461 | ||
| 458 | wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC); | ||
| 459 | wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_PER); | ||
| 460 | |||
| 461 | wm8350_register_irq(wm8350, WM8350_IRQ_RTC_SEC, | 462 | wm8350_register_irq(wm8350, WM8350_IRQ_RTC_SEC, |
| 462 | wm8350_rtc_update_handler, NULL); | 463 | wm8350_rtc_update_handler, 0, |
| 464 | "RTC Seconds", wm8350); | ||
| 465 | wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC); | ||
| 463 | 466 | ||
| 464 | wm8350_register_irq(wm8350, WM8350_IRQ_RTC_ALM, | 467 | wm8350_register_irq(wm8350, WM8350_IRQ_RTC_ALM, |
| 465 | wm8350_rtc_alarm_handler, NULL); | 468 | wm8350_rtc_alarm_handler, 0, |
| 466 | wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_ALM); | 469 | "RTC Alarm", wm8350); |
| 467 | 470 | ||
| 468 | return 0; | 471 | return 0; |
| 469 | } | 472 | } |
| @@ -473,8 +476,6 @@ static int __devexit wm8350_rtc_remove(struct platform_device *pdev) | |||
| 473 | struct wm8350 *wm8350 = platform_get_drvdata(pdev); | 476 | struct wm8350 *wm8350 = platform_get_drvdata(pdev); |
| 474 | struct wm8350_rtc *wm_rtc = &wm8350->rtc; | 477 | struct wm8350_rtc *wm_rtc = &wm8350->rtc; |
| 475 | 478 | ||
| 476 | wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC); | ||
| 477 | |||
| 478 | wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC); | 479 | wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC); |
| 479 | wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM); | 480 | wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM); |
| 480 | 481 | ||
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c index bd9883f41e63..2be9f2fa41f9 100644 --- a/drivers/usb/otg/twl4030-usb.c +++ b/drivers/usb/otg/twl4030-usb.c | |||
| @@ -33,7 +33,7 @@ | |||
| 33 | #include <linux/io.h> | 33 | #include <linux/io.h> |
| 34 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
| 35 | #include <linux/usb/otg.h> | 35 | #include <linux/usb/otg.h> |
| 36 | #include <linux/i2c/twl4030.h> | 36 | #include <linux/i2c/twl.h> |
| 37 | #include <linux/regulator/consumer.h> | 37 | #include <linux/regulator/consumer.h> |
| 38 | #include <linux/err.h> | 38 | #include <linux/err.h> |
| 39 | 39 | ||
| @@ -276,16 +276,16 @@ static int twl4030_i2c_write_u8_verify(struct twl4030_usb *twl, | |||
| 276 | { | 276 | { |
| 277 | u8 check; | 277 | u8 check; |
| 278 | 278 | ||
| 279 | if ((twl4030_i2c_write_u8(module, data, address) >= 0) && | 279 | if ((twl_i2c_write_u8(module, data, address) >= 0) && |
| 280 | (twl4030_i2c_read_u8(module, &check, address) >= 0) && | 280 | (twl_i2c_read_u8(module, &check, address) >= 0) && |
| 281 | (check == data)) | 281 | (check == data)) |
| 282 | return 0; | 282 | return 0; |
| 283 | dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n", | 283 | dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n", |
| 284 | 1, module, address, check, data); | 284 | 1, module, address, check, data); |
| 285 | 285 | ||
| 286 | /* Failed once: Try again */ | 286 | /* Failed once: Try again */ |
| 287 | if ((twl4030_i2c_write_u8(module, data, address) >= 0) && | 287 | if ((twl_i2c_write_u8(module, data, address) >= 0) && |
| 288 | (twl4030_i2c_read_u8(module, &check, address) >= 0) && | 288 | (twl_i2c_read_u8(module, &check, address) >= 0) && |
| 289 | (check == data)) | 289 | (check == data)) |
| 290 | return 0; | 290 | return 0; |
| 291 | dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n", | 291 | dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n", |
| @@ -303,7 +303,7 @@ static inline int twl4030_usb_write(struct twl4030_usb *twl, | |||
| 303 | { | 303 | { |
| 304 | int ret = 0; | 304 | int ret = 0; |
| 305 | 305 | ||
| 306 | ret = twl4030_i2c_write_u8(TWL4030_MODULE_USB, data, address); | 306 | ret = twl_i2c_write_u8(TWL4030_MODULE_USB, data, address); |
| 307 | if (ret < 0) | 307 | if (ret < 0) |
| 308 | dev_dbg(twl->dev, | 308 | dev_dbg(twl->dev, |
| 309 | "TWL4030:USB:Write[0x%x] Error %d\n", address, ret); | 309 | "TWL4030:USB:Write[0x%x] Error %d\n", address, ret); |
| @@ -315,7 +315,7 @@ static inline int twl4030_readb(struct twl4030_usb *twl, u8 module, u8 address) | |||
| 315 | u8 data; | 315 | u8 data; |
| 316 | int ret = 0; | 316 | int ret = 0; |
| 317 | 317 | ||
| 318 | ret = twl4030_i2c_read_u8(module, &data, address); | 318 | ret = twl_i2c_read_u8(module, &data, address); |
| 319 | if (ret >= 0) | 319 | if (ret >= 0) |
| 320 | ret = data; | 320 | ret = data; |
| 321 | else | 321 | else |
| @@ -462,7 +462,7 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on) | |||
| 462 | * SLEEP. We work around this by clearing the bit after usv3v1 | 462 | * SLEEP. We work around this by clearing the bit after usv3v1 |
| 463 | * is re-activated. This ensures that VUSB3V1 is really active. | 463 | * is re-activated. This ensures that VUSB3V1 is really active. |
| 464 | */ | 464 | */ |
| 465 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, | 465 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, |
| 466 | VUSB_DEDICATED2); | 466 | VUSB_DEDICATED2); |
| 467 | regulator_enable(twl->usb1v5); | 467 | regulator_enable(twl->usb1v5); |
| 468 | pwr &= ~PHY_PWR_PHYPWD; | 468 | pwr &= ~PHY_PWR_PHYPWD; |
| @@ -505,44 +505,44 @@ static void twl4030_phy_resume(struct twl4030_usb *twl) | |||
| 505 | static int twl4030_usb_ldo_init(struct twl4030_usb *twl) | 505 | static int twl4030_usb_ldo_init(struct twl4030_usb *twl) |
| 506 | { | 506 | { |
| 507 | /* Enable writing to power configuration registers */ | 507 | /* Enable writing to power configuration registers */ |
| 508 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY); | 508 | twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY); |
| 509 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x0C, PROTECT_KEY); | 509 | twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x0C, PROTECT_KEY); |
| 510 | 510 | ||
| 511 | /* put VUSB3V1 LDO in active state */ | 511 | /* put VUSB3V1 LDO in active state */ |
| 512 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2); | 512 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2); |
| 513 | 513 | ||
| 514 | /* input to VUSB3V1 LDO is from VBAT, not VBUS */ | 514 | /* input to VUSB3V1 LDO is from VBAT, not VBUS */ |
| 515 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1); | 515 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1); |
| 516 | 516 | ||
| 517 | /* Initialize 3.1V regulator */ | 517 | /* Initialize 3.1V regulator */ |
| 518 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP); | 518 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP); |
| 519 | 519 | ||
| 520 | twl->usb3v1 = regulator_get(twl->dev, "usb3v1"); | 520 | twl->usb3v1 = regulator_get(twl->dev, "usb3v1"); |
| 521 | if (IS_ERR(twl->usb3v1)) | 521 | if (IS_ERR(twl->usb3v1)) |
| 522 | return -ENODEV; | 522 | return -ENODEV; |
| 523 | 523 | ||
| 524 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE); | 524 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE); |
| 525 | 525 | ||
| 526 | /* Initialize 1.5V regulator */ | 526 | /* Initialize 1.5V regulator */ |
| 527 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP); | 527 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP); |
| 528 | 528 | ||
| 529 | twl->usb1v5 = regulator_get(twl->dev, "usb1v5"); | 529 | twl->usb1v5 = regulator_get(twl->dev, "usb1v5"); |
| 530 | if (IS_ERR(twl->usb1v5)) | 530 | if (IS_ERR(twl->usb1v5)) |
| 531 | goto fail1; | 531 | goto fail1; |
| 532 | 532 | ||
| 533 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE); | 533 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE); |
| 534 | 534 | ||
| 535 | /* Initialize 1.8V regulator */ | 535 | /* Initialize 1.8V regulator */ |
| 536 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP); | 536 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP); |
| 537 | 537 | ||
| 538 | twl->usb1v8 = regulator_get(twl->dev, "usb1v8"); | 538 | twl->usb1v8 = regulator_get(twl->dev, "usb1v8"); |
| 539 | if (IS_ERR(twl->usb1v8)) | 539 | if (IS_ERR(twl->usb1v8)) |
| 540 | goto fail2; | 540 | goto fail2; |
| 541 | 541 | ||
| 542 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE); | 542 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE); |
| 543 | 543 | ||
| 544 | /* disable access to power configuration registers */ | 544 | /* disable access to power configuration registers */ |
| 545 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY); | 545 | twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY); |
| 546 | 546 | ||
| 547 | return 0; | 547 | return 0; |
| 548 | 548 | ||
diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c index ad05da5ba3c7..4c10edecfb66 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | struct adp5520_bl { | 16 | struct adp5520_bl { |
| 17 | struct device *master; | 17 | struct device *master; |
| 18 | struct adp5520_backlight_platfrom_data *pdata; | 18 | struct adp5520_backlight_platform_data *pdata; |
| 19 | struct mutex lock; | 19 | struct mutex lock; |
| 20 | unsigned long cached_daylight_max; | 20 | unsigned long cached_daylight_max; |
| 21 | int id; | 21 | int id; |
| @@ -31,29 +31,30 @@ static int adp5520_bl_set(struct backlight_device *bl, int brightness) | |||
| 31 | if (data->pdata->en_ambl_sens) { | 31 | if (data->pdata->en_ambl_sens) { |
| 32 | if ((brightness > 0) && (brightness < ADP5020_MAX_BRIGHTNESS)) { | 32 | if ((brightness > 0) && (brightness < ADP5020_MAX_BRIGHTNESS)) { |
| 33 | /* Disable Ambient Light auto adjust */ | 33 | /* Disable Ambient Light auto adjust */ |
| 34 | ret |= adp5520_clr_bits(master, BL_CONTROL, | 34 | ret |= adp5520_clr_bits(master, ADP5520_BL_CONTROL, |
| 35 | BL_AUTO_ADJ); | 35 | ADP5520_BL_AUTO_ADJ); |
| 36 | ret |= adp5520_write(master, DAYLIGHT_MAX, brightness); | 36 | ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX, |
| 37 | brightness); | ||
| 37 | } else { | 38 | } else { |
| 38 | /* | 39 | /* |
| 39 | * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust | 40 | * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust |
| 40 | * restore daylight l3 sysfs brightness | 41 | * restore daylight l3 sysfs brightness |
| 41 | */ | 42 | */ |
| 42 | ret |= adp5520_write(master, DAYLIGHT_MAX, | 43 | ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX, |
| 43 | data->cached_daylight_max); | 44 | data->cached_daylight_max); |
| 44 | ret |= adp5520_set_bits(master, BL_CONTROL, | 45 | ret |= adp5520_set_bits(master, ADP5520_BL_CONTROL, |
| 45 | BL_AUTO_ADJ); | 46 | ADP5520_BL_AUTO_ADJ); |
| 46 | } | 47 | } |
| 47 | } else { | 48 | } else { |
| 48 | ret |= adp5520_write(master, DAYLIGHT_MAX, brightness); | 49 | ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX, brightness); |
| 49 | } | 50 | } |
| 50 | 51 | ||
| 51 | if (data->current_brightness && brightness == 0) | 52 | if (data->current_brightness && brightness == 0) |
| 52 | ret |= adp5520_set_bits(master, | 53 | ret |= adp5520_set_bits(master, |
| 53 | MODE_STATUS, DIM_EN); | 54 | ADP5520_MODE_STATUS, ADP5520_DIM_EN); |
| 54 | else if (data->current_brightness == 0 && brightness) | 55 | else if (data->current_brightness == 0 && brightness) |
| 55 | ret |= adp5520_clr_bits(master, | 56 | ret |= adp5520_clr_bits(master, |
| 56 | MODE_STATUS, DIM_EN); | 57 | ADP5520_MODE_STATUS, ADP5520_DIM_EN); |
| 57 | 58 | ||
| 58 | if (!ret) | 59 | if (!ret) |
| 59 | data->current_brightness = brightness; | 60 | data->current_brightness = brightness; |
| @@ -79,7 +80,7 @@ static int adp5520_bl_get_brightness(struct backlight_device *bl) | |||
| 79 | int error; | 80 | int error; |
| 80 | uint8_t reg_val; | 81 | uint8_t reg_val; |
| 81 | 82 | ||
| 82 | error = adp5520_read(data->master, BL_VALUE, ®_val); | 83 | error = adp5520_read(data->master, ADP5520_BL_VALUE, ®_val); |
| 83 | 84 | ||
| 84 | return error ? data->current_brightness : reg_val; | 85 | return error ? data->current_brightness : reg_val; |
| 85 | } | 86 | } |
| @@ -93,33 +94,46 @@ static int adp5520_bl_setup(struct backlight_device *bl) | |||
| 93 | { | 94 | { |
| 94 | struct adp5520_bl *data = bl_get_data(bl); | 95 | struct adp5520_bl *data = bl_get_data(bl); |
| 95 | struct device *master = data->master; | 96 | struct device *master = data->master; |
| 96 | struct adp5520_backlight_platfrom_data *pdata = data->pdata; | 97 | struct adp5520_backlight_platform_data *pdata = data->pdata; |
| 97 | int ret = 0; | 98 | int ret = 0; |
| 98 | 99 | ||
| 99 | ret |= adp5520_write(master, DAYLIGHT_MAX, pdata->l1_daylight_max); | 100 | ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX, |
| 100 | ret |= adp5520_write(master, DAYLIGHT_DIM, pdata->l1_daylight_dim); | 101 | pdata->l1_daylight_max); |
| 102 | ret |= adp5520_write(master, ADP5520_DAYLIGHT_DIM, | ||
| 103 | pdata->l1_daylight_dim); | ||
| 101 | 104 | ||
| 102 | if (pdata->en_ambl_sens) { | 105 | if (pdata->en_ambl_sens) { |
| 103 | data->cached_daylight_max = pdata->l1_daylight_max; | 106 | data->cached_daylight_max = pdata->l1_daylight_max; |
| 104 | ret |= adp5520_write(master, OFFICE_MAX, pdata->l2_office_max); | 107 | ret |= adp5520_write(master, ADP5520_OFFICE_MAX, |
| 105 | ret |= adp5520_write(master, OFFICE_DIM, pdata->l2_office_dim); | 108 | pdata->l2_office_max); |
| 106 | ret |= adp5520_write(master, DARK_MAX, pdata->l3_dark_max); | 109 | ret |= adp5520_write(master, ADP5520_OFFICE_DIM, |
| 107 | ret |= adp5520_write(master, DARK_DIM, pdata->l3_dark_dim); | 110 | pdata->l2_office_dim); |
| 108 | ret |= adp5520_write(master, L2_TRIP, pdata->l2_trip); | 111 | ret |= adp5520_write(master, ADP5520_DARK_MAX, |
| 109 | ret |= adp5520_write(master, L2_HYS, pdata->l2_hyst); | 112 | pdata->l3_dark_max); |
| 110 | ret |= adp5520_write(master, L3_TRIP, pdata->l3_trip); | 113 | ret |= adp5520_write(master, ADP5520_DARK_DIM, |
| 111 | ret |= adp5520_write(master, L3_HYS, pdata->l3_hyst); | 114 | pdata->l3_dark_dim); |
| 112 | ret |= adp5520_write(master, ALS_CMPR_CFG, | 115 | ret |= adp5520_write(master, ADP5520_L2_TRIP, |
| 113 | ALS_CMPR_CFG_VAL(pdata->abml_filt, L3_EN)); | 116 | pdata->l2_trip); |
| 117 | ret |= adp5520_write(master, ADP5520_L2_HYS, | ||
| 118 | pdata->l2_hyst); | ||
| 119 | ret |= adp5520_write(master, ADP5520_L3_TRIP, | ||
| 120 | pdata->l3_trip); | ||
| 121 | ret |= adp5520_write(master, ADP5520_L3_HYS, | ||
| 122 | pdata->l3_hyst); | ||
| 123 | ret |= adp5520_write(master, ADP5520_ALS_CMPR_CFG, | ||
| 124 | ALS_CMPR_CFG_VAL(pdata->abml_filt, | ||
| 125 | ADP5520_L3_EN)); | ||
| 114 | } | 126 | } |
| 115 | 127 | ||
| 116 | ret |= adp5520_write(master, BL_CONTROL, | 128 | ret |= adp5520_write(master, ADP5520_BL_CONTROL, |
| 117 | BL_CTRL_VAL(pdata->fade_led_law, pdata->en_ambl_sens)); | 129 | BL_CTRL_VAL(pdata->fade_led_law, |
| 130 | pdata->en_ambl_sens)); | ||
| 118 | 131 | ||
| 119 | ret |= adp5520_write(master, BL_FADE, FADE_VAL(pdata->fade_in, | 132 | ret |= adp5520_write(master, ADP5520_BL_FADE, FADE_VAL(pdata->fade_in, |
| 120 | pdata->fade_out)); | 133 | pdata->fade_out)); |
| 121 | 134 | ||
| 122 | ret |= adp5520_set_bits(master, MODE_STATUS, BL_EN | DIM_EN); | 135 | ret |= adp5520_set_bits(master, ADP5520_MODE_STATUS, |
| 136 | ADP5520_BL_EN | ADP5520_DIM_EN); | ||
| 123 | 137 | ||
| 124 | return ret; | 138 | return ret; |
| 125 | } | 139 | } |
| @@ -156,29 +170,31 @@ static ssize_t adp5520_store(struct device *dev, const char *buf, | |||
| 156 | } | 170 | } |
| 157 | 171 | ||
| 158 | static ssize_t adp5520_bl_dark_max_show(struct device *dev, | 172 | static ssize_t adp5520_bl_dark_max_show(struct device *dev, |
| 159 | struct device_attribute *attr, char *buf) | 173 | struct device_attribute *attr, char *buf) |
| 160 | { | 174 | { |
| 161 | return adp5520_show(dev, buf, DARK_MAX); | 175 | return adp5520_show(dev, buf, ADP5520_DARK_MAX); |
| 162 | } | 176 | } |
| 163 | 177 | ||
| 164 | static ssize_t adp5520_bl_dark_max_store(struct device *dev, | 178 | static ssize_t adp5520_bl_dark_max_store(struct device *dev, |
| 165 | struct device_attribute *attr, const char *buf, size_t count) | 179 | struct device_attribute *attr, |
| 180 | const char *buf, size_t count) | ||
| 166 | { | 181 | { |
| 167 | return adp5520_store(dev, buf, count, DARK_MAX); | 182 | return adp5520_store(dev, buf, count, ADP5520_DARK_MAX); |
| 168 | } | 183 | } |
| 169 | static DEVICE_ATTR(dark_max, 0664, adp5520_bl_dark_max_show, | 184 | static DEVICE_ATTR(dark_max, 0664, adp5520_bl_dark_max_show, |
| 170 | adp5520_bl_dark_max_store); | 185 | adp5520_bl_dark_max_store); |
| 171 | 186 | ||
| 172 | static ssize_t adp5520_bl_office_max_show(struct device *dev, | 187 | static ssize_t adp5520_bl_office_max_show(struct device *dev, |
| 173 | struct device_attribute *attr, char *buf) | 188 | struct device_attribute *attr, char *buf) |
| 174 | { | 189 | { |
| 175 | return adp5520_show(dev, buf, OFFICE_MAX); | 190 | return adp5520_show(dev, buf, ADP5520_OFFICE_MAX); |
| 176 | } | 191 | } |
| 177 | 192 | ||
| 178 | static ssize_t adp5520_bl_office_max_store(struct device *dev, | 193 | static ssize_t adp5520_bl_office_max_store(struct device *dev, |
| 179 | struct device_attribute *attr, const char *buf, size_t count) | 194 | struct device_attribute *attr, |
| 195 | const char *buf, size_t count) | ||
| 180 | { | 196 | { |
| 181 | return adp5520_store(dev, buf, count, OFFICE_MAX); | 197 | return adp5520_store(dev, buf, count, ADP5520_OFFICE_MAX); |
| 182 | } | 198 | } |
| 183 | static DEVICE_ATTR(office_max, 0664, adp5520_bl_office_max_show, | 199 | static DEVICE_ATTR(office_max, 0664, adp5520_bl_office_max_show, |
| 184 | adp5520_bl_office_max_store); | 200 | adp5520_bl_office_max_store); |
| @@ -186,16 +202,17 @@ static DEVICE_ATTR(office_max, 0664, adp5520_bl_office_max_show, | |||
| 186 | static ssize_t adp5520_bl_daylight_max_show(struct device *dev, | 202 | static ssize_t adp5520_bl_daylight_max_show(struct device *dev, |
| 187 | struct device_attribute *attr, char *buf) | 203 | struct device_attribute *attr, char *buf) |
| 188 | { | 204 | { |
| 189 | return adp5520_show(dev, buf, DAYLIGHT_MAX); | 205 | return adp5520_show(dev, buf, ADP5520_DAYLIGHT_MAX); |
| 190 | } | 206 | } |
| 191 | 207 | ||
| 192 | static ssize_t adp5520_bl_daylight_max_store(struct device *dev, | 208 | static ssize_t adp5520_bl_daylight_max_store(struct device *dev, |
| 193 | struct device_attribute *attr, const char *buf, size_t count) | 209 | struct device_attribute *attr, |
| 210 | const char *buf, size_t count) | ||
| 194 | { | 211 | { |
| 195 | struct adp5520_bl *data = dev_get_drvdata(dev); | 212 | struct adp5520_bl *data = dev_get_drvdata(dev); |
| 196 | 213 | ||
| 197 | strict_strtoul(buf, 10, &data->cached_daylight_max); | 214 | strict_strtoul(buf, 10, &data->cached_daylight_max); |
| 198 | return adp5520_store(dev, buf, count, DAYLIGHT_MAX); | 215 | return adp5520_store(dev, buf, count, ADP5520_DAYLIGHT_MAX); |
| 199 | } | 216 | } |
| 200 | static DEVICE_ATTR(daylight_max, 0664, adp5520_bl_daylight_max_show, | 217 | static DEVICE_ATTR(daylight_max, 0664, adp5520_bl_daylight_max_show, |
| 201 | adp5520_bl_daylight_max_store); | 218 | adp5520_bl_daylight_max_store); |
| @@ -203,14 +220,14 @@ static DEVICE_ATTR(daylight_max, 0664, adp5520_bl_daylight_max_show, | |||
| 203 | static ssize_t adp5520_bl_dark_dim_show(struct device *dev, | 220 | static ssize_t adp5520_bl_dark_dim_show(struct device *dev, |
| 204 | struct device_attribute *attr, char *buf) | 221 | struct device_attribute *attr, char *buf) |
| 205 | { | 222 | { |
| 206 | return adp5520_show(dev, buf, DARK_DIM); | 223 | return adp5520_show(dev, buf, ADP5520_DARK_DIM); |
| 207 | } | 224 | } |
| 208 | 225 | ||
| 209 | static ssize_t adp5520_bl_dark_dim_store(struct device *dev, | 226 | static ssize_t adp5520_bl_dark_dim_store(struct device *dev, |
| 210 | struct device_attribute *attr, | 227 | struct device_attribute *attr, |
| 211 | const char *buf, size_t count) | 228 | const char *buf, size_t count) |
| 212 | { | 229 | { |
| 213 | return adp5520_store(dev, buf, count, DARK_DIM); | 230 | return adp5520_store(dev, buf, count, ADP5520_DARK_DIM); |
| 214 | } | 231 | } |
| 215 | static DEVICE_ATTR(dark_dim, 0664, adp5520_bl_dark_dim_show, | 232 | static DEVICE_ATTR(dark_dim, 0664, adp5520_bl_dark_dim_show, |
| 216 | adp5520_bl_dark_dim_store); | 233 | adp5520_bl_dark_dim_store); |
| @@ -218,29 +235,29 @@ static DEVICE_ATTR(dark_dim, 0664, adp5520_bl_dark_dim_show, | |||
| 218 | static ssize_t adp5520_bl_office_dim_show(struct device *dev, | 235 | static ssize_t adp5520_bl_office_dim_show(struct device *dev, |
| 219 | struct device_attribute *attr, char *buf) | 236 | struct device_attribute *attr, char *buf) |
| 220 | { | 237 | { |
| 221 | return adp5520_show(dev, buf, OFFICE_DIM); | 238 | return adp5520_show(dev, buf, ADP5520_OFFICE_DIM); |
| 222 | } | 239 | } |
| 223 | 240 | ||
| 224 | static ssize_t adp5520_bl_office_dim_store(struct device *dev, | 241 | static ssize_t adp5520_bl_office_dim_store(struct device *dev, |
| 225 | struct device_attribute *attr, | 242 | struct device_attribute *attr, |
| 226 | const char *buf, size_t count) | 243 | const char *buf, size_t count) |
| 227 | { | 244 | { |
| 228 | return adp5520_store(dev, buf, count, OFFICE_DIM); | 245 | return adp5520_store(dev, buf, count, ADP5520_OFFICE_DIM); |
| 229 | } | 246 | } |
| 230 | static DEVICE_ATTR(office_dim, 0664, adp5520_bl_office_dim_show, | 247 | static DEVICE_ATTR(office_dim, 0664, adp5520_bl_office_dim_show, |
| 231 | adp5520_bl_office_dim_store); | 248 | adp5520_bl_office_dim_store); |
| 232 | 249 | ||
| 233 | static ssize_t adp5520_bl_daylight_dim_show(struct device *dev, | 250 | static ssize_t adp5520_bl_daylight_dim_show(struct device *dev, |
| 234 | struct device_attribute *attr, char *buf) | 251 | struct device_attribute *attr, char *buf) |
| 235 | { | 252 | { |
| 236 | return adp5520_show(dev, buf, DAYLIGHT_DIM); | 253 | return adp5520_show(dev, buf, ADP5520_DAYLIGHT_DIM); |
| 237 | } | 254 | } |
| 238 | 255 | ||
| 239 | static ssize_t adp5520_bl_daylight_dim_store(struct device *dev, | 256 | static ssize_t adp5520_bl_daylight_dim_store(struct device *dev, |
| 240 | struct device_attribute *attr, | 257 | struct device_attribute *attr, |
| 241 | const char *buf, size_t count) | 258 | const char *buf, size_t count) |
| 242 | { | 259 | { |
| 243 | return adp5520_store(dev, buf, count, DAYLIGHT_DIM); | 260 | return adp5520_store(dev, buf, count, ADP5520_DAYLIGHT_DIM); |
| 244 | } | 261 | } |
| 245 | static DEVICE_ATTR(daylight_dim, 0664, adp5520_bl_daylight_dim_show, | 262 | static DEVICE_ATTR(daylight_dim, 0664, adp5520_bl_daylight_dim_show, |
| 246 | adp5520_bl_daylight_dim_store); | 263 | adp5520_bl_daylight_dim_store); |
| @@ -316,7 +333,7 @@ static int __devexit adp5520_bl_remove(struct platform_device *pdev) | |||
| 316 | struct backlight_device *bl = platform_get_drvdata(pdev); | 333 | struct backlight_device *bl = platform_get_drvdata(pdev); |
| 317 | struct adp5520_bl *data = bl_get_data(bl); | 334 | struct adp5520_bl *data = bl_get_data(bl); |
| 318 | 335 | ||
| 319 | adp5520_clr_bits(data->master, MODE_STATUS, BL_EN); | 336 | adp5520_clr_bits(data->master, ADP5520_MODE_STATUS, ADP5520_BL_EN); |
| 320 | 337 | ||
| 321 | if (data->pdata->en_ambl_sens) | 338 | if (data->pdata->en_ambl_sens) |
| 322 | sysfs_remove_group(&bl->dev.kobj, | 339 | sysfs_remove_group(&bl->dev.kobj, |
diff --git a/drivers/video/omap/lcd_2430sdp.c b/drivers/video/omap/lcd_2430sdp.c index 760645d9dbb6..e3eccc9af78e 100644 --- a/drivers/video/omap/lcd_2430sdp.c +++ b/drivers/video/omap/lcd_2430sdp.c | |||
| @@ -25,7 +25,7 @@ | |||
| 25 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
| 26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
| 27 | #include <linux/gpio.h> | 27 | #include <linux/gpio.h> |
| 28 | #include <linux/i2c/twl4030.h> | 28 | #include <linux/i2c/twl.h> |
| 29 | 29 | ||
| 30 | #include <plat/mux.h> | 30 | #include <plat/mux.h> |
| 31 | #include <asm/mach-types.h> | 31 | #include <asm/mach-types.h> |
| @@ -52,7 +52,7 @@ static unsigned enable_gpio; | |||
| 52 | #define TWL4030_VPLL2_DEV_GRP 0x33 | 52 | #define TWL4030_VPLL2_DEV_GRP 0x33 |
| 53 | #define TWL4030_VPLL2_DEDICATED 0x36 | 53 | #define TWL4030_VPLL2_DEDICATED 0x36 |
| 54 | 54 | ||
| 55 | #define t2_out(c, r, v) twl4030_i2c_write_u8(c, r, v) | 55 | #define t2_out(c, r, v) twl_i2c_write_u8(c, r, v) |
| 56 | 56 | ||
| 57 | 57 | ||
| 58 | static int sdp2430_panel_init(struct lcd_panel *panel, | 58 | static int sdp2430_panel_init(struct lcd_panel *panel, |
diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c index cb46556f2973..8162a40d1522 100644 --- a/drivers/watchdog/twl4030_wdt.c +++ b/drivers/watchdog/twl4030_wdt.c | |||
| @@ -26,7 +26,7 @@ | |||
| 26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
| 27 | #include <linux/miscdevice.h> | 27 | #include <linux/miscdevice.h> |
| 28 | #include <linux/uaccess.h> | 28 | #include <linux/uaccess.h> |
| 29 | #include <linux/i2c/twl4030.h> | 29 | #include <linux/i2c/twl.h> |
| 30 | 30 | ||
| 31 | #define TWL4030_WATCHDOG_CFG_REG_OFFS 0x3 | 31 | #define TWL4030_WATCHDOG_CFG_REG_OFFS 0x3 |
| 32 | 32 | ||
| @@ -48,7 +48,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " | |||
| 48 | 48 | ||
| 49 | static int twl4030_wdt_write(unsigned char val) | 49 | static int twl4030_wdt_write(unsigned char val) |
| 50 | { | 50 | { |
| 51 | return twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, val, | 51 | return twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, val, |
| 52 | TWL4030_WATCHDOG_CFG_REG_OFFS); | 52 | TWL4030_WATCHDOG_CFG_REG_OFFS); |
| 53 | } | 53 | } |
| 54 | 54 | ||
