Commit 76b8f82c authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents af853e63 9da66539
......@@ -19,7 +19,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
#include <linux/i2c/twl4030.h>
#include <linux/i2c/twl.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
......
......@@ -20,7 +20,7 @@
#include <linux/input/matrix_keypad.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
#include <linux/i2c/twl4030.h>
#include <linux/i2c/twl.h>
#include <linux/regulator/machine.h>
#include <linux/io.h>
#include <linux/gpio.h>
......
......@@ -24,7 +24,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl4030.h>
#include <linux/i2c/twl.h>
#include <linux/io.h>
#include <linux/smsc911x.h>
......
......@@ -29,7 +29,7 @@
#include <linux/mtd/nand.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl4030.h>
#include <linux/i2c/twl.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
......
......@@ -24,7 +24,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl4030.h>
#include <linux/i2c/twl.h>
#include <linux/leds.h>
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
......
......@@ -26,7 +26,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/i2c/twl4030.h>
#include <linux/i2c/twl.h>
#include <linux/regulator/machine.h>
#include <linux/mtd/mtd.h>
......
......@@ -402,15 +402,9 @@ static struct twl4030_usb_data rx51_usb_data = {
static struct twl4030_ins sleep_on_seq[] __initdata = {
/*
* Turn off VDD1 and VDD2.
* Turn off everything
*/
{MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_OFF), 4},
{MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_OFF), 2},
/*
* And also turn off the OMAP3 PLLs and the sysclk output.
*/
{MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_OFF), 3},
{MSG_SINGULAR(DEV_GRP_P1, 0x17, RES_STATE_OFF), 3},
{MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_SLEEP), 2},
};
static struct twl4030_script sleep_on_script __initdata = {
......@@ -421,14 +415,9 @@ static struct twl4030_script sleep_on_script __initdata = {
static struct twl4030_ins wakeup_seq[] __initdata = {
/*
* Reenable the OMAP3 PLLs.
* Wakeup VDD1 and VDD2.
* Reenable sysclk output.
* Reenable everything
*/
{MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_ACTIVE), 0x30},
{MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_ACTIVE), 0x30},
{MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_ACTIVE), 0x37},
{MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 3},
{MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_ACTIVE), 2},
};
static struct twl4030_script wakeup_script __initdata = {
......@@ -439,10 +428,9 @@ static struct twl4030_script wakeup_script __initdata = {
static struct twl4030_ins wakeup_p3_seq[] __initdata = {
/*
* Wakeup VDD1 (dummy to be able to insert a delay)
* Enable CLKEN
* Reenable everything
*/
{MSG_SINGULAR(DEV_GRP_P1, 0x17, RES_STATE_ACTIVE), 3},
{MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_ACTIVE), 2},
};
static struct twl4030_script wakeup_p3_script __initdata = {
......@@ -463,12 +451,11 @@ static struct twl4030_ins wrst_seq[] __initdata = {
{MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_OFF), 2},
{MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 0, 1, RES_STATE_ACTIVE),
0x13},
{MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_PP, 0, 2, RES_STATE_WRST), 0x13},
{MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_PP, 0, 3, RES_STATE_OFF), 0x13},
{MSG_SINGULAR(DEV_GRP_NULL, RES_VDD1, RES_STATE_WRST), 0x13},
{MSG_SINGULAR(DEV_GRP_NULL, RES_VDD2, RES_STATE_WRST), 0x13},
{MSG_SINGULAR(DEV_GRP_NULL, RES_VPLL1, RES_STATE_WRST), 0x35},
{MSG_SINGULAR(DEV_GRP_P1, RES_HFCLKOUT, RES_STATE_ACTIVE), 2},
{MSG_SINGULAR(DEV_GRP_P3, RES_HFCLKOUT, RES_STATE_ACTIVE), 2},
{MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_ACTIVE), 2},
};
......@@ -490,22 +477,81 @@ static struct twl4030_script *twl4030_scripts[] __initdata = {
};
static struct twl4030_resconfig twl4030_rconfig[] __initdata = {
{ .resource = RES_VINTANA1, .devgroup = -1, .type = -1, .type2 = 1 },
{ .resource = RES_VINTANA2, .devgroup = -1, .type = -1, .type2 = 1 },
{ .resource = RES_VINTDIG, .devgroup = -1, .type = -1, .type2 = 1 },
{ .resource = RES_VMMC1, .devgroup = -1, .type = -1, .type2 = 3},
{ .resource = RES_VMMC2, .devgroup = DEV_GRP_NULL, .type = -1,
.type2 = 3},
{ .resource = RES_VAUX1, .devgroup = -1, .type = -1, .type2 = 3},
{ .resource = RES_VAUX2, .devgroup = -1, .type = -1, .type2 = 3},
{ .resource = RES_VAUX3, .devgroup = -1, .type = -1, .type2 = 3},
{ .resource = RES_VAUX4, .devgroup = -1, .type = -1, .type2 = 3},
{ .resource = RES_VPLL2, .devgroup = -1, .type = -1, .type2 = 3},
{ .resource = RES_VDAC, .devgroup = -1, .type = -1, .type2 = 3},
{ .resource = RES_VSIM, .devgroup = DEV_GRP_NULL, .type = -1,
.type2 = 3},
{ .resource = RES_CLKEN, .devgroup = DEV_GRP_P3, .type = -1,
.type2 = 1 },
{ .resource = RES_VDD1, .devgroup = -1,
.type = 1, .type2 = -1, .remap_off = RES_STATE_OFF,
.remap_sleep = RES_STATE_OFF
},
{ .resource = RES_VDD2, .devgroup = -1,
.type = 1, .type2 = -1, .remap_off = RES_STATE_OFF,
.remap_sleep = RES_STATE_OFF
},
{ .resource = RES_VPLL1, .devgroup = -1,
.type = 1, .type2 = -1, .remap_off = RES_STATE_OFF,
.remap_sleep = RES_STATE_OFF
},
{ .resource = RES_VPLL2, .devgroup = -1,
.type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_VAUX1, .devgroup = -1,
.type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_VAUX2, .devgroup = -1,
.type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_VAUX3, .devgroup = -1,
.type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_VAUX4, .devgroup = -1,
.type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_VMMC1, .devgroup = -1,
.type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_VMMC2, .devgroup = -1,
.type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_VDAC, .devgroup = -1,
.type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_VSIM, .devgroup = -1,
.type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_VINTANA1, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
.type = -1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_VINTANA2, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
.type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_VINTDIG, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
.type = -1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_VIO, .devgroup = DEV_GRP_P3,
.type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_CLKEN, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
.type = 1, .type2 = -1 , .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_REGEN, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
.type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_NRES_PWRON, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
.type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_SYSEN, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
.type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_HFCLKOUT, .devgroup = DEV_GRP_P3,
.type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_32KCLKOUT, .devgroup = -1,
.type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_RESET, .devgroup = -1,
.type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
},
{ .resource = RES_Main_Ref, .devgroup = -1,
.type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
},
{ 0, 0},
};
......
......@@ -472,8 +472,22 @@
#endif
#define TWL4030_GPIO_IRQ_END (TWL4030_GPIO_IRQ_BASE + TWL4030_GPIO_NR_IRQS)
#define TWL6030_IRQ_BASE (OMAP_FPGA_IRQ_END)
#ifdef CONFIG_TWL4030_CORE
#define TWL6030_BASE_NR_IRQS 20
#else
#define TWL6030_BASE_NR_IRQS 0
#endif
#define TWL6030_IRQ_END (TWL6030_IRQ_BASE + TWL6030_BASE_NR_IRQS)
/* Total number of interrupts depends on the enabled blocks above */
#define NR_IRQS TWL4030_GPIO_IRQ_END
#if (TWL4030_GPIO_IRQ_END > TWL6030_IRQ_END)
#define TWL_IRQ_END TWL4030_GPIO_IRQ_END
#else
#define TWL_IRQ_END TWL6030_IRQ_END
#endif
#define NR_IRQS TWL_IRQ_END
#define OMAP_IRQ_BIT(irq) (1 << ((irq) % 32))
......
......@@ -34,9 +34,9 @@ static int adp5520_gpio_get_value(struct gpio_chip *chip, unsigned off)
*/
if (test_bit(off, &dev->output))
adp5520_read(dev->master, GPIO_OUT, &reg_val);
adp5520_read(dev->master, ADP5520_GPIO_OUT, &reg_val);
else
adp5520_read(dev->master, GPIO_IN, &reg_val);
adp5520_read(dev->master, ADP5520_GPIO_IN, &reg_val);
return !!(reg_val & dev->lut[off]);
}
......@@ -48,9 +48,9 @@ static void adp5520_gpio_set_value(struct gpio_chip *chip,
dev = container_of(chip, struct adp5520_gpio, gpio_chip);
if (val)
adp5520_set_bits(dev->master, GPIO_OUT, dev->lut[off]);
adp5520_set_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]);
else
adp5520_clr_bits(dev->master, GPIO_OUT, dev->lut[off]);
adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]);
}
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)
clear_bit(off, &dev->output);
return adp5520_clr_bits(dev->master, GPIO_CFG_2, dev->lut[off]);
return adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_2,
dev->lut[off]);
}
static int adp5520_gpio_direction_output(struct gpio_chip *chip,
......@@ -73,18 +74,21 @@ static int adp5520_gpio_direction_output(struct gpio_chip *chip,
set_bit(off, &dev->output);
if (val)
ret |= adp5520_set_bits(dev->master, GPIO_OUT, dev->lut[off]);
ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_OUT,
dev->lut[off]);
else
ret |= adp5520_clr_bits(dev->master, GPIO_OUT, dev->lut[off]);
ret |= adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT,
dev->lut[off]);
ret |= adp5520_set_bits(dev->master, GPIO_CFG_2, dev->lut[off]);
ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_CFG_2,
dev->lut[off]);
return ret;
}
static int __devinit adp5520_gpio_probe(struct platform_device *pdev)
{
struct adp5520_gpio_platfrom_data *pdata = pdev->dev.platform_data;
struct adp5520_gpio_platform_data *pdata = pdev->dev.platform_data;
struct adp5520_gpio *dev;
struct gpio_chip *gc;
int ret, i, gpios;
......@@ -129,20 +133,20 @@ static int __devinit adp5520_gpio_probe(struct platform_device *pdev)
gc->label = pdev->name;
gc->owner = THIS_MODULE;
ret = adp5520_clr_bits(dev->master, GPIO_CFG_1,
ret = adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_1,
pdata->gpio_en_mask);
if (pdata->gpio_en_mask & GPIO_C3)
ctl_mask |= C3_MODE;
if (pdata->gpio_en_mask & ADP5520_GPIO_C3)
ctl_mask |= ADP5520_C3_MODE;
if (pdata->gpio_en_mask & GPIO_R3)
ctl_mask |= R3_MODE;
if (pdata->gpio_en_mask & ADP5520_GPIO_R3)
ctl_mask |= ADP5520_R3_MODE;
if (ctl_mask)
ret = adp5520_set_bits(dev->master, LED_CONTROL,
ret = adp5520_set_bits(dev->master, ADP5520_LED_CONTROL,
ctl_mask);
ret |= adp5520_set_bits(dev->master, GPIO_PULLUP,
ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_PULLUP,
pdata->gpio_pullup_mask);
if (ret) {
......
......@@ -34,7 +34,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/i2c/twl4030.h>
#include <linux/i2c/twl.h>
/*
......@@ -80,7 +80,7 @@ static unsigned int gpio_usage_count;
*/
static inline int gpio_twl4030_write(u8 address, u8 data)
{
return twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, data, address);
return twl_i2c_write_u8(TWL4030_MODULE_GPIO, data, address);
}
/*----------------------------------------------------------------------*/
......@@ -117,7 +117,7 @@ static inline int gpio_twl4030_read(u8 address)
u8 data;
int ret = 0;
ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &data, address);
ret = twl_i2c_read_u8(TWL4030_MODULE_GPIO, &data, address);
return (ret < 0) ? ret : data;
}
......@@ -142,7 +142,7 @@ static void twl4030_led_set_value(int led, int value)
cached_leden &= ~mask;
else
cached_leden |= mask;
status = twl4030_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
TWL4030_LED_LEDEN);
mutex_unlock(&gpio_lock);
}
......@@ -223,23 +223,23 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
}
/* initialize PWM to always-drive */
status = twl4030_i2c_write_u8(module, 0x7f,
status = twl_i2c_write_u8(module, 0x7f,
TWL4030_PWMx_PWMxOFF);
if (status < 0)
goto done;
status = twl4030_i2c_write_u8(module, 0x7f,
status = twl_i2c_write_u8(module, 0x7f,
TWL4030_PWMx_PWMxON);
if (status < 0)
goto done;
/* init LED to not-driven (high) */
module = TWL4030_MODULE_LED;
status = twl4030_i2c_read_u8(module, &cached_leden,
status = twl_i2c_read_u8(module, &cached_leden,
TWL4030_LED_LEDEN);
if (status < 0)
goto done;
cached_leden &= ~ledclr_mask;
status = twl4030_i2c_write_u8(module, cached_leden,
status = twl_i2c_write_u8(module, cached_leden,
TWL4030_LED_LEDEN);
if (status < 0)
goto done;
......@@ -370,7 +370,7 @@ static int __devinit gpio_twl4030_pulls(u32 ups, u32 downs)
message[i] = bit_mask;
}
return twl4030_i2c_write(TWL4030_MODULE_GPIO, message,
return twl_i2c_write(TWL4030_MODULE_GPIO, message,
REG_GPIOPUPDCTR1, 5);
}
......@@ -387,7 +387,7 @@ static int __devinit gpio_twl4030_debounce(u32 debounce, u8 mmc_cd)
debounce >>= 8;
message[3] = (debounce & 0x03);
return twl4030_i2c_write(TWL4030_MODULE_GPIO, message,
return twl_i2c_write(TWL4030_MODULE_GPIO, message,
REG_GPIO_DEBEN1, 3);
}
......
......@@ -22,8 +22,7 @@
#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/pdata.h>
#include <linux/mfd/wm831x/gpio.h>
#define WM831X_GPIO_MAX 16
#include <linux/mfd/wm831x/irq.h>
struct wm831x_gpio {
struct wm831x *wm831x;
......@@ -80,6 +79,17 @@ static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
value << offset);
}
static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
struct wm831x *wm831x = wm831x_gpio->wm831x;
if (!wm831x->irq_base)
return -EINVAL;
return wm831x->irq_base + WM831X_IRQ_GPIO_1 + offset;
}
#ifdef CONFIG_DEBUG_FS
static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
......@@ -175,6 +185,7 @@ static struct gpio_chip template_chip = {
.get = wm831x_gpio_get,
.direction_output = wm831x_gpio_direction_out,
.set = wm831x_gpio_set,
.to_irq = wm831x_gpio_to_irq,
.dbg_show = wm831x_gpio_dbg_show,
.can_sleep = 1,
};
......@@ -192,7 +203,7 @@ static int __devinit wm831x_gpio_probe(struct platform_device *pdev)
wm831x_gpio->wm831x = wm831x;
wm831x_gpio->gpio_chip = template_chip;
wm831x_gpio->gpio_chip.ngpio = WM831X_GPIO_MAX;
wm831x_gpio->gpio_chip.ngpio = wm831x->num_gpio;
wm831x_gpio->gpio_chip.dev = &pdev->dev;
if (pdata && pdata->gpio_base)
wm831x_gpio->gpio_chip.base = pdata->gpio_base;
......
......@@ -24,6 +24,16 @@ config KEYBOARD_AAED2000
To compile this driver as a module, choose M here: the
module will be called aaed2000_kbd.
config KEYBOARD_ADP5520
tristate "Keypad Support for ADP5520 PMIC"
depends on PMIC_ADP5520
help
This option enables support for the keypad scan matrix
on Analog Devices ADP5520 PMICs.
To compile this driver as a module, choose M here: the module will
be called adp5520-keys.
config KEYBOARD_ADP5588
tristate "ADP5588 I2C QWERTY Keypad and IO Expander"
depends on I2C
......
......@@ -5,6 +5,7 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o
obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
......
/*
* Keypad driver for Analog Devices ADP5520 MFD PMICs
*
* Copyright 2009 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/mfd/adp5520.h>
struct adp5520_keys {
struct input_dev *input;
struct notifier_block notifier;
struct device *master;
unsigned short keycode[ADP5520_KEYMAPSIZE];
};
static void adp5520_keys_report_event(struct adp5520_keys *dev,
unsigned short keymask, int value)
{
int i;
for (i = 0; i < ADP5520_MAXKEYS; i++)
if (keymask & (1 << i))
input_report_key(dev->input, dev->keycode[i], value);
input_sync(dev->input);
}
static int adp5520_keys_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
struct adp5520_keys *dev;
uint8_t reg_val_lo, reg_val_hi;
unsigned short keymask;
dev = container_of(nb, struct adp5520_keys, notifier);
if (event & ADP5520_KP_INT) {
adp5520_read(dev->master, ADP5520_KP_INT_STAT_1, &reg_val_lo);
adp5520_read(dev->master, ADP5520_KP_INT_STAT_2, &reg_val_hi);
keymask = (reg_val_hi << 8) | reg_val_lo;
/* Read twice to clear */
adp5520_read(dev->master, ADP5520_KP_INT_STAT_1, &reg_val_lo);
adp5520_read(dev->master, ADP5520_KP_INT_STAT_2, &reg_val_hi);
keymask |= (reg_val_hi << 8) | reg_val_lo;
adp5520_keys_report_event(dev, keymask, 1);
}
if (event & ADP5520_KR_INT) {
adp5520_read(dev->master, ADP5520_KR_INT_STAT_1, &reg_val_lo);
adp5520_read(dev->master, ADP5520_KR_INT_STAT_2, &reg_val_hi);
keymask = (reg_val_hi << 8) | reg_val_lo;
/* Read twice to clear */
adp5520_read(dev->master, ADP5520_KR_INT_STAT_1, &reg_val_lo);
adp5520_read(dev->master, ADP5520_KR_INT_STAT_2, &reg_val_hi);
keymask |= (reg_val_hi << 8) | reg_val_lo;
adp5520_keys_report_event(dev, keymask, 0);
}
return 0;
}
static int __devinit adp5520_keys_probe(struct platform_device *pdev)
{
struct adp5520_keys_platform_data *pdata = pdev->dev.platform_data;
struct input_dev *input;
struct adp5520_keys *dev;
int ret, i;
unsigned char en_mask, ctl_mask = 0;
if (pdev->id != ID_ADP5520) {
dev_err(&pdev->dev, "only ADP5520 supports Keypad\n");
return -EINVAL;
}
if (pdata == NULL) {
dev_err(&pdev->dev, "missing platform data\n");
return -EINVAL;
}
if (!(pdata->rows_en_mask && pdata->cols_en_mask))
return -EINVAL;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
dev_err(&pdev->dev, "failed to alloc memory\n");
return -ENOMEM;
}
input = input_allocate_device();
if (!input) {
ret = -ENOMEM;
goto err;
}
dev->master = pdev->dev.parent;
dev->input = input;
input->name = pdev->name;
input->phys = "adp5520-keys/input0";
input->dev.parent = &pdev->dev;
input_set_drvdata(input, dev);
input->id.bustype = BUS_I2C;
input->id.vendor = 0x0001;
input->id.product = 0x5520;
input->id.version = 0x0001;
input->keycodesize = sizeof(dev->keycode[0]);
input->keycodemax = pdata->keymapsize;
input->keycode = dev->keycode;
memcpy(dev->keycode, pdata->keymap,
pdata->keymapsize * input->keycodesize);
/* setup input device */
__set_bit(EV_KEY, input->evbit);
if (pdata->repeat)
__set_bit(EV_REP, input->evbit);
for (i = 0; i < input->keycodemax; i++)
__set_bit(dev->keycode[i], input->keybit);
__clear_bit(KEY_RESERVED, input->keybit);
ret = input_register_device(input);
if (ret) {
dev_err(&pdev->dev, "unable to register input device\n");
goto err;
}
en_mask = pdata->rows_en_mask | pdata->cols_en_mask;
ret = adp5520_set_bits(dev->master, ADP5520_GPIO_CFG_1, en_mask);
if (en_mask & ADP5520_COL_C3)
ctl_mask |= ADP5520_C3_MODE;
if (en_mask & ADP5520_ROW_R3)
ctl_mask |= ADP5520_R3_MODE;
if (ctl_mask)
ret |= adp5520_set_bits(dev->master, ADP5520_LED_CONTROL,
ctl_mask);
ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_PULLUP,
pdata->rows_en_mask);
if (ret) {
dev_err(&pdev->dev, "failed to write\n");
ret = -EIO;
goto err1;
}
dev->notifier.notifier_call = adp5520_keys_notifier;
ret = adp5520_register_notifier(dev->master, &dev->notifier,
ADP5520_KP_IEN | ADP5520_KR_IEN);
if (ret) {
dev_err(&pdev->dev, "failed to register notifier\n");
goto err1;
}
platform_set_drvdata(pdev, dev);
return 0;
err1:
input_unregister_device(input);
input = NULL;
err:
input_free_device(input);
kfree(dev);
return ret;
}
static int __devexit adp5520_keys_remove(struct platform_device *pdev)
{
struct adp5520_keys *dev = platform_get_drvdata(pdev);
adp5520_unregister_notifier(dev->master, &dev->notifier,
ADP5520_KP_IEN | ADP5520_KR_IEN);
input_unregister_device(dev->input);
kfree(dev);
return 0;
}
static struct platform_driver adp5520_keys_driver = {
.driver = {
.name = "adp5520-keys",
.owner = THIS_MODULE,
},
.probe = adp5520_keys_probe,
.remove = __devexit_p(adp5520_keys_remove),
};
static int __init adp5520_keys_init(void)
{
return platform_driver_register(&adp5520_keys_driver);
}
module_init(adp5520_keys_init);
static void __exit adp5520_keys_exit(void)
{
platform_driver_unregister(&adp5520_keys_driver);
}
module_exit(adp5520_keys_exit);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Keys ADP5520 Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:adp5520-keys");
......@@ -31,7 +31,7 @@
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/i2c/twl4030.h>
#include <linux/i2c/twl.h>
/*
......@@ -133,7 +133,7 @@ struct twl4030_keypad {
static int twl4030_kpread(struct twl4030_keypad *kp,
u8 *data, u32 reg, u8 num_bytes)
{
int ret = twl4030_i2c_read(TWL4030_MODULE_KEYPAD, data, reg, num_bytes);
int ret = twl_i2c_read(TWL4030_MODULE_KEYPAD, data, reg, num_bytes);
if (ret < 0)
dev_warn(kp->dbg_dev,
......@@ -145,7 +145,7 @@ static int twl4030_kpread(struct twl4030_keypad *kp,
static int twl4030_kpwrite_u8(struct twl4030_keypad *kp, u8 data, u32 reg)
{
int ret = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, data, reg);
int ret = twl_i2c_write_u8(TWL4030_MODULE_KEYPAD, data, reg);
if (ret < 0)
dev_warn(kp->dbg_dev,
......
......@@ -55,7 +55,6 @@ pcf50633_input_irq(int irq, void *data)
static int __devinit pcf50633_input_probe(struct platform_device *pdev)
{
struct pcf50633_input *input;
struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data;
struct input_dev *input_dev;
int ret;
......@@ -71,7 +70,7 @@ static int __devinit pcf50633_input_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, input);
input->pcf = pdata->pcf;
input->pcf = dev_to_pcf50633(pdev->dev.parent);
input->input_dev = input_dev;
input_dev->name = "PCF50633 PMU events";
......@@ -85,9 +84,9 @@ static int __devinit pcf50633_input_probe(struct platform_device *pdev)
kfree(input);
return ret;
}
pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ONKEYR,
pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYR,
pcf50633_input_irq, input);
pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ONKEYF,
pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYF,
pcf50633_input_irq, input);
return 0;
......
......@@ -27,7 +27,7 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/i2c/twl4030.h>
#include <linux/i2c/twl.h>
#define PWR_PWRON_IRQ (1 << 0)
......@@ -49,7 +49,7 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr)
local_irq_enable();
#endif
err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value,
err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value,
STS_HW_CONDITIONS);
if (!err) {
input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ);
......
/*
* Base driver for Marvell 88PM8607
*
* Copyright (C) 2009 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/88pm8607.h>
#define PM8607_REG_RESOURCE(_start, _end) \
{ \
.start = PM8607_##_start, \
.end = PM8607_##_end, \
.flags = IORESOURCE_IO, \
}
static struct resource pm8607_regulator_resources[] = {
PM8607_REG_RESOURCE(BUCK1, BUCK1),
PM8607_REG_RESOURCE(BUCK2, BUCK2),
PM8607_REG_RESOURCE(BUCK3, BUCK3),
PM8607_REG_RESOURCE(LDO1, LDO1),
PM8607_REG_RESOURCE(LDO2, LDO2),
PM8607_REG_RESOURCE(LDO3, LDO3),
PM8607_REG_RESOURCE(LDO4, LDO4),
PM8607_REG_RESOURCE(LDO5, LDO5),
PM8607_REG_RESOURCE(LDO6, LDO6),
PM8607_REG_RESOURCE(LDO7, LDO7),
PM8607_REG_RESOURCE(LDO8, LDO8),
PM8607_REG_RESOURCE(LDO9, LDO9),
PM8607_REG_RESOURCE(LDO10, LDO10),
PM8607_REG_RESOURCE(LDO12, LDO12),
PM8607_REG_RESOURCE(LDO14, LDO14),
};
#define PM8607_REG_DEVS(_name, _id) \
{ \
.name = "88pm8607-" #_name, \
.num_resources = 1, \
.resources = &pm8607_regulator_resources[PM8607_ID_##_id], \
}
static struct mfd_cell pm8607_devs[] = {
PM8607_REG_DEVS(buck1, BUCK1),
PM8607_REG_DEVS(buck2, BUCK2),
PM8607_REG_DEVS(buck3, BUCK3),
PM8607_REG_DEVS(ldo1, LDO1),
PM8607_REG_DEVS(ldo2, LDO2),
PM8607_REG_DEVS(ldo3, LDO3),
PM8607_REG_DEVS(ldo4, LDO4),
PM8607_REG_DEVS(ldo5, LDO5),
PM8607_REG_DEVS(ldo6, LDO6),
PM8607_REG_DEVS(ldo7, LDO7),
PM8607_REG_DEVS(ldo8, LDO8),
PM8607_REG_DEVS(ldo9, LDO9),
PM8607_REG_DEVS(ldo10, LDO10),
PM8607_REG_DEVS(ldo12, LDO12),
PM8607_REG_DEVS(ldo14, LDO14),
};
static inline int pm8607_read_device(struct pm8607_chip *chip,
int reg, int bytes, void *dest)
{
struct i2c_client *i2c = chip->client;
unsigned char data;
int ret;
data = (unsigned char)reg;
ret = i2c_master_send(i2c, &data, 1);
if (ret < 0)
return ret;
ret = i2c_master_recv(i2c, dest, bytes);
if (ret < 0)
return ret;
return 0;
}
static inline int pm8607_write_device(struct pm8607_chip *chip,
int reg, int bytes, void *src)
{
struct i2c_client *i2c = chip->client;
unsigned char buf[bytes + 1];
int ret;
buf[0] = (unsigned char)reg;
memcpy(&buf[1], src, bytes);
ret = i2c_master_send(i2c, buf, bytes + 1);
if (ret < 0)
return ret;
return 0;
}
int pm8607_reg_read(struct pm8607_chip *chip, int reg)
{
unsigned char data;
int ret;
mutex_lock(&chip->io_lock);
ret = chip->read(chip, reg, 1, &data);
mutex_unlock(&chip->io_lock);
if (ret < 0)
return ret;
else
return (int)data;
}
EXPORT_SYMBOL(pm8607_reg_read);
int pm8607_reg_write(struct pm8607_chip *chip, int reg,
unsigned char data)
{
int ret;
mutex_lock(&chip->io_lock);
ret = chip->write(chip, reg, 1, &data);
mutex_unlock(&chip->io_lock);
return ret;
}
EXPORT_SYMBOL(pm8607_reg_write);
int pm8607_bulk_read(struct pm8607_chip *chip, int reg,
int count, unsigned char *buf)
{
int ret;
mutex_lock(&chip->io_lock);
ret = chip->read(chip, reg, count, buf);
mutex_unlock(&chip->io_lock);
return ret;
}
EXPORT_SYMBOL(pm8607_bulk_read);
int pm8607_bulk_write(struct pm8607_chip *chip, int reg,
int count, unsigned char *buf)
{
int ret;
mutex_lock(&chip->io_lock);
ret = chip->write(chip, reg, count, buf);
mutex_unlock(&chip->io_lock);
return ret;
}
EXPORT_SYMBOL(pm8607_bulk_write);
int pm8607_set_bits(struct pm8607_chip *chip, int reg,
unsigned char mask, unsigned char data)
{
unsigned char value;
int ret;
mutex_lock(&chip->io_lock);
ret = chip->read(chip, reg, 1, &value);
if (ret < 0)
goto out;
value &= ~mask;
value |= data;
ret = chip->write(chip, reg, 1, &value);
out:
mutex_unlock(&chip->io_lock);
return ret;
}
EXPORT_SYMBOL(pm8607_set_bits);
static const struct i2c_device_id pm8607_id_table[] = {
{ "88PM8607", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, pm8607_id_table);
static int __devinit pm8607_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pm8607_platform_data *pdata = client->dev.platform_data;
struct pm8607_chip *chip;
int i, count;
int ret;
chip = kzalloc(sizeof(struct pm8607_chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
chip->client = client;
chip->dev = &client->dev;
chip->read = pm8607_read_device;
chip->write = pm8607_write_device;
i2c_set_clientdata(client, chip);
mutex_init(&chip->io_lock);
dev_set_drvdata(chip->dev, chip);
ret = pm8607_reg_read(chip, PM8607_CHIP_ID);
if (ret < 0) {
dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
goto out;
}
if ((ret & CHIP_ID_MASK) == CHIP_ID)
dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n",
ret);
else {
dev_err(chip->dev, "Failed to detect Marvell 88PM8607. "
"Chip ID: %02x\n", ret);
goto out;
}
chip->chip_id = ret;
ret = pm8607_reg_read(chip, PM8607_BUCK3);
if (ret < 0) {
dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret);
goto out;
}
if (ret & PM8607_BUCK3_DOUBLE)
chip->buck3_double = 1;
ret = pm8607_reg_read(chip, PM8607_MISC1);
if (ret < 0) {
dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);
goto out;
}
if (pdata->i2c_port == PI2C_PORT)
ret |= PM8607_MISC1_PI2C;
else
ret &= ~PM8607_MISC1_PI2C;
ret = pm8607_reg_write(chip, PM8607_MISC1, ret);
if (ret < 0) {
dev_err(chip->dev, "Failed to write MISC1 register: %d\n", ret);
goto out;
}
count = ARRAY_SIZE(pm8607_devs);
for (i = 0; i < count; i++) {
ret = mfd_add_devices(chip->dev, i, &pm8607_devs[i],
1, NULL, 0);
if (ret != 0) {
dev_err(chip->dev, "Failed to add subdevs\n");
goto out;
}
}
return 0;
out:
i2c_set_clientdata(client, NULL);
kfree(chip);
return ret;
}
static int __devexit pm8607_remove(struct i2c_client *client)
{
struct pm8607_chip *chip = i2c_get_clientdata(client);
mfd_remove_devices(chip->dev);
kfree(chip);
return 0;
}
static struct i2c_driver pm8607_driver = {
.driver = {
.name = "88PM8607",
.owner = THIS_MODULE,
},
.probe = pm8607_probe,
.remove = __devexit_p(pm8607_remove),
.id_table = pm8607_id_table,
};
static int __init pm8607_init(void)
{
int ret;
ret = i2c_add_driver(&pm8607_driver);
if (ret != 0)
pr_err("Failed to register 88PM8607 I2C driver: %d\n", ret);
return ret;
}
subsys_initcall(pm8607_init);
static void __exit pm8607_exit(void)
{
i2c_del_driver(&pm8607_driver);
}
module_exit(pm8607_exit);
MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM8607");
MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
MODULE_LICENSE("GPL");
......@@ -103,10 +103,10 @@ config MENELAUS
cell phones and PDAs.
config TWL4030_CORE
bool "Texas Instruments TWL4030/TPS659x0 Support"
bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support"
depends on I2C=y && GENERIC_HARDIRQS
help
Say yes here if you have TWL4030 family chip on your board.
Say yes here if you have TWL4030 / TWL6030 family chip on your board.
This core driver provides register access and IRQ handling
facilities, and registers devices for the various functions
so that function-specific drivers can bind to them.
......@@ -174,6 +174,16 @@ config PMIC_DA903X
individual components like LCD backlight, voltage regulators,
LEDs and battery-charger under the corresponding menus.
config PMIC_ADP5520
bool "Analog Devices ADP5520/01 MFD PMIC Core Support"
depends on I2C=y
help
Say yes here to add support for Analog Devices AD5520 and ADP5501,
Multifunction Power Management IC. This includes
the I2C driver and the core APIs _only_, you have to select
individual components like LCD backlight, LEDs, GPIOs and Kepad
under the corresponding menus.
config MFD_WM8400
tristate "Support Wolfson Microelectronics WM8400"
select MFD_CORE
......@@ -185,12 +195,12 @@ config MFD_WM8400
the functionality of the device.
config MFD_WM831X
tristate "Support Wolfson Microelectronics WM831x PMICs"
bool "Support Wolfson Microelectronics WM831x/2x PMICs"
select MFD_CORE
depends on I2C
depends on I2C=y
help
Support for the Wolfson Microelecronics WM831x PMICs. This
driver provides common support for accessing the device,
Support for the Wolfson Microelecronics WM831x and WM832x PMICs.
This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the
functionality of the device.
......@@ -319,6 +329,25 @@ config EZX_PCAP
This enables the PCAP ASIC present on EZX Phones. This is
needed for MMC, TouchScreen, Sound, USB, etc..
config MFD_88PM8607
bool "Support Marvell 88PM8607"
depends on I2C=y
select MFD_CORE
help
This supports for Marvell 88PM8607 Power Management IC. This includes
the I2C driver and the core APIs _only_, you have to select
individual components like voltage regulators, RTC and
battery-charger under the corresponding menus.
config AB4500_CORE
tristate "ST-Ericsson's AB4500 Mixed Signal Power management chip"
depends on SPI
help
Select this option to enable access to AB4500 power management
chip. This connects to U8500 on the SSP/SPI bus and exports
read/write functions for the devices to get access to this chip.
This chip embeds various other multimedia funtionalities as well.
endmenu
menu "Multimedia Capabilities Port drivers"
......
......@@ -19,13 +19,14 @@ obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o
obj-$(CONFIG_MFD_WM831X) += wm831x.o
wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
wm8350-objs += wm8350-irq.o
obj-$(CONFIG_MFD_WM8350) += wm8350.o
obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
obj-$(CONFIG_TPS65010) += tps65010.o
obj-$(CONFIG_MENELAUS) += menelaus.o
obj-$(CONFIG_TWL4030_CORE) += twl4030-core.o twl4030-irq.o
obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o
obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o
......@@ -52,3 +53,6 @@ obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o
obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
obj-$(CONFIG_AB4500_CORE) += ab4500-core.o
obj-$(CONFIG_MFD_88PM8607) += 88pm8607.o
obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
\ No newline at end of file
......@@ -900,9 +900,6 @@ static int __init ab3100_probe(struct i2c_client *client,
goto exit_no_testreg_client;
}
strlcpy(ab3100->testreg_client->name, id->name,
sizeof(ab3100->testreg_client->name));
err = ab3100_setup(ab3100);
if (err)
goto exit_no_setup;
......
/*
* Copyright (C) 2009 ST-Ericsson
*
* Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation.
*
* AB4500 is a companion power management chip used with U8500.
* On this platform, this is interfaced with SSP0 controller
* which is a ARM primecell pl022.
*
* At the moment the module just exports read/write features.
* Interrupt management to be added - TODO.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/mfd/ab4500.h>
/* just required if probe fails, we need to
* unregister the device
*/
static struct spi_driver ab4500_driver;
/*
* This funtion writes to any AB4500 registers using
* SPI protocol & before it writes it packs the data
* in the below 24 bit frame format
*
* *|------------------------------------|
* *| 23|22...18|17.......10|9|8|7......0|
* *| r/w bank adr data |
* * ------------------------------------
*
* This function shouldn't be called from interrupt
* context
*/
int ab4500_write(struct ab4500 *ab4500, unsigned char block,
unsigned long addr, unsigned char data)
{
struct spi_transfer xfer;
struct spi_message msg;
int err;
unsigned long spi_data =
block << 18 | addr << 10 | data;
mutex_lock(&ab4500->lock);
ab4500->tx_buf[0] = spi_data;
ab4500->rx_buf[0] = 0;
xfer.tx_buf = ab4500->tx_buf;
xfer.rx_buf = NULL;
xfer.len = sizeof(unsigned long);
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
err = spi_sync(ab4500->spi, &msg);
mutex_unlock(&ab4500->lock);
return err;
}
EXPORT_SYMBOL(ab4500_write);
int ab4500_read(struct ab4500 *ab4500, unsigned char block,
unsigned long addr)
{
struct spi_transfer xfer;
struct spi_message msg;
unsigned long spi_data =
1 << 23 | block << 18 | addr << 10;
mutex_lock(&ab4500->lock);
ab4500->tx_buf[0] = spi_data;
ab4500->rx_buf[0] = 0;
xfer.tx_buf = ab4500->tx_buf;
xfer.rx_buf = ab4500->rx_buf;
xfer.len = sizeof(unsigned long);
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
spi_sync(ab4500->spi, &msg);
mutex_unlock(&ab4500->lock);
return ab4500->rx_buf[0];
}
EXPORT_SYMBOL(ab4500_read);
/* ref: ab3100 core */
#define AB4500_DEVICE(devname, devid) \
static struct platform_device ab4500_##devname##_device = { \
.name = devid, \
.id = -1, \
}
/* list of childern devices of ab4500 - all are
* not populated here - TODO
*/
AB4500_DEVICE(charger, "ab4500-charger");
AB4500_DEVICE(audio, "ab4500-audio");
AB4500_DEVICE(usb, "ab4500-usb");
AB4500_DEVICE(tvout, "ab4500-tvout");
AB4500_DEVICE(sim, "ab4500-sim");
AB4500_DEVICE(gpadc, "ab4500-gpadc");
AB4500_DEVICE(clkmgt, "ab4500-clkmgt");
AB4500_DEVICE(misc, "ab4500-misc");
static struct platform_device *ab4500_platform_devs[] = {
&ab4500_charger_device,
&ab4500_audio_device,
&ab4500_usb_device,
&ab4500_tvout_device,
&ab4500_sim_device,
&ab4500_gpadc_device,
&ab4500_clkmgt_device,
&ab4500_misc_device,
};
static int __init ab4500_probe(struct spi_device *spi)
{
struct ab4500 *ab4500;
unsigned char revision;
int err = 0;
int i;
ab4500 = kzalloc(sizeof *ab4500, GFP_KERNEL);
if (!ab4500) {
dev_err(&spi->dev, "could not allocate AB4500\n");
err = -ENOMEM;
goto not_detect;
}
ab4500->spi = spi;
spi_set_drvdata(spi, ab4500);
mutex_init(&ab4500->lock);
/* read the revision register */
revision = ab4500_read(ab4500, AB4500_MISC, AB4500_REV_REG);
/* revision id 0x0 is for early drop, 0x10 is for cut1.0 */
if (revision == 0x0 || revision == 0x10)
dev_info(&spi->dev, "Detected chip: %s, revision = %x\n",
ab4500_driver.driver.name, revision);
else {
dev_err(&spi->dev, "unknown chip: 0x%x\n", revision);
goto not_detect;
}
for (i = 0; i < ARRAY_SIZE(ab4500_platform_devs); i++) {
ab4500_platform_devs[i]->dev.parent =
&spi->dev;
platform_set_drvdata(ab4500_platform_devs[i], ab4500);
}
/* register the ab4500 platform devices */
platform_add_devices(ab4500_platform_devs,
ARRAY_SIZE(ab4500_platform_devs));
return err;
not_detect:
spi_unregister_driver(&ab4500_driver);
kfree(ab4500);
return err;
}
static int __devexit ab4500_remove(struct spi_device *spi)
{
struct ab4500 *ab4500 =
spi_get_drvdata(spi);
kfree(ab4500);
return 0;
}
static struct spi_driver ab4500_driver = {
.driver = {
.name = "ab4500",
.owner = THIS_MODULE,
},
.probe = ab4500_probe,
.remove = __devexit_p(ab4500_remove)
};
static int __devinit ab4500_init(void)
{
return spi_register_driver(&ab4500_driver);
}
static void __exit ab4500_exit(void)
{
spi_unregister_driver(&ab4500_driver);
}
subsys_initcall(ab4500_init);
module_exit(ab4500_exit);
MODULE_AUTHOR("Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com");
MODULE_DESCRIPTION("AB4500 core driver");
MODULE_LICENSE("GPL");
/*
* Base driver for Analog Devices ADP5520/ADP5501 MFD PMICs
* LCD Backlight: drivers/video/backlight/adp5520_bl
* LEDs : drivers/led/leds-adp5520
* GPIO : drivers/gpio/adp5520-gpio (ADP5520 only)
* Keys : drivers/input/keyboard/adp5520-keys (ADP5520 only)
*
* Copyright 2009 Analog Devices Inc.
*
* Derived from da903x:
* Copyright (C) 2008 Compulab, Ltd.
* Mike Rapoport <mike@compulab.co.il>
*
* Copyright (C) 2006-2008 Marvell International Ltd.
* Eric Miao <eric.miao@marvell.com>
*
* Licensed under the GPL-2 or later.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/mfd/adp5520.h>
struct adp5520_chip {
struct i2c_client *client;
struct device *dev;
struct mutex lock;
struct blocking_notifier_head notifier_list;
int irq;
unsigned long id;
};
static int __adp5520_read(struct i2c_client *client,
int reg, uint8_t *val)
{
int ret;
ret = i2c_smbus_read_byte_data(client, reg);
if (ret < 0) {
dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
return ret;
}
*val = (uint8_t)ret;
return 0;
}
static int __adp5520_write(struct i2c_client *client,
int reg, uint8_t val)
{
int ret;
ret = i2c_smbus_write_byte_data(client, reg, val);
if (ret < 0) {
dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n",
val, reg);
return ret;
}
return 0;
}
static int __adp5520_ack_bits(struct i2c_client *client, int reg,
uint8_t bit_mask)
{
struct adp5520_chip *chip = i2c_get_clientdata(client);
uint8_t reg_val;
int ret;
mutex_lock(&chip->lock);
ret = __adp5520_read(client, reg, &reg_val);
if (!ret) {
reg_val |= bit_mask;
ret = __adp5520_write(client, reg, reg_val);
}
mutex_unlock(&chip->lock);
return ret;
}
int adp5520_write(struct device *dev, int reg, uint8_t val)
{
return __adp5520_write(to_i2c_client(dev), reg, val);
}
EXPORT_SYMBOL_GPL(adp5520_write);
int adp5520_read(struct device *dev, int reg, uint8_t *val)
{
return __adp5520_read(to_i2c_client(dev), reg, val);
}
EXPORT_SYMBOL_GPL(adp5520_read);
int adp5520_set_bits(struct device *dev, int reg, uint8_t bit_mask)
{
struct adp5520_chip *chip = dev_get_drvdata(dev);
uint8_t reg_val;
int ret;
mutex_lock(&chip->lock);
ret = __adp5520_read(chip->client, reg, &reg_val);
if (!ret && ((reg_val & bit_mask) == 0)) {
reg_val |= bit_mask;
ret = __adp5520_write(chip->client, reg, reg_val);
}
mutex_unlock(&chip->lock);
return ret;
}
EXPORT_SYMBOL_GPL(adp5520_set_bits);
int adp5520_clr_bits(struct device *dev, int reg, uint8_t bit_mask)
{
struct adp5520_chip *chip = dev_get_drvdata(dev);
uint8_t reg_val;
int ret;
mutex_lock(&chip->lock);
ret = __adp5520_read(chip->client, reg, &reg_val);
if (!ret && (reg_val & bit_mask)) {
reg_val &= ~bit_mask;
ret = __adp5520_write(chip->client, reg, reg_val);
}
mutex_unlock(&chip->lock);
return ret;
}
EXPORT_SYMBOL_GPL(adp5520_clr_bits);
int adp5520_register_notifier(struct device *dev, struct notifier_block *nb,
unsigned int events)
{
struct adp5520_chip *chip = dev_get_drvdata(dev);
if (chip->irq) {
adp5520_set_bits(chip->dev, ADP5520_INTERRUPT_ENABLE,
events & (ADP5520_KP_IEN | ADP5520_KR_IEN |
ADP5520_OVP_IEN | ADP5520_CMPR_IEN));
return blocking_notifier_chain_register(&chip->notifier_list,
nb);
}
return -ENODEV;
}
EXPORT_SYMBOL_GPL(adp5520_register_notifier);
int adp5520_unregister_notifier(struct device *dev, struct notifier_block *nb,
unsigned int events)
{
struct adp5520_chip *chip = dev_get_drvdata(dev);
adp5520_clr_bits(chip->dev, ADP5520_INTERRUPT_ENABLE,
events & (ADP5520_KP_IEN | ADP5520_KR_IEN |
ADP5520_OVP_IEN | ADP5520_CMPR_IEN));
return blocking_notifier_chain_unregister(&chip->notifier_list, nb);
}
EXPORT_SYMBOL_GPL(adp5520_unregister_notifier);
static irqreturn_t adp5520_irq_thread(int irq, void *data)
{
struct adp5520_chip *chip = data;
unsigned int events;
uint8_t reg_val;
int ret;
ret = __adp5520_read(chip->client, ADP5520_MODE_STATUS, &reg_val);
if (ret)
goto out;
events = reg_val & (ADP5520_OVP_INT | ADP5520_CMPR_INT |
ADP5520_GPI_INT | ADP5520_KR_INT | ADP5520_KP_INT);
blocking_notifier_call_chain(&chip->notifier_list, events, NULL);
/* ACK, Sticky bits are W1C */
__adp5520_ack_bits(chip->client, ADP5520_MODE_STATUS, events);
out:
return IRQ_HANDLED;
}
static int __remove_subdev(struct device *dev, void *unused)
{
platform_device_unregister(to_platform_device(dev));
return 0;
}
static int adp5520_remove_subdevs(struct adp5520_chip *chip)
{
return device_for_each_child(chip->dev, NULL, __remove_subdev);
}
static int __devinit adp5520_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct adp5520_platform_data *pdata = client->dev.platform_data;
struct platform_device *pdev;
struct adp5520_chip *chip;
int ret;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&client->dev, "SMBUS Word Data not Supported\n");
return -EIO;
}
if (pdata == NULL) {
dev_err(&client->dev, "missing platform data\n");
return -ENODEV;
}
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
i2c_set_clientdata(client, chip);
chip->client = client;
chip->dev = &client->dev;
chip->irq = client->irq;
chip->id = id->driver_data;
mutex_init(&chip->lock);
if (chip->irq) {
BLOCKING_INIT_NOTIFIER_HEAD(&chip->notifier_list);
ret = request_threaded_irq(chip->irq, NULL, adp5520_irq_thread,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"adp5520", chip);
if (ret) {
dev_err(&client->dev, "failed to request irq %d\n",
chip->irq);
goto out_free_chip;
}
}
ret = adp5520_write(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY);
if (ret) {
dev_err(&client->dev, "failed to write\n");
goto out_free_irq;
}
if (pdata->keys) {
pdev = platform_device_register_data(chip->dev, "adp5520-keys",
chip->id, pdata->keys, sizeof(*pdata->keys));
if (IS_ERR(pdev)) {
ret = PTR_ERR(pdev);
goto out_remove_subdevs;
}
}
if (pdata->gpio) {
pdev = platform_device_register_data(chip->dev, "adp5520-gpio",
chip->id, pdata->gpio, sizeof(*pdata->gpio));
if (IS_ERR(pdev)) {
ret = PTR_ERR(pdev);
goto out_remove_subdevs;
}
}
if (pdata->leds) {
pdev = platform_device_register_data(chip->dev, "adp5520-led",
chip->id, pdata->leds, sizeof(*pdata->leds));
if (IS_ERR(pdev)) {
ret = PTR_ERR(pdev);
goto out_remove_subdevs;
}
}
if (pdata->backlight) {
pdev = platform_device_register_data(chip->dev,
"adp5520-backlight",
chip->id,
pdata->backlight,
sizeof(*pdata->backlight));
if (IS_ERR(pdev)) {
ret = PTR_ERR(pdev);
goto out_remove_subdevs;
}
}
return 0;
out_remove_subdevs:
adp5520_remove_subdevs(chip);
out_free_irq:
if (chip->irq)
free_irq(chip->irq, chip);
out_free_chip:
i2c_set_clientdata(client, NULL);
kfree(chip);
return ret;
}
static int __devexit adp5520_remove(struct i2c_client *client)
{
struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
if (chip->irq)
free_irq(chip->irq, chip);
adp5520_remove_subdevs(chip);
adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0);
i2c_set_clientdata(client, NULL);
kfree(chip);
return 0;
}
#ifdef CONFIG_PM
static int adp5520_suspend(struct i2c_client *client,
pm_message_t state)
{
struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY);
return 0;
}
static int adp5520_resume(struct i2c_client *client)
{
struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY);
return 0;
}
#else
#define adp5520_suspend NULL
#define adp5520_resume NULL
#endif
static const struct i2c_device_id adp5520_id[] = {
{ "pmic-adp5520", ID_ADP5520 },
{ "pmic-adp5501", ID_ADP5501 },
{ }
};
MODULE_DEVICE_TABLE(i2c, adp5520_id);
static struct i2c_driver adp5520_driver = {
.driver = {
.name = "adp5520",
.owner = THIS_MODULE,
},
.probe = adp5520_probe,
.remove = __devexit_p(adp5520_remove),
.suspend = adp5520_suspend,
.resume = adp5520_resume,
.id_table = adp5520_id,
};
static int __init adp5520_init(void)
{
return i2c_add_driver(&adp5520_driver);
}
module_init(adp5520_init);
static void __exit adp5520_exit(void)
{
i2c_del_driver(&adp5520_driver);
}
module_exit(adp5520_exit);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("ADP5520(01) PMIC-MFD Driver");
MODULE_LICENSE("GPL");
......@@ -908,7 +908,7 @@ static int __init asic3_probe(struct platform_device *pdev)
return ret;
}
static int asic3_remove(struct platform_device *pdev)
static int __devexit asic3_remove(struct platform_device *pdev)
{
int ret;
struct asic3 *asic = platform_get_drvdata(pdev);
......
......@@ -387,7 +387,6 @@ static int __devinit pcap_add_subdev(struct pcap_chip *pcap,
pdev = platform_device_alloc(subdev->name, subdev->id);
pdev->dev.parent = &pcap->spi->dev;
pdev->dev.platform_data = subdev->platform_data;
platform_set_drvdata(pdev, pcap);
return platform_device_add(pdev);
}
......
This diff is collapsed.
......@@ -209,17 +209,16 @@ static void pcf50633_adc_irq(int irq, void *data)
static int __devinit pcf50633_adc_probe(struct platform_device *pdev)
{
struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data;
struct pcf50633_adc *adc;
adc = kzalloc(sizeof(*adc), GFP_KERNEL);
if (!adc)
return -ENOMEM;
adc->pcf = pdata->pcf;
adc->pcf = dev_to_pcf50633(pdev->dev.parent);
platform_set_drvdata(pdev, adc);
pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ADCRDY,
pcf50633_register_irq(adc->pcf, PCF50633_IRQ_ADCRDY,
pcf50633_adc_irq, adc);
mutex_init(&adc->queue_mutex);
......
......@@ -290,7 +290,7 @@ static int __pcf50633_irq_mask_set(struct pcf50633 *pcf, int irq, u8 mask)
int pcf50633_irq_mask(struct pcf50633 *pcf, int irq)
{
dev_info(pcf->dev, "Masking IRQ %d\n", irq);
dev_dbg(pcf->dev, "Masking IRQ %d\n", irq);
return __pcf50633_irq_mask_set(pcf, irq, 1);
}
......@@ -298,7 +298,7 @@ EXPORT_SYMBOL_GPL(pcf50633_irq_mask);
int pcf50633_irq_unmask(struct pcf50633 *pcf, int irq)
{
dev_info(pcf->dev, "Unmasking IRQ %d\n", irq);
dev_dbg(pcf->dev, "Unmasking IRQ %d\n", irq);
return __pcf50633_irq_mask_set(pcf, irq, 0);
}
......@@ -345,6 +345,9 @@ static void pcf50633_irq_worker(struct work_struct *work)
goto out;
}
/* defeat 8s death from lowsys on A5 */
pcf50633_reg_write(pcf, PCF50633_REG_OOCSHDWN, 0x04);
/* We immediately read the usb and adapter status. We thus make sure
* only of USBINS/USBREM IRQ handlers are called */
if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) {
......@@ -453,7 +456,6 @@ static void
pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
struct platform_device **pdev)
{
struct pcf50633_subdev_pdata *subdev_pdata;
int ret;
*pdev = platform_device_alloc(name, -1);
......@@ -462,15 +464,6 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
return;
}
subdev_pdata = kmalloc(sizeof(*subdev_pdata), GFP_KERNEL);
if (!subdev_pdata) {
dev_err(pcf->dev, "Error allocating subdev pdata\n");
platform_device_put(*pdev);
}
subdev_pdata->pcf = pcf;
platform_device_add_data(*pdev, subdev_pdata, sizeof(*subdev_pdata));
(*pdev)->dev.parent = pcf->dev;
ret = platform_device_add(*pdev);
......@@ -482,13 +475,13 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
}
#ifdef CONFIG_PM
static int pcf50633_suspend(struct device *dev, pm_message_t state)
static int pcf50633_suspend(struct i2c_client *client, pm_message_t state)
{
struct pcf50633 *pcf;
int ret = 0, i;
u8 res[5];
pcf = dev_get_drvdata(dev);
pcf = i2c_get_clientdata(client);
/* Make sure our interrupt handlers are not called
* henceforth */
......@@ -523,12 +516,12 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state)
return ret;
}
static int pcf50633_resume(struct device *dev)
static int pcf50633_resume(struct i2c_client *client)
{
struct pcf50633 *pcf;
int ret;
pcf = dev_get_drvdata(dev);
pcf = i2c_get_clientdata(client);
/* Write the saved mask registers */
ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,
......@@ -560,9 +553,14 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
{
struct pcf50633 *pcf;
struct pcf50633_platform_data *pdata = client->dev.platform_data;
int i, ret = 0;
int i, ret;
int version, variant;
if (!client->irq) {
dev_err(&client->dev, "Missing IRQ\n");
return -ENOENT;
}
pcf = kzalloc(sizeof(*pcf), GFP_KERNEL);
if (!pcf)
return -ENOMEM;
......@@ -577,6 +575,12 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
pcf->irq = client->irq;
pcf->work_queue = create_singlethread_workqueue("pcf50633");
if (!pcf->work_queue) {
dev_err(&client->dev, "Failed to alloc workqueue\n");
ret = -ENOMEM;
goto err_free;
}
INIT_WORK(&pcf->irq_work, pcf50633_irq_worker);
version = pcf50633_reg_read(pcf, 0);
......@@ -584,7 +588,7 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
if (version < 0 || variant < 0) {
dev_err(pcf->dev, "Unable to probe pcf50633\n");
ret = -ENODEV;
goto err;
goto err_destroy_workqueue;
}
dev_info(pcf->dev, "Probed device version %d variant %d\n",
......@@ -598,6 +602,14 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
pcf50633_reg_write(pcf, PCF50633_REG_INT4M, 0x00);
pcf50633_reg_write(pcf, PCF50633_REG_INT5M, 0x00);
ret = request_irq(client->irq, pcf50633_irq,
IRQF_TRIGGER_LOW, "pcf50633", pcf);
if (ret) {
dev_err(pcf->dev, "Failed to request IRQ %d\n", ret);
goto err_destroy_workqueue;
}
/* Create sub devices */
pcf50633_client_dev_register(pcf, "pcf50633-input",
&pcf->input_pdev);
......@@ -613,31 +625,18 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
pdev = platform_device_alloc("pcf50633-regltr", i);
if (!pdev) {
dev_err(pcf->dev, "Cannot create regulator\n");
dev_err(pcf->dev, "Cannot create regulator %d\n", i);
continue;
}
pdev->dev.parent = pcf->dev;
pdev->dev.platform_data = &pdata->reg_init_data[i];
dev_set_drvdata(&pdev->dev, pcf);
platform_device_add_data(pdev, &pdata->reg_init_data[i],
sizeof(pdata->reg_init_data[i]));
pcf->regulator_pdev[i] = pdev;
platform_device_add(pdev);
}
if (client->irq) {
ret = request_irq(client->irq, pcf50633_irq,
IRQF_TRIGGER_LOW, "pcf50633", pcf);
if (ret) {
dev_err(pcf->dev, "Failed to request IRQ %d\n", ret);
goto err;
}
} else {
dev_err(pcf->dev, "No IRQ configured\n");
goto err;
}
if (enable_irq_wake(client->irq) < 0)
dev_err(pcf->dev, "IRQ %u cannot be enabled as wake-up source"
"in this hardware revision", client->irq);
......@@ -651,9 +650,12 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
return 0;
err:
err_destroy_workqueue:
destroy_workqueue(pcf->work_queue);
err_free:
i2c_set_clientdata(client, NULL);
kfree(pcf);
return ret;
}
......@@ -686,12 +688,12 @@ static struct i2c_device_id pcf50633_id_table[] = {
static struct i2c_driver pcf50633_driver = {
.driver = {
.name = "pcf50633",
.suspend = pcf50633_suspend,
.resume = pcf50633_resume,
},
.id_table = pcf50633_id_table,
.probe = pcf50633_probe,
.remove = __devexit_p(pcf50633_remove),
.suspend = pcf50633_suspend,
.resume = pcf50633_resume,
};
static int __init pcf50633_init(void)
......
......@@ -637,7 +637,7 @@ static int tps65010_probe(struct i2c_client *client,
tps, DEBUG_FOPS);
/* optionally register GPIOs */
if (board && board->base > 0) {
if (board && board->base != 0) {
tps->outmask = board->outmask;
tps->chip.label = client->name;
......@@ -964,6 +964,34 @@ int tps65010_config_vregs1(unsigned value)
}
EXPORT_SYMBOL(tps65010_config_vregs1);
int tps65010_config_vdcdc2(unsigned value)
{
struct i2c_client *c;
int status;
if (!the_tps)
return -ENODEV;
c = the_tps->client;
mutex_lock(&the_tps->lock);
pr_debug("%s: vdcdc2 0x%02x\n", DRIVER_NAME,
i2c_smbus_read_byte_data(c, TPS_VDCDC2));
status = i2c_smbus_write_byte_data(c, TPS_VDCDC2, value);
if (status != 0)
printk(KERN_ERR "%s: Failed to write vdcdc2 register\n",
DRIVER_NAME);
else
pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
i2c_smbus_read_byte_data(c, TPS_VDCDC2));
mutex_unlock(&the_tps->lock);
return status;
}
EXPORT_SYMBOL(tps65010_config_vdcdc2);
/*-------------------------------------------------------------------------*/
/* tps65013_set_low_pwr parameter:
* mode: ON or OFF
......
......@@ -32,7 +32,7 @@
#include <linux/irq.h>
#include <linux/kthread.h>
#include <linux/i2c/twl4030.h>
#include <linux/i2c/twl.h>
/*
......@@ -74,6 +74,8 @@ struct sih {
u8 edr_offset;
u8 bytes_edr; /* bytelen of EDR */
u8 irq_lines; /* number of supported irq lines */
/* SIR ignored -- set interrupt, for testing only */
struct irq_data {
u8 isr_offset;
......@@ -82,6 +84,9 @@ struct sih {
/* + 2 bytes padding */
};
static const struct sih *sih_modules;
static int nr_sih_modules;
#define SIH_INITIALIZER(modname, nbits) \
.module = TWL4030_MODULE_ ## modname, \
.control_offset = TWL4030_ ## modname ## _SIH_CTRL, \
......@@ -89,6 +94,7 @@ struct sih {
.bytes_ixr = DIV_ROUND_UP(nbits, 8), \
.edr_offset = TWL4030_ ## modname ## _EDR, \
.bytes_edr = DIV_ROUND_UP((2*(nbits)), 8), \
.irq_lines = 2, \
.mask = { { \
.isr_offset = TWL4030_ ## modname ## _ISR1, \
.imr_offset = TWL4030_ ## modname ## _IMR1, \
......@@ -107,7 +113,8 @@ struct sih {
/* Order in this table matches order in PIH_ISR. That is,
* BIT(n) in PIH_ISR is sih_modules[n].
*/
static const struct sih sih_modules[6] = {
/* sih_modules_twl4030 is used both in twl4030 and twl5030 */
static const struct sih sih_modules_twl4030[6] = {
[0] = {
.name = "gpio",
.module = TWL4030_MODULE_GPIO,
......@@ -118,6 +125,7 @@ static const struct sih sih_modules[6] = {
/* Note: *all* of these IRQs default to no-trigger */
.edr_offset = REG_GPIO_EDR1,
.bytes_edr = 5,
.irq_lines = 2,
.mask = { {
.isr_offset = REG_GPIO_ISR1A,
.imr_offset = REG_GPIO_IMR1A,
......@@ -140,6 +148,7 @@ static const struct sih sih_modules[6] = {
.edr_offset = TWL4030_INTERRUPTS_BCIEDR1,
/* Note: most of these IRQs default to no-trigger */
.bytes_edr = 3,
.irq_lines = 2,
.mask = { {
.isr_offset = TWL4030_INTERRUPTS_BCIISR1A,
.imr_offset = TWL4030_INTERRUPTS_BCIIMR1A,
......@@ -164,6 +173,99 @@ static const struct sih sih_modules[6] = {
/* there are no SIH modules #6 or #7 ... */
};
static const struct sih sih_modules_twl5031[8] = {
[0] = {
.name = "gpio",
.module = TWL4030_MODULE_GPIO,
.control_offset = REG_GPIO_SIH_CTRL,
.set_cor = true,
.bits = TWL4030_GPIO_MAX,
.bytes_ixr = 3,
/* Note: *all* of these IRQs default to no-trigger */
.edr_offset = REG_GPIO_EDR1,
.bytes_edr = 5,
.irq_lines = 2,
.mask = { {
.isr_offset = REG_GPIO_ISR1A,
.imr_offset = REG_GPIO_IMR1A,
}, {
.isr_offset = REG_GPIO_ISR1B,
.imr_offset = REG_GPIO_IMR1B,
}, },
},
[1] = {
.name = "keypad",
.set_cor = true,
SIH_INITIALIZER(KEYPAD_KEYP, 4)
},
[2] = {
.name = "bci",
.module = TWL5031_MODULE_INTERRUPTS,
.control_offset = TWL5031_INTERRUPTS_BCISIHCTRL,
.bits = 7,
.bytes_ixr = 1,
.edr_offset = TWL5031_INTERRUPTS_BCIEDR1,
/* Note: most of these IRQs default to no-trigger */
.bytes_edr = 2,
.irq_lines = 2,
.mask = { {
.isr_offset = TWL5031_INTERRUPTS_BCIISR1,
.imr_offset = TWL5031_INTERRUPTS_BCIIMR1,
}, {
.isr_offset = TWL5031_INTERRUPTS_BCIISR2,
.imr_offset = TWL5031_INTERRUPTS_BCIIMR2,
}, },
},
[3] = {
.name = "madc",
SIH_INITIALIZER(MADC, 4)
},
[4] = {
/* USB doesn't use the same SIH organization */
.name = "usb",
},
[5] = {
.name = "power",
.set_cor = true,
SIH_INITIALIZER(INT_PWR, 8)
},
[6] = {
/*
* ACI doesn't use the same SIH organization.
* For example, it supports only one interrupt line
*/
.name = "aci",
.module = TWL5031_MODULE_ACCESSORY,
.bits = 9,
.bytes_ixr = 2,
.irq_lines = 1,
.mask = { {
.isr_offset = TWL5031_ACIIDR_LSB,
.imr_offset = TWL5031_ACIIMR_LSB,
}, },
},
[7] = {
/* Accessory */
.name = "acc",
.module = TWL5031_MODULE_ACCESSORY,
.control_offset = TWL5031_ACCSIHCTRL,
.bits = 2,
.bytes_ixr = 1,
.edr_offset = TWL5031_ACCEDR1,
/* Note: most of these IRQs default to no-trigger */
.bytes_edr = 1,
.irq_lines = 2,
.mask = { {
.isr_offset = TWL5031_ACCISR1,
.imr_offset = TWL5031_ACCIMR1,
}, {
.isr_offset = TWL5031_ACCISR2,
.imr_offset = TWL5031_ACCIMR2,
}, },
},
};
#undef TWL4030_MODULE_KEYPAD_KEYP
#undef TWL4030_MODULE_INT_PWR
#undef TWL4030_INT_PWR_EDR
......@@ -194,7 +296,7 @@ static int twl4030_irq_thread(void *data)
/* Wait for IRQ, then read PIH irq status (also blocking) */
wait_for_completion_interruptible(&irq_event);
ret = twl4030_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr,
ret = twl_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr,
REG_PIH_ISR_P1);
if (ret) {
pr_warning("twl4030: I2C error %d reading PIH ISR\n",
......@@ -284,13 +386,17 @@ static int twl4030_init_sih_modules(unsigned line)
/* disable all interrupts on our line */
memset(buf, 0xff, sizeof buf);
sih = sih_modules;
for (i = 0; i < ARRAY_SIZE(sih_modules); i++, sih++) {
for (i = 0; i < nr_sih_modules; i++, sih++) {
/* skip USB -- it's funky */
if (!sih->bytes_ixr)
continue;
status = twl4030_i2c_write(sih->module, buf,
/* Not all the SIH modules support multiple interrupt lines */
if (sih->irq_lines <= line)
continue;
status = twl_i2c_write(sih->module, buf,
sih->mask[line].imr_offset, sih->bytes_ixr);
if (status < 0)
pr_err("twl4030: err %d initializing %s %s\n",
......@@ -304,7 +410,7 @@ static int twl4030_init_sih_modules(unsigned line)
* And for PWR_INT it's not documented...
*/
if (sih->set_cor) {
status = twl4030_i2c_write_u8(sih->module,
status = twl_i2c_write_u8(sih->module,
TWL4030_SIH_CTRL_COR_MASK,
sih->control_offset);
if (status < 0)
......@@ -314,7 +420,7 @@ static int twl4030_init_sih_modules(unsigned line)
}
sih = sih_modules;
for (i = 0; i < ARRAY_SIZE(sih_modules); i++, sih++) {
for (i = 0; i < nr_sih_modules; i++, sih++) {
u8 rxbuf[4];
int j;
......@@ -322,20 +428,24 @@ static int twl4030_init_sih_modules(unsigned line)
if (!sih->bytes_ixr)
continue;
/* Not all the SIH modules support multiple interrupt lines */
if (sih->irq_lines <= line)
continue;
/* Clear pending interrupt status. Either the read was
* enough, or we need to write those bits. Repeat, in
* case an IRQ is pending (PENDDIS=0) ... that's not
* uncommon with PWR_INT.PWRON.
*/
for (j = 0; j < 2; j++) {
status = twl4030_i2c_read(sih->module, rxbuf,
status = twl_i2c_read(sih->module, rxbuf,
sih->mask[line].isr_offset, sih->bytes_ixr);
if (status < 0)
pr_err("twl4030: err %d initializing %s %s\n",
status, sih->name, "ISR");
if (!sih->set_cor)
status = twl4030_i2c_write(sih->module, buf,
status = twl_i2c_write(sih->module, buf,
sih->mask[line].isr_offset,
sih->bytes_ixr);
/* else COR=1 means read sufficed.
......@@ -404,7 +514,7 @@ static void twl4030_sih_do_mask(struct work_struct *work)
return;
/* write the whole mask ... simpler than subsetting it */
status = twl4030_i2c_write(sih->module, imr.bytes,
status = twl_i2c_write(sih->module, imr.bytes,
sih->mask[irq_line].imr_offset, sih->bytes_ixr);
if (status)
pr_err("twl4030: %s, %s --> %d\n", __func__,
......@@ -435,7 +545,7 @@ static void twl4030_sih_do_edge(struct work_struct *work)
* any processor on the other IRQ line, EDR registers are
* shared.
*/
status = twl4030_i2c_read(sih->module, bytes + 1,
status = twl_i2c_read(sih->module, bytes + 1,
sih->edr_offset, sih->bytes_edr);
if (status) {
pr_err("twl4030: %s, %s --> %d\n", __func__,
......@@ -469,7 +579,7 @@ static void twl4030_sih_do_edge(struct work_struct *work)
}
/* Write */
status = twl4030_i2c_write(sih->module, bytes,
status = twl_i2c_write(sih->module, bytes,
sih->edr_offset, sih->bytes_edr);
if (status)
pr_err("twl4030: %s, %s --> %d\n", __func__,
......@@ -554,7 +664,7 @@ static inline int sih_read_isr(const struct sih *sih)
/* FIXME need retry-on-error ... */
isr.word = 0;
status = twl4030_i2c_read(sih->module, isr.bytes,
status = twl_i2c_read(sih->module, isr.bytes,
sih->mask[irq_line].isr_offset, sih->bytes_ixr);
return (status < 0) ? status : le32_to_cpu(isr.word);
......@@ -611,7 +721,7 @@ int twl4030_sih_setup(int module)
/* only support modules with standard clear-on-read for now */
for (sih_mod = 0, sih = sih_modules;
sih_mod < ARRAY_SIZE(sih_modules);
sih_mod < nr_sih_modules;
sih_mod++, sih++) {
if (sih->module == module && sih->set_cor) {
if (!WARN((irq_base + sih->bits) > NR_IRQS,
......@@ -668,7 +778,7 @@ int twl4030_sih_setup(int module)
/* FIXME pass in which interrupt line we'll use ... */
#define twl_irq_line 0
int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
{
static struct irq_chip twl4030_irq_chip;
......@@ -728,7 +838,8 @@ int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
goto fail_rqirq;
}
task = kthread_run(twl4030_irq_thread, (void *)irq_num, "twl4030-irq");
task = kthread_run(twl4030_irq_thread, (void *)(long)irq_num,
"twl4030-irq");
if (IS_ERR(task)) {
pr_err("twl4030: could not create irq %d thread!\n", irq_num);
status = PTR_ERR(task);
......@@ -747,7 +858,7 @@ int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
return status;
}
int twl_exit_irq(void)
int twl4030_exit_irq(void)
{
/* FIXME undo twl_init_irq() */
if (twl4030_irq_base) {
......@@ -756,3 +867,16 @@ int twl_exit_irq(void)
}
return 0;
}
int twl4030_init_chip_irq(const char *chip)
{
if (!strcmp(chip, "twl5031")) {
sih_modules = sih_modules_twl5031;
nr_sih_modules = ARRAY_SIZE(sih_modules_twl5031);
} else {
sih_modules = sih_modules_twl4030;
nr_sih_modules = ARRAY_SIZE(sih_modules_twl4030);
}
return 0;
}
......@@ -26,7 +26,7 @@
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/i2c/twl4030.h>
#include <linux/i2c/twl.h>
#include <linux/platform_device.h>
#include <asm/mach-types.h>
......@@ -67,19 +67,35 @@ static u8 twl4030_start_script_address = 0x2b;
#define R_KEY_1 0xC0
#define R_KEY_2 0x0C
/* resource configuration registers */
#define DEVGROUP_OFFSET 0
/* resource configuration registers
<RESOURCE>_DEV_GRP at address 'n+0'
<RESOURCE>_TYPE at address 'n+1'
<RESOURCE>_REMAP at address 'n+2'
<RESOURCE>_DEDICATED at address 'n+3'
*/
#define DEV_GRP_OFFSET 0
#define TYPE_OFFSET 1
#define REMAP_OFFSET 2
#define DEDICATED_OFFSET 3
/* Bit positions in the registers */
/* <RESOURCE>_DEV_GRP */
#define DEV_GRP_SHIFT 5
#define DEV_GRP_MASK (7 << DEV_GRP_SHIFT)
/* Bit positions */
#define DEVGROUP_SHIFT 5
#define DEVGROUP_MASK (7 << DEVGROUP_SHIFT)
/* <RESOURCE>_TYPE */
#define TYPE_SHIFT 0
#define TYPE_MASK (7 << TYPE_SHIFT)
#define TYPE2_SHIFT 3
#define TYPE2_MASK (3 << TYPE2_SHIFT)
/* <RESOURCE>_REMAP */
#define SLEEP_STATE_SHIFT 0
#define SLEEP_STATE_MASK (0xf << SLEEP_STATE_SHIFT)
#define OFF_STATE_SHIFT 4
#define OFF_STATE_MASK (0xf << OFF_STATE_SHIFT)
static u8 res_config_addrs[] = {
[RES_VAUX1] = 0x17,
[RES_VAUX2] = 0x1b,
......@@ -115,11 +131,11 @@ static int __init twl4030_write_script_byte(u8 address, u8 byte)
{
int err;
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
R_MEMORY_ADDRESS);
if (err)
goto out;
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte,
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte,
R_MEMORY_DATA);
out:
return err;
......@@ -176,18 +192,18 @@ static int __init twl4030_config_wakeup3_sequence(u8 address)
u8 data;
/* Set SLEEP to ACTIVE SEQ address for P3 */
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
R_SEQ_ADD_S2A3);
if (err)
goto out;
/* P3 LVL_WAKEUP should be on LEVEL */
err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
R_P3_SW_EVENTS);
if (err)
goto out;
data |= LVL_WAKEUP;
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
R_P3_SW_EVENTS);
out:
if (err)
......@@ -201,42 +217,42 @@ static int __init twl4030_config_wakeup12_sequence(u8 address)
u8 data;
/* Set SLEEP to ACTIVE SEQ address for P1 and P2 */
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
R_SEQ_ADD_S2A12);
if (err)
goto out;
/* P1/P2 LVL_WAKEUP should be on LEVEL */
err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
R_P1_SW_EVENTS);
if (err)
goto out;
data |= LVL_WAKEUP;
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
R_P1_SW_EVENTS);
if (err)
goto out;
err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
R_P2_SW_EVENTS);
if (err)
goto out;
data |= LVL_WAKEUP;
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
R_P2_SW_EVENTS);
if (err)
goto out;
if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) {
/* Disabling AC charger effect on sleep-active transitions */
err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
R_CFG_P1_TRANSITION);
if (err)
goto out;
data &= ~(1<<1);
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data ,
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data ,
R_CFG_P1_TRANSITION);
if (err)
goto out;
......@@ -254,7 +270,7 @@ static int __init twl4030_config_sleep_sequence(u8 address)
int err;
/* Set ACTIVE to SLEEP SEQ address in T2 memory*/
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
R_SEQ_ADD_A2S);
if (err)
......@@ -269,41 +285,41 @@ static int __init twl4030_config_warmreset_sequence(u8 address)
u8 rd_data;
/* Set WARM RESET SEQ address for P1 */
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
R_SEQ_ADD_WARM);
if (err)
goto out;
/* P1/P2/P3 enable WARMRESET */
err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
R_P1_SW_EVENTS);
if (err)
goto out;
rd_data |= ENABLE_WARMRESET;
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
R_P1_SW_EVENTS);
if (err)
goto out;
err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
R_P2_SW_EVENTS);
if (err)
goto out;
rd_data |= ENABLE_WARMRESET;
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
R_P2_SW_EVENTS);
if (err)
goto out;
err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
R_P3_SW_EVENTS);
if (err)
goto out;
rd_data |= ENABLE_WARMRESET;
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
R_P3_SW_EVENTS);
out:
if (err)
......@@ -317,6 +333,7 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
int err;
u8 type;
u8 grp;
u8 remap;
if (rconfig->resource > TOTAL_RESOURCES) {
pr_err("TWL4030 Resource %d does not exist\n",
......@@ -327,19 +344,19 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
rconfig_addr = res_config_addrs[rconfig->resource];
/* Set resource group */
err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp,
rconfig_addr + DEVGROUP_OFFSET);
err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp,
rconfig_addr + DEV_GRP_OFFSET);
if (err) {
pr_err("TWL4030 Resource %d group could not be read\n",
rconfig->resource);
return err;
}
if (rconfig->devgroup >= 0) {
grp &= ~DEVGROUP_MASK;
grp |= rconfig->devgroup << DEVGROUP_SHIFT;
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
grp, rconfig_addr + DEVGROUP_OFFSET);
if (rconfig->devgroup != TWL4030_RESCONFIG_UNDEF) {
grp &= ~DEV_GRP_MASK;
grp |= rconfig->devgroup << DEV_GRP_SHIFT;
err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
grp, rconfig_addr + DEV_GRP_OFFSET);
if (err < 0) {
pr_err("TWL4030 failed to program devgroup\n");
return err;
......@@ -347,7 +364,7 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
}
/* Set resource types */
err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &type,
err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &type,
rconfig_addr + TYPE_OFFSET);
if (err < 0) {
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)
return err;
}
if (rconfig->type >= 0) {
if (rconfig->type != TWL4030_RESCONFIG_UNDEF) {
type &= ~TYPE_MASK;
type |= rconfig->type << TYPE_SHIFT;
}
if (rconfig->type2 >= 0) {
if (rconfig->type2 != TWL4030_RESCONFIG_UNDEF) {
type &= ~TYPE2_MASK;
type |= rconfig->type2 << TYPE2_SHIFT;
}
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
type, rconfig_addr + TYPE_OFFSET);
if (err < 0) {
pr_err("TWL4030 failed to program resource type\n");
return err;
}
/* Set remap states */
err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &remap,
rconfig_addr + REMAP_OFFSET);
if (err < 0) {
pr_err("TWL4030 Resource %d remap could not be read\n",
rconfig->resource);
return err;
}
if (rconfig->remap_off != TWL4030_RESCONFIG_UNDEF) {
remap &= ~OFF_STATE_MASK;
remap |= rconfig->remap_off << OFF_STATE_SHIFT;
}
if (rconfig->remap_sleep != TWL4030_RESCONFIG_UNDEF) {
remap &= ~SLEEP_STATE_MASK;
remap |= rconfig->remap_off << SLEEP_STATE_SHIFT;
}
err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
remap,
rconfig_addr + REMAP_OFFSET);
if (err < 0) {
pr_err("TWL4030 failed to program remap\n");
return err;
}
return 0;
}
......@@ -424,12 +468,12 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
struct twl4030_resconfig *resconfig;
u8 address = twl4030_start_script_address;
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1,
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1,
R_PROTECT_KEY);
if (err)
goto unlock;
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2,
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2,
R_PROTECT_KEY);
if (err)
goto unlock;
......@@ -452,7 +496,7 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
}
}
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY);
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY);
if (err)
pr_err("TWL4030 Unable to relock registers\n");
return;
......
/*
* twl6030-irq.c - TWL6030 irq support
*
* Copyright (C) 2005-2009 Texas Instruments, Inc.
*
* Modifications to defer interrupt handling to a kernel thread:
* Copyright (C) 2006 MontaVista Software, Inc.
*
* Based on tlv320aic23.c:
* Copyright (c) by Kai Svahn <kai.svahn@nokia.com>
*
* Code cleanup and modifications to IRQ handler.
* by syed khasim <x0khasim@ti.com>
*
* TWL6030 specific code and IRQ handling changes by
* Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com>
* Balaji T K <balajitk@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kthread.h>
#include <linux/i2c/twl.h>
/*
* TWL6030 (unlike its predecessors, which had two level interrupt handling)
* three interrupt registers INT_STS_A, INT_STS_B and INT_STS_C.
* It exposes status bits saying who has raised an interrupt. There are
* three mask registers that corresponds to these status registers, that
* enables/disables these interrupts.
*
* We set up IRQs starting at a platform-specified base. An interrupt map table,
* specifies mapping between interrupt number and the associated module.
*
*/
static int twl6030_interrupt_mapping[24] = {
PWR_INTR_OFFSET, /* Bit 0 PWRON */
PWR_INTR_OFFSET, /* Bit 1 RPWRON */
PWR_INTR_OFFSET, /* Bit 2 BAT_VLOW */
RTC_INTR_OFFSET, /* Bit 3 RTC_ALARM */
RTC_INTR_OFFSET, /* Bit 4 RTC_PERIOD */
HOTDIE_INTR_OFFSET, /* Bit 5 HOT_DIE */
SMPSLDO_INTR_OFFSET, /* Bit 6 VXXX_SHORT */
SMPSLDO_INTR_OFFSET, /* Bit 7 VMMC_SHORT */
SMPSLDO_INTR_OFFSET, /* Bit 8 VUSIM_SHORT */
BATDETECT_INTR_OFFSET, /* Bit 9 BAT */
SIMDETECT_INTR_OFFSET, /* Bit 10 SIM */
MMCDETECT_INTR_OFFSET, /* Bit 11 MMC */
RSV_INTR_OFFSET, /* Bit 12 Reserved */
MADC_INTR_OFFSET, /* Bit 13 GPADC_RT_EOC */
MADC_INTR_OFFSET, /* Bit 14 GPADC_SW_EOC */
GASGAUGE_INTR_OFFSET, /* Bit 15 CC_AUTOCAL */
USBOTG_INTR_OFFSET, /* Bit 16 ID_WKUP */
USBOTG_INTR_OFFSET, /* Bit 17 VBUS_WKUP */
USBOTG_INTR_OFFSET, /* Bit 18 ID */
USBOTG_INTR_OFFSET, /* Bit 19 VBUS */
CHARGER_INTR_OFFSET, /* Bit 20 CHRG_CTRL */
CHARGER_INTR_OFFSET, /* Bit 21 EXT_CHRG */
CHARGER_INTR_OFFSET, /* Bit 22 INT_CHRG */
RSV_INTR_OFFSET, /* Bit 23 Reserved */
};
/*----------------------------------------------------------------------*/
static unsigned twl6030_irq_base;
static struct completion irq_event;
/*
* This thread processes interrupts reported by the Primary Interrupt Handler.
*/
static int twl6030_irq_thread(void *data)
{
long irq = (long)data;
static unsigned i2c_errors;
static const unsigned max_i2c_errors = 100;
int ret;
current->flags |= PF_NOFREEZE;
while (!kthread_should_stop()) {
int i;
union {
u8 bytes[4];
u32 int_sts;
} sts;
/* Wait for IRQ, then read PIH irq status (also blocking) */
wait_for_completion_interruptible(&irq_event);
/* read INT_STS_A, B and C in one shot using a burst read */
ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes,
REG_INT_STS_A, 3);
if (ret) {
pr_warning("twl6030: I2C error %d reading PIH ISR\n",
ret);
if (++i2c_errors >= max_i2c_errors) {
printk(KERN_ERR "Maximum I2C error count"
" exceeded. Terminating %s.\n",
__func__);
break;
}
complete(&irq_event);
continue;
}
sts.bytes[3] = 0; /* Only 24 bits are valid*/
for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) {
local_irq_disable();
if (sts.int_sts & 0x1) {
int module_irq = twl6030_irq_base +
twl6030_interrupt_mapping[i];
struct irq_desc *d = irq_to_desc(module_irq);
if (!d) {
pr_err("twl6030: Invalid SIH IRQ: %d\n",
module_irq);
return -EINVAL;
}
/* These can't be masked ... always warn
* if we get any surprises.
*/
if (d->status & IRQ_DISABLED)
note_interrupt(module_irq, d,
IRQ_NONE);
else
d->handle_irq(module_irq, d);
}
local_irq_enable();
}
ret = twl_i2c_write(TWL_MODULE_PIH, sts.bytes,
REG_INT_STS_A, 3); /* clear INT_STS_A */
if (ret)
pr_warning("twl6030: I2C error in clearing PIH ISR\n");
enable_irq(irq);
}
return 0;
}
/*
* handle_twl6030_int() is the desc->handle method for the twl6030 interrupt.
* This is a chained interrupt, so there is no desc->action method for it.
* Now we need to query the interrupt controller in the twl6030 to determine
* which module is generating the interrupt request. However, we can't do i2c
* transactions in interrupt context, so we must defer that work to a kernel
* thread. All we do here is acknowledge and mask the interrupt and wakeup
* the kernel thread.
*/
static irqreturn_t handle_twl6030_pih(int irq, void *devid)
{
disable_irq_nosync(irq);
complete(devid);
return IRQ_HANDLED;
}
/*----------------------------------------------------------------------*/
static inline void activate_irq(int irq)
{
#ifdef CONFIG_ARM
/* ARM requires an extra step to clear IRQ_NOREQUEST, which it
* sets on behalf of every irq_chip. Also sets IRQ_NOPROBE.
*/
set_irq_flags(irq, IRQF_VALID);
#else
/* same effect on other architectures */
set_irq_noprobe(irq);
#endif
}
/*----------------------------------------------------------------------*/
static unsigned twl6030_irq_next;
/*----------------------------------------------------------------------*/
int twl6030_interrupt_unmask(u8 bit_mask, u8 offset)
{
int ret;
u8 unmask_value;
ret = twl_i2c_read_u8(TWL_MODULE_PIH, &unmask_value,
REG_INT_STS_A + offset);
unmask_value &= (~(bit_mask));
ret |= twl_i2c_write_u8(TWL_MODULE_PIH, unmask_value,
REG_INT_STS_A + offset); /* unmask INT_MSK_A/B/C */
return ret;
}
EXPORT_SYMBOL(twl6030_interrupt_unmask);
int twl6030_interrupt_mask(u8 bit_mask, u8 offset)
{
int ret;
u8 mask_value;
ret = twl_i2c_read_u8(TWL_MODULE_PIH, &mask_value,
REG_INT_STS_A + offset);
mask_value |= (bit_mask);
ret |= twl_i2c_write_u8(TWL_MODULE_PIH, mask_value,
REG_INT_STS_A + offset); /* mask INT_MSK_A/B/C */
return ret;
}
EXPORT_SYMBOL(twl6030_interrupt_mask);
int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
{
int status = 0;
int i;
struct task_struct *task;
int ret;
u8 mask[4];
static struct irq_chip twl6030_irq_chip;
mask[1] = 0xFF;
mask[2] = 0xFF;
mask[3] = 0xFF;
ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
REG_INT_MSK_LINE_A, 3); /* MASK ALL INT LINES */
ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
REG_INT_MSK_STS_A, 3); /* MASK ALL INT STS */
ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
REG_INT_STS_A, 3); /* clear INT_STS_A,B,C */
twl6030_irq_base = irq_base;
/* install an irq handler for each of the modules;
* clone dummy irq_chip since PIH can't *do* anything
*/
twl6030_irq_chip = dummy_irq_chip;
twl6030_irq_chip.name = "twl6030";
twl6030_irq_chip.set_type = NULL;
for (i = irq_base; i < irq_end; i++) {
set_irq_chip_and_handler(i, &twl6030_irq_chip,
handle_simple_irq);
activate_irq(i);
}
twl6030_irq_next = i;
pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
irq_num, irq_base, twl6030_irq_next - 1);
/* install an irq handler to demultiplex the TWL6030 interrupt */
init_completion(&irq_event);
task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");
if (IS_ERR(task)) {
pr_err("twl6030: could not create irq %d thread!\n", irq_num);
status = PTR_ERR(task);
goto fail_kthread;
}
status = request_irq(irq_num, handle_twl6030_pih, IRQF_DISABLED,
"TWL6030-PIH", &irq_event);
if (status < 0) {
pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status);
goto fail_irq;
}
return status;
fail_irq:
free_irq(irq_num, &irq_event);
fail_kthread:
for (i = irq_base; i < irq_end; i++)
set_irq_chip_and_handler(i, NULL, NULL);
return status;
}
int twl6030_exit_irq(void)
{
if (twl6030_irq_base) {
pr_err("twl6030: can't yet clean up IRQs?\n");
return -ENOSYS;
}
return 0;
}
......@@ -90,9 +90,10 @@ int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = {
EXPORT_SYMBOL_GPL(wm831x_isinkv_values);
enum wm831x_parent {
WM8310 = 0,
WM8311 = 1,
WM8312 = 2,
WM8310 = 0x8310,
WM8311 = 0x8311,
WM8312 = 0x8312,
WM8320 = 0x8320,
};
static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
......@@ -478,6 +479,20 @@ static struct resource wm831x_dcdc4_resources[] = {
},
};
static struct resource wm8320_dcdc4_buck_resources[] = {
{
.start = WM831X_DC4_CONTROL,
.end = WM832X_DC4_SLEEP_CONTROL,
.flags = IORESOURCE_IO,
},
{
.name = "UV",
.start = WM831X_IRQ_UV_DC4,
.end = WM831X_IRQ_UV_DC4,
.flags = IORESOURCE_IRQ,
},
};
static struct resource wm831x_gpio_resources[] = {
{
.start = WM831X_IRQ_GPIO_1,
......@@ -1237,6 +1252,137 @@ static struct mfd_cell wm8312_devs[] = {
},
};
static struct mfd_cell wm8320_devs[] = {
{
.name = "wm831x-backup",
},
{
.name = "wm831x-buckv",
.id = 1,
.num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
.resources = wm831x_dcdc1_resources,
},
{
.name = "wm831x-buckv",
.id = 2,
.num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
.resources = wm831x_dcdc2_resources,
},
{
.name = "wm831x-buckp",
.id = 3,
.num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
.resources = wm831x_dcdc3_resources,
},
{
.name = "wm831x-buckp",
.id = 4,
.num_resources = ARRAY_SIZE(wm8320_dcdc4_buck_resources),
.resources = wm8320_dcdc4_buck_resources,
},
{
.name = "wm831x-gpio",
.num_resources = ARRAY_SIZE(wm831x_gpio_resources),
.resources = wm831x_gpio_resources,
},
{
.name = "wm831x-hwmon",
},
{
.name = "wm831x-ldo",
.id = 1,
.num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
.resources = wm831x_ldo1_resources,
},
{
.name = "wm831x-ldo",
.id = 2,
.num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
.resources = wm831x_ldo2_resources,
},
{
.name = "wm831x-ldo",
.id = 3,
.num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
.resources = wm831x_ldo3_resources,
},
{
.name = "wm831x-ldo",
.id = 4,
.num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
.resources = wm831x_ldo4_resources,
},
{
.name = "wm831x-ldo",
.id = 5,
.num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
.resources = wm831x_ldo5_resources,
},
{
.name = "wm831x-ldo",
.id = 6,
.num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
.resources = wm831x_ldo6_resources,
},
{
.name = "wm831x-aldo",
.id = 7,
.num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
.resources = wm831x_ldo7_resources,
},
{
.name = "wm831x-aldo",
.id = 8,
.num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
.resources = wm831x_ldo8_resources,
},
{
.name = "wm831x-aldo",
.id = 9,
.num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
.resources = wm831x_ldo9_resources,
},
{
.name = "wm831x-aldo",
.id = 10,
.num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
.resources = wm831x_ldo10_resources,
},
{
.name = "wm831x-alive-ldo",
.id = 11,
.num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
.resources = wm831x_ldo11_resources,
},
{
.name = "wm831x-on",
.num_resources = ARRAY_SIZE(wm831x_on_resources),
.resources = wm831x_on_resources,
},
{
.name = "wm831x-rtc",
.num_resources = ARRAY_SIZE(wm831x_rtc_resources),
.resources = wm831x_rtc_resources,
},
{
.name = "wm831x-status",
.id = 1,
.num_resources = ARRAY_SIZE(wm831x_status1_resources),
.resources = wm831x_status1_resources,
},
{
.name = "wm831x-status",
.id = 2,
.num_resources = ARRAY_SIZE(wm831x_status2_resources),
.resources = wm831x_status2_resources,
},
{
.name = "wm831x-watchdog",
.num_resources = ARRAY_SIZE(wm831x_wdt_resources),
.resources = wm831x_wdt_resources,
},
};
static struct mfd_cell backlight_devs[] = {
{
.name = "wm831x-backlight",
......@@ -1282,50 +1428,37 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
goto err;
}
/* Some engineering samples do not have the ID set, rely on
* the device being registered correctly.
*/
if (ret == 0) {
dev_info(wm831x->dev, "Device is an engineering sample\n");
ret = id;
}
switch (ret) {
case 0x8310:
case WM8310:
parent = WM8310;
switch (rev) {
case 0:
dev_info(wm831x->dev, "WM8310 revision %c\n",
'A' + rev);
break;
}
wm831x->num_gpio = 16;
dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev);
break;
case 0x8311:
case WM8311:
parent = WM8311;
switch (rev) {
case 0:
dev_info(wm831x->dev, "WM8311 revision %c\n",
'A' + rev);
break;
}
wm831x->num_gpio = 16;
dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev);
break;
case 0x8312:
case WM8312:
parent = WM8312;
switch (rev) {
case 0:
dev_info(wm831x->dev, "WM8312 revision %c\n",
'A' + rev);
break;
}
wm831x->num_gpio = 16;
dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev);
break;
case 0:
/* Some engineering samples do not have the ID set,
* rely on the device being registered correctly.
* This will need revisiting for future devices with
* multiple dies.
*/
parent = id;
switch (rev) {
case 0:
dev_info(wm831x->dev, "WM831%d ES revision %c\n",
parent, 'A' + rev);
break;
}
case WM8320:
parent = WM8320;
wm831x->num_gpio = 12;
dev_info(wm831x->dev, "WM8320 revision %c\n", 'A' + rev);
break;
default:
......@@ -1338,7 +1471,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
* current parts.
*/
if (parent != id)
dev_warn(wm831x->dev, "Device was registered as a WM831%lu\n",
dev_warn(wm831x->dev, "Device was registered as a WM%lx\n",
id);
/* Bootstrap the user key */
......@@ -1371,18 +1504,24 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
case WM8310:
ret = mfd_add_devices(wm831x->dev, -1,
wm8310_devs, ARRAY_SIZE(wm8310_devs),
NULL, 0);
NULL, wm831x->irq_base);
break;
case WM8311:
ret = mfd_add_devices(wm831x->dev, -1,
wm8311_devs, ARRAY_SIZE(wm8311_devs),
NULL, 0);
NULL, wm831x->irq_base);
break;
case WM8312:
ret = mfd_add_devices(wm831x->dev, -1,
wm8312_devs, ARRAY_SIZE(wm8312_devs),
NULL, wm831x->irq_base);
break;
case WM8320:
ret = mfd_add_devices(wm831x->dev, -1,
wm8320_devs, ARRAY_SIZE(wm8320_devs),
NULL, 0);
break;
......@@ -1399,7 +1538,8 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
if (pdata && pdata->backlight) {
/* Treat errors as non-critical */
ret = mfd_add_devices(wm831x->dev, -1, backlight_devs,
ARRAY_SIZE(backlight_devs), NULL, 0);
ARRAY_SIZE(backlight_devs), NULL,
wm831x->irq_base);
if (ret < 0)
dev_err(wm831x->dev, "Failed to add backlight: %d\n",
ret);
......@@ -1511,6 +1651,7 @@ static const struct i2c_device_id wm831x_i2c_id[] = {
{ "wm8310", WM8310 },
{ "wm8311", WM8311 },
{ "wm8312", WM8312 },
{ "wm8320", WM8320 },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -3170,14 +3170,6 @@ const u16 wm8352_mode3_defaults[] = {
};
#endif
/* The register defaults for the config mode used must be compiled in but
* due to the impact on kernel size it is possible to disable
*/
#ifndef WM8350_HAVE_CONFIG_MODE
#warning No WM8350 config modes supported - select at least one of the
#warning MFD_WM8350_CONFIG_MODE_n options from the board driver.
#endif
/*
* Access masks.
*/
......
......@@ -303,7 +303,6 @@ static const u8 mbc_irq_handlers[] = {
static int __devinit pcf50633_mbc_probe(struct platform_device *pdev)
{
struct pcf50633_mbc *mbc;
struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data;
int ret;
int i;
u8 mbcs1;
......@@ -313,7 +312,7 @@ static int __devinit pcf50633_mbc_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, mbc);
mbc->pcf = pdata->pcf;
mbc->pcf = dev_to_pcf50633(pdev->dev.parent);
/* Set up IRQ handlers */
for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
......
This diff is collapsed.
......@@ -70,7 +70,7 @@ config REGULATOR_MAX1586
for PXA27x chips to control VCC_CORE and VCC_USIM voltages.
config REGULATOR_TWL4030
bool "TI TWL4030/TWL5030/TPS695x0 PMIC"
bool "TI TWL4030/TWL5030/TWL6030/TPS695x0 PMIC"
depends on TWL4030_CORE
help
This driver supports the voltage regulators provided by
......
......@@ -11,7 +11,7 @@ obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o
obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
......
......@@ -314,13 +314,15 @@ static int __devinit pcf50633_regulator_probe(struct platform_device *pdev)
struct pcf50633 *pcf;
/* Already set by core driver */
pcf = platform_get_drvdata(pdev);
pcf = dev_to_pcf50633(pdev->dev.parent);
rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
pdev->dev.platform_data, pcf);
if (IS_ERR(rdev))
return PTR_ERR(rdev);
platform_set_drvdata(pdev, rdev);
if (pcf->pdata->regulator_registered)
pcf->pdata->regulator_registered(pcf, pdev->id);
......@@ -331,6 +333,7 @@ static int __devexit pcf50633_regulator_remove(struct platform_device *pdev)
{
struct regulator_dev *rdev = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
regulator_unregister(rdev);
return 0;
......
......@@ -1330,9 +1330,10 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
},
};
static void pmic_uv_handler(struct wm8350 *wm8350, int irq, void *data)
static irqreturn_t pmic_uv_handler(int irq, void *data)
{
struct regulator_dev *rdev = (struct regulator_dev *)data;
struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
mutex_lock(&rdev->mutex);
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)
REGULATOR_EVENT_UNDER_VOLTAGE,
wm8350);
mutex_unlock(&rdev->mutex);
return IRQ_HANDLED;
}
static int wm8350_regulator_probe(struct platform_device *pdev)
......@@ -1388,7 +1391,7 @@ static int wm8350_regulator_probe(struct platform_device *pdev)
/* register regulator IRQ */
ret = wm8350_register_irq(wm8350, wm8350_reg[pdev->id].irq,
pmic_uv_handler, rdev);
pmic_uv_handler, 0, "UV", rdev);
if (ret < 0) {
regulator_unregister(rdev);
dev_err(&pdev->dev, "failed to register regulator %s IRQ\n",
......@@ -1396,8 +1399,6 @@ static int wm8350_regulator_probe(struct platform_device *pdev)
return ret;
}
wm8350_unmask_irq(wm8350, wm8350_reg[pdev->id].irq);
return 0;
}
......@@ -1406,7 +1407,6 @@ static int wm8350_regulator_remove(struct platform_device *pdev)
struct regulator_dev *rdev = platform_get_drvdata(pdev);
struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
wm8350_mask_irq(wm8350, wm8350_reg[pdev->id].irq);
wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq);
regulator_unregister(rdev);
......
......@@ -258,14 +258,14 @@ config RTC_DRV_TWL92330
the Menelaus driver; it's not separate module.
config RTC_DRV_TWL4030
tristate "TI TWL4030/TWL5030/TPS659x0"
tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0"
depends on RTC_CLASS && TWL4030_CORE
help
If you say yes here you get support for the RTC on the
TWL4030 family chips, used mostly with OMAP3 platforms.
TWL4030/TWL5030/TWL6030 family chips, used mostly with OMAP3 platforms.
This driver can also be built as a module. If so, the module
will be called rtc-twl4030.
will be called rtc-twl.
config RTC_DRV_S35390A
tristate "Seiko Instruments S-35390A"
......
......@@ -80,7 +80,7 @@ obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o
obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl4030.o
obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o
obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o
obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment