]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'for-next' of git://git.o-hand.com/linux-mfd
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 20 Oct 2008 16:22:47 +0000 (09:22 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 20 Oct 2008 16:22:47 +0000 (09:22 -0700)
* 'for-next' of git://git.o-hand.com/linux-mfd:
  mfd: further unbork the ucb1400 ac97_bus dependencies
  mfd: ucb1400 needs GPIO
  mfd: ucb1400 sound driver uses/depends on AC97_BUS:
  mfd: Don't use NO_IRQ in WM8350
  mfd: update TMIO drivers to use the clock API
  mfd: twl4030-core irq simplification
  mfd: add base support for Dialog DA9030/DA9034 PMICs
  mfd: TWL4030 core driver
  mfd: support tmiofb cell on tc6393xb
  mfd: add OHCI cell to tc6393xb
  mfd: Fix htc-egpio compile warning
  mfd: do tcb6393xb state restore on resume only if requested
  mfd: provide and use setup hook for tc6393xb
  mfd: update sm501 debugging/low information messages
  mfd: reduce stack usage in mfd-core.c

19 files changed:
arch/arm/mach-pxa/include/mach/tosa.h
arch/arm/mach-pxa/tosa.c
drivers/input/touchscreen/Kconfig
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/da903x.c [new file with mode: 0644]
drivers/mfd/htc-egpio.c
drivers/mfd/mfd-core.c
drivers/mfd/sm501.c
drivers/mfd/t7l66xb.c
drivers/mfd/tc6387xb.c
drivers/mfd/tc6393xb.c
drivers/mfd/twl4030-core.c [new file with mode: 0644]
drivers/mfd/wm8350-core.c
include/linux/i2c/twl4030.h [new file with mode: 0644]
include/linux/mfd/da903x.h [new file with mode: 0644]
include/linux/mfd/t7l66xb.h
include/linux/mfd/tc6387xb.h
include/linux/mfd/tc6393xb.h

index a72803f0461bbe4320cebcaad410d2c17e5f685f..8bce6d8615b9ddec02856941fd1e700d79c505de 100644 (file)
@@ -59,8 +59,6 @@
  * TC6393XB GPIOs
  */
 #define TOSA_TC6393XB_GPIO_BASE                (NR_BUILTIN_GPIO + 2 * 12)
-#define TOSA_TC6393XB_GPIO(i)          (TOSA_TC6393XB_GPIO_BASE + (i))
-#define TOSA_TC6393XB_GPIO_BIT(gpio)   (1 << (gpio - TOSA_TC6393XB_GPIO_BASE))
 
 #define TOSA_GPIO_TG_ON                        (TOSA_TC6393XB_GPIO_BASE + 0)
 #define TOSA_GPIO_L_MUTE               (TOSA_TC6393XB_GPIO_BASE + 1)
index 130e37e4ebdd2292aef62443a8614e89d8dd92bd..a6c4694359cabfdde423f8e669cac9dfeaca9163 100644 (file)
@@ -706,16 +706,39 @@ static struct tmio_nand_data tosa_tc6393xb_nand_config = {
        .badblock_pattern = &tosa_tc6393xb_nand_bbt,
 };
 
-static struct tc6393xb_platform_data tosa_tc6393xb_setup = {
+static int tosa_tc6393xb_setup(struct platform_device *dev)
+{
+       int rc;
+
+       rc = gpio_request(TOSA_GPIO_CARD_VCC_ON, "CARD_VCC_ON");
+       if (rc)
+               goto err_req;
+
+       rc = gpio_direction_output(TOSA_GPIO_CARD_VCC_ON, 1);
+       if (rc)
+               goto err_dir;
+
+       return rc;
+
+err_dir:
+       gpio_free(TOSA_GPIO_CARD_VCC_ON);
+err_req:
+       return rc;
+}
+
+static void tosa_tc6393xb_teardown(struct platform_device *dev)
+{
+       gpio_free(TOSA_GPIO_CARD_VCC_ON);
+}
+
+static struct tc6393xb_platform_data tosa_tc6393xb_data = {
        .scr_pll2cr     = 0x0cc1,
        .scr_gper       = 0x3300,
-       .scr_gpo_dsr    =
-               TOSA_TC6393XB_GPIO_BIT(TOSA_GPIO_CARD_VCC_ON),
-       .scr_gpo_doecr  =
-               TOSA_TC6393XB_GPIO_BIT(TOSA_GPIO_CARD_VCC_ON),
 
        .irq_base       = IRQ_BOARD_START,
        .gpio_base      = TOSA_TC6393XB_GPIO_BASE,
+       .setup          = tosa_tc6393xb_setup,
+       .teardown       = tosa_tc6393xb_teardown,
 
        .enable         = tosa_tc6393xb_enable,
        .disable        = tosa_tc6393xb_disable,
@@ -723,6 +746,8 @@ static struct tc6393xb_platform_data tosa_tc6393xb_setup = {
        .resume         = tosa_tc6393xb_resume,
 
        .nand_data      = &tosa_tc6393xb_nand_config,
+
+       .resume_restore = 1,
 };
 
 
@@ -730,7 +755,7 @@ static struct platform_device tc6393xb_device = {
        .name   = "tc6393xb",
        .id     = -1,
        .dev    = {
-               .platform_data  = &tosa_tc6393xb_setup,
+               .platform_data  = &tosa_tc6393xb_data,
        },
        .num_resources  = ARRAY_SIZE(tc6393xb_resources),
        .resource       = tc6393xb_resources,
index 6e1e8c624f9e73c0afda36b2eb603dcb77f5ac17..8317fdef1691c0bb4c564116c8b27c75e24b561e 100644 (file)
@@ -219,7 +219,7 @@ config TOUCHSCREEN_ATMEL_TSADCC
 
 config TOUCHSCREEN_UCB1400
        tristate "Philips UCB1400 touchscreen"
-       select AC97_BUS
+       depends on AC97_BUS
        depends on UCB1400_CORE
        help
          This enables support for the Philips UCB1400 touchscreen interface.
index 5eff8ad834d6f6bae7da3e97a89a3a6c87a336fa..5a79d2d4cdaeaff90e0306a651dea21ba95e79f8 100644 (file)
@@ -52,6 +52,8 @@ config HTC_PASIC3
 
 config UCB1400_CORE
        tristate "Philips UCB1400 Core driver"
+       depends on AC97_BUS
+       depends on GPIOLIB
        help
          This enables support for the Philips UCB1400 core functions.
          The UCB1400 is an AC97 audio codec.
@@ -59,6 +61,20 @@ config UCB1400_CORE
          To compile this driver as a module, choose M here: the
          module will be called ucb1400_core.
 
+config TWL4030_CORE
+       bool "Texas Instruments TWL4030/TPS659x0 Support"
+       depends on I2C=y && GENERIC_HARDIRQS && (ARCH_OMAP2 || ARCH_OMAP3)
+       help
+         Say yes here if you have TWL4030 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.
+
+         These multi-function chips are found on many OMAP2 and OMAP3
+         boards, providing power management, RTC, GPIO, keypad, a
+         high speed USB OTG transceiver, an audio codec (on most
+         versions) and many other features.
+
 config MFD_TMIO
        bool
        default n
index 759b1fe1c891a44bac2c5486ea51da90d1de0985..68e237b830ad1b6294ab460d30de806ede18874e 100644 (file)
@@ -17,6 +17,8 @@ wm8350-objs                   := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
 obj-$(CONFIG_MFD_WM8350)       += wm8350.o
 obj-$(CONFIG_MFD_WM8350_I2C)   += wm8350-i2c.o
 
+obj-$(CONFIG_TWL4030_CORE)     += twl4030-core.o
+
 obj-$(CONFIG_MFD_CORE)         += mfd-core.o
 
 obj-$(CONFIG_MCP)              += mcp-core.o
diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c
new file mode 100644 (file)
index 0000000..b57326a
--- /dev/null
@@ -0,0 +1,563 @@
+/*
+ * Base driver for Dialog Semiconductor DA9030/DA9034
+ *
+ * Copyright (C) 2008 Compulab, Ltd.
+ *     Mike Rapoport <mike@compulab.co.il>
+ *
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ *     Eric Miao <eric.miao@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/da903x.h>
+
+#define DA9030_CHIP_ID         0x00
+#define DA9030_EVENT_A         0x01
+#define DA9030_EVENT_B         0x02
+#define DA9030_EVENT_C         0x03
+#define DA9030_STATUS          0x04
+#define DA9030_IRQ_MASK_A      0x05
+#define DA9030_IRQ_MASK_B      0x06
+#define DA9030_IRQ_MASK_C      0x07
+#define DA9030_SYS_CTRL_A      0x08
+#define DA9030_SYS_CTRL_B      0x09
+#define DA9030_FAULT_LOG       0x0a
+
+#define DA9034_CHIP_ID         0x00
+#define DA9034_EVENT_A         0x01
+#define DA9034_EVENT_B         0x02
+#define DA9034_EVENT_C         0x03
+#define DA9034_EVENT_D         0x04
+#define DA9034_STATUS_A                0x05
+#define DA9034_STATUS_B                0x06
+#define DA9034_IRQ_MASK_A      0x07
+#define DA9034_IRQ_MASK_B      0x08
+#define DA9034_IRQ_MASK_C      0x09
+#define DA9034_IRQ_MASK_D      0x0a
+#define DA9034_SYS_CTRL_A      0x0b
+#define DA9034_SYS_CTRL_B      0x0c
+#define DA9034_FAULT_LOG       0x0d
+
+struct da903x_chip;
+
+struct da903x_chip_ops {
+       int     (*init_chip)(struct da903x_chip *);
+       int     (*unmask_events)(struct da903x_chip *, unsigned int events);
+       int     (*mask_events)(struct da903x_chip *, unsigned int events);
+       int     (*read_events)(struct da903x_chip *, unsigned int *events);
+       int     (*read_status)(struct da903x_chip *, unsigned int *status);
+};
+
+struct da903x_chip {
+       struct i2c_client       *client;
+       struct device           *dev;
+       struct da903x_chip_ops  *ops;
+
+       int                     type;
+       uint32_t                events_mask;
+
+       struct mutex            lock;
+       struct work_struct      irq_work;
+
+       struct blocking_notifier_head notifier_list;
+};
+
+static inline int __da903x_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 inline int __da903x_reads(struct i2c_client *client, int reg,
+                                int len, uint8_t *val)
+{
+       int ret;
+
+       ret = i2c_smbus_read_i2c_block_data(client, reg, len, val);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed reading from 0x%02x\n", reg);
+               return ret;
+       }
+       return 0;
+}
+
+static inline int __da903x_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 inline int __da903x_writes(struct i2c_client *client, int reg,
+                                 int len, uint8_t *val)
+{
+       int ret;
+
+       ret = i2c_smbus_write_i2c_block_data(client, reg, len, val);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed writings to 0x%02x\n", reg);
+               return ret;
+       }
+       return 0;
+}
+
+int da903x_register_notifier(struct device *dev, struct notifier_block *nb,
+                               unsigned int events)
+{
+       struct da903x_chip *chip = dev_get_drvdata(dev);
+
+       chip->ops->unmask_events(chip, events);
+       return blocking_notifier_chain_register(&chip->notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(da903x_register_notifier);
+
+int da903x_unregister_notifier(struct device *dev, struct notifier_block *nb,
+                               unsigned int events)
+{
+       struct da903x_chip *chip = dev_get_drvdata(dev);
+
+       chip->ops->mask_events(chip, events);
+       return blocking_notifier_chain_unregister(&chip->notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(da903x_unregister_notifier);
+
+int da903x_write(struct device *dev, int reg, uint8_t val)
+{
+       return __da903x_write(to_i2c_client(dev), reg, val);
+}
+EXPORT_SYMBOL_GPL(da903x_write);
+
+int da903x_read(struct device *dev, int reg, uint8_t *val)
+{
+       return __da903x_read(to_i2c_client(dev), reg, val);
+}
+EXPORT_SYMBOL_GPL(da903x_read);
+
+int da903x_set_bits(struct device *dev, int reg, uint8_t bit_mask)
+{
+       struct da903x_chip *chip = dev_get_drvdata(dev);
+       uint8_t reg_val;
+       int ret = 0;
+
+       mutex_lock(&chip->lock);
+
+       ret = __da903x_read(chip->client, reg, &reg_val);
+       if (ret)
+               goto out;
+
+       if ((reg_val & bit_mask) == 0) {
+               reg_val |= bit_mask;
+               ret = __da903x_write(chip->client, reg, reg_val);
+       }
+out:
+       mutex_unlock(&chip->lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(da903x_set_bits);
+
+int da903x_clr_bits(struct device *dev, int reg, uint8_t bit_mask)
+{
+       struct da903x_chip *chip = dev_get_drvdata(dev);
+       uint8_t reg_val;
+       int ret = 0;
+
+       mutex_lock(&chip->lock);
+
+       ret = __da903x_read(chip->client, reg, &reg_val);
+       if (ret)
+               goto out;
+
+       if (reg_val & bit_mask) {
+               reg_val &= ~bit_mask;
+               ret = __da903x_write(chip->client, reg, reg_val);
+       }
+out:
+       mutex_unlock(&chip->lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(da903x_clr_bits);
+
+int da903x_update(struct device *dev, int reg, uint8_t val, uint8_t mask)
+{
+       struct da903x_chip *chip = dev_get_drvdata(dev);
+       uint8_t reg_val;
+       int ret = 0;
+
+       mutex_lock(&chip->lock);
+
+       ret = __da903x_read(chip->client, reg, &reg_val);
+       if (ret)
+               goto out;
+
+       if ((reg_val & mask) != val) {
+               reg_val = (reg_val & ~mask) | val;
+               ret = __da903x_write(chip->client, reg, reg_val);
+       }
+out:
+       mutex_unlock(&chip->lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(da903x_update);
+
+int da903x_query_status(struct device *dev, unsigned int sbits)
+{
+       struct da903x_chip *chip = dev_get_drvdata(dev);
+       unsigned int status = 0;
+
+       chip->ops->read_status(chip, &status);
+       return ((status & sbits) == sbits);
+}
+EXPORT_SYMBOL(da903x_query_status);
+
+static int __devinit da9030_init_chip(struct da903x_chip *chip)
+{
+       uint8_t chip_id;
+       int err;
+
+       err = __da903x_read(chip->client, DA9030_CHIP_ID, &chip_id);
+       if (err)
+               return err;
+
+       err = __da903x_write(chip->client, DA9030_SYS_CTRL_A, 0xE8);
+       if (err)
+               return err;
+
+       dev_info(chip->dev, "DA9030 (CHIP ID: 0x%02x) detected\n", chip_id);
+       return 0;
+}
+
+static int da9030_unmask_events(struct da903x_chip *chip, unsigned int events)
+{
+       uint8_t v[3];
+
+       chip->events_mask &= ~events;
+
+       v[0] = (chip->events_mask & 0xff);
+       v[1] = (chip->events_mask >> 8) & 0xff;
+       v[2] = (chip->events_mask >> 16) & 0xff;
+
+       return __da903x_writes(chip->client, DA9030_IRQ_MASK_A, 3, v);
+}
+
+static int da9030_mask_events(struct da903x_chip *chip, unsigned int events)
+{
+       uint8_t v[3];
+
+       chip->events_mask &= ~events;
+
+       v[0] = (chip->events_mask & 0xff);
+       v[1] = (chip->events_mask >> 8) & 0xff;
+       v[2] = (chip->events_mask >> 16) & 0xff;
+
+       return __da903x_writes(chip->client, DA9030_IRQ_MASK_A, 3, v);
+}
+
+static int da9030_read_events(struct da903x_chip *chip, unsigned int *events)
+{
+       uint8_t v[3] = {0, 0, 0};
+       int ret;
+
+       ret = __da903x_reads(chip->client, DA9030_EVENT_A, 3, v);
+       if (ret < 0)
+               return ret;
+
+       *events = (v[2] << 16) | (v[1] << 8) | v[0];
+       return 0;
+}
+
+static int da9030_read_status(struct da903x_chip *chip, unsigned int *status)
+{
+       return __da903x_read(chip->client, DA9030_STATUS, (uint8_t *)status);
+}
+
+static int da9034_init_chip(struct da903x_chip *chip)
+{
+       uint8_t chip_id;
+       int err;
+
+       err = __da903x_read(chip->client, DA9034_CHIP_ID, &chip_id);
+       if (err)
+               return err;
+
+       err = __da903x_write(chip->client, DA9034_SYS_CTRL_A, 0xE8);
+       if (err)
+               return err;
+
+       /* avoid SRAM power off during sleep*/
+       __da903x_write(chip->client, 0x10, 0x07);
+       __da903x_write(chip->client, 0x11, 0xff);
+       __da903x_write(chip->client, 0x12, 0xff);
+
+       /* Enable the ONKEY power down functionality */
+       __da903x_write(chip->client, DA9034_SYS_CTRL_B, 0x20);
+       __da903x_write(chip->client, DA9034_SYS_CTRL_A, 0x60);
+
+       /* workaround to make LEDs work */
+       __da903x_write(chip->client, 0x90, 0x01);
+       __da903x_write(chip->client, 0xB0, 0x08);
+
+       /* make ADTV1 and SDTV1 effective */
+       __da903x_write(chip->client, 0x20, 0x00);
+
+       dev_info(chip->dev, "DA9034 (CHIP ID: 0x%02x) detected\n", chip_id);
+       return 0;
+}
+
+static int da9034_unmask_events(struct da903x_chip *chip, unsigned int events)
+{
+       uint8_t v[4];
+
+       chip->events_mask &= ~events;
+
+       v[0] = (chip->events_mask & 0xff);
+       v[1] = (chip->events_mask >> 8) & 0xff;
+       v[2] = (chip->events_mask >> 16) & 0xff;
+       v[3] = (chip->events_mask >> 24) & 0xff;
+
+       return __da903x_writes(chip->client, DA9034_IRQ_MASK_A, 4, v);
+}
+
+static int da9034_mask_events(struct da903x_chip *chip, unsigned int events)
+{
+       uint8_t v[4];
+
+       chip->events_mask |= events;
+
+       v[0] = (chip->events_mask & 0xff);
+       v[1] = (chip->events_mask >> 8) & 0xff;
+       v[2] = (chip->events_mask >> 16) & 0xff;
+       v[3] = (chip->events_mask >> 24) & 0xff;
+
+       return __da903x_writes(chip->client, DA9034_IRQ_MASK_A, 4, v);
+}
+
+static int da9034_read_events(struct da903x_chip *chip, unsigned int *events)
+{
+       uint8_t v[4] = {0, 0, 0, 0};
+       int ret;
+
+       ret = __da903x_reads(chip->client, DA9034_EVENT_A, 4, v);
+       if (ret < 0)
+               return ret;
+
+       *events = (v[3] << 24) | (v[2] << 16) | (v[1] << 8) | v[0];
+       return 0;
+}
+
+static int da9034_read_status(struct da903x_chip *chip, unsigned int *status)
+{
+       uint8_t v[2] = {0, 0};
+       int ret = 0;
+
+       ret = __da903x_reads(chip->client, DA9034_STATUS_A, 2, v);
+       if (ret)
+               return ret;
+
+       *status = (v[1] << 8) | v[0];
+       return 0;
+}
+
+static void da903x_irq_work(struct work_struct *work)
+{
+       struct da903x_chip *chip =
+               container_of(work, struct da903x_chip, irq_work);
+       unsigned int events = 0;
+
+       while (1) {
+               if (chip->ops->read_events(chip, &events))
+                       break;
+
+               events &= ~chip->events_mask;
+               if (events == 0)
+                       break;
+
+               blocking_notifier_call_chain(
+                               &chip->notifier_list, events, NULL);
+       }
+       enable_irq(chip->client->irq);
+}
+
+static int da903x_irq_handler(int irq, void *data)
+{
+       struct da903x_chip *chip = data;
+
+       disable_irq_nosync(irq);
+       (void)schedule_work(&chip->irq_work);
+
+       return IRQ_HANDLED;
+}
+
+static struct da903x_chip_ops da903x_ops[] = {
+       [0] = {
+               .init_chip      = da9030_init_chip,
+               .unmask_events  = da9030_unmask_events,
+               .mask_events    = da9030_mask_events,
+               .read_events    = da9030_read_events,
+               .read_status    = da9030_read_status,
+       },
+       [1] = {
+               .init_chip      = da9034_init_chip,
+               .unmask_events  = da9034_unmask_events,
+               .mask_events    = da9034_mask_events,
+               .read_events    = da9034_read_events,
+               .read_status    = da9034_read_status,
+       }
+};
+
+static const struct i2c_device_id da903x_id_table[] = {
+       { "da9030", 0 },
+       { "da9034", 1 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, da903x_id_table);
+
+static int __devexit __remove_subdev(struct device *dev, void *unused)
+{
+       platform_device_unregister(to_platform_device(dev));
+       return 0;
+}
+
+static int __devexit da903x_remove_subdevs(struct da903x_chip *chip)
+{
+       return device_for_each_child(chip->dev, NULL, __remove_subdev);
+}
+
+static int __devinit da903x_add_subdevs(struct da903x_chip *chip,
+                                       struct da903x_platform_data *pdata)
+{
+       struct da903x_subdev_info *subdev;
+       struct platform_device *pdev;
+       int i, ret = 0;
+
+       for (i = 0; i < pdata->num_subdevs; i++) {
+               subdev = &pdata->subdevs[i];
+
+               pdev = platform_device_alloc(subdev->name, subdev->id);
+
+               pdev->dev.parent = chip->dev;
+               pdev->dev.platform_data = subdev->platform_data;
+
+               ret = platform_device_add(pdev);
+               if (ret)
+                       goto failed;
+       }
+       return 0;
+
+failed:
+       da903x_remove_subdevs(chip);
+       return ret;
+}
+
+static int __devinit da903x_probe(struct i2c_client *client,
+                                 const struct i2c_device_id *id)
+{
+       struct da903x_platform_data *pdata = client->dev.platform_data;
+       struct da903x_chip *chip;
+       unsigned int tmp;
+       int ret;
+
+       chip = kzalloc(sizeof(struct da903x_chip), GFP_KERNEL);
+       if (chip == NULL)
+               return -ENOMEM;
+
+       chip->client = client;
+       chip->dev = &client->dev;
+       chip->ops = &da903x_ops[id->driver_data];
+
+       mutex_init(&chip->lock);
+       INIT_WORK(&chip->irq_work, da903x_irq_work);
+       BLOCKING_INIT_NOTIFIER_HEAD(&chip->notifier_list);
+
+       i2c_set_clientdata(client, chip);
+
+       ret = chip->ops->init_chip(chip);
+       if (ret)
+               goto out_free_chip;
+
+       /* mask and clear all IRQs */
+       chip->events_mask = 0xffffffff;
+       chip->ops->mask_events(chip, chip->events_mask);
+       chip->ops->read_events(chip, &tmp);
+
+       ret = request_irq(client->irq, da903x_irq_handler,
+                       IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+                       "da903x", chip);
+       if (ret) {
+               dev_err(&client->dev, "failed to request irq %d\n",
+                               client->irq);
+               goto out_free_chip;
+       }
+
+       ret = da903x_add_subdevs(chip, pdata);
+       if (ret)
+               goto out_free_irq;
+
+       return 0;
+
+out_free_irq:
+       free_irq(client->irq, chip);
+out_free_chip:
+       i2c_set_clientdata(client, NULL);
+       kfree(chip);
+       return ret;
+}
+
+static int __devexit da903x_remove(struct i2c_client *client)
+{
+       struct da903x_chip *chip = i2c_get_clientdata(client);
+
+       da903x_remove_subdevs(chip);
+       kfree(chip);
+       return 0;
+}
+
+static struct i2c_driver da903x_driver = {
+       .driver = {
+               .name   = "da903x",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = da903x_probe,
+       .remove         = __devexit_p(da903x_remove),
+       .id_table       = da903x_id_table,
+};
+
+static int __init da903x_init(void)
+{
+       return i2c_add_driver(&da903x_driver);
+}
+module_init(da903x_init);
+
+static void __exit da903x_exit(void)
+{
+       i2c_del_driver(&da903x_driver);
+}
+module_exit(da903x_exit);
+
+MODULE_DESCRIPTION("PMIC Driver for Dialog Semiconductor DA9034");
+MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"
+             "Mike Rapoport <mike@compulab.co.il>");
+MODULE_LICENSE("GPL");
index 6be43172dc656911cd5c9f41f8717426e2be9e54..50dff6e0088d919fae79f7769f412dbf5cc297ed 100644 (file)
@@ -289,7 +289,7 @@ static int __init egpio_probe(struct platform_device *pdev)
        ei->base_addr = ioremap_nocache(res->start, res->end - res->start);
        if (!ei->base_addr)
                goto fail;
-       pr_debug("EGPIO phys=%08x virt=%p\n", res->start, ei->base_addr);
+       pr_debug("EGPIO phys=%08x virt=%p\n", (u32)res->start, ei->base_addr);
 
        if ((pdata->bus_width != 16) && (pdata->bus_width != 32))
                goto fail;
index 9c9c126ed334d406320088ce29e66a8f3958f15d..6c0d1bec4b76c1ab58ae0cbe86cc2539cc3b6375 100644 (file)
@@ -20,7 +20,7 @@ static int mfd_add_device(struct device *parent, int id,
                          struct resource *mem_base,
                          int irq_base)
 {
-       struct resource res[cell->num_resources];
+       struct resource *res;
        struct platform_device *pdev;
        int ret = -ENOMEM;
        int r;
@@ -29,14 +29,17 @@ static int mfd_add_device(struct device *parent, int id,
        if (!pdev)
                goto fail_alloc;
 
+       res = kzalloc(sizeof(*res) * cell->num_resources, GFP_KERNEL);
+       if (!res)
+               goto fail_device;
+
        pdev->dev.parent = parent;
 
        ret = platform_device_add_data(pdev,
                        cell->platform_data, cell->data_size);
        if (ret)
-               goto fail_device;
+               goto fail_res;
 
-       memset(res, 0, sizeof(res));
        for (r = 0; r < cell->num_resources; r++) {
                res[r].name = cell->resources[r].name;
                res[r].flags = cell->resources[r].flags;
@@ -64,11 +67,15 @@ static int mfd_add_device(struct device *parent, int id,
 
        ret = platform_device_add(pdev);
        if (ret)
-               goto fail_device;
+               goto fail_res;
+
+       kfree(res);
 
        return 0;
 
 /*     platform_device_del(pdev); */
+fail_res:
+       kfree(res);
 fail_device:
        platform_device_put(pdev);
 fail_alloc:
index 7aebad4c06ff939114bdff7f5f58874ee197f96d..220e4371266be19dc304fb2b08ae42c203ea8bee 100644 (file)
@@ -623,8 +623,8 @@ unsigned long sm501_set_clock(struct device *dev,
 
        sm501_sync_regs(sm);
 
-       dev_info(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n",
-                gate, clock, mode);
+       dev_dbg(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n",
+               gate, clock, mode);
 
        sm501_mdelay(sm, 16);
        mutex_unlock(&sm->clock_lock);
@@ -742,7 +742,7 @@ static int sm501_register_device(struct sm501_devdata *sm,
        int ret;
 
        for (ptr = 0; ptr < pdev->num_resources; ptr++) {
-               printk("%s[%d] flags %08lx: %08llx..%08llx\n",
+               printk(KERN_DEBUG "%s[%d] flags %08lx: %08llx..%08llx\n",
                       pdev->name, ptr,
                       pdev->resource[ptr].flags,
                       (unsigned long long)pdev->resource[ptr].start,
index 49a0fffc02afc238813c42ecff698700184b962f..9f7024c0f8ec284843cd70deeefedf51babf84c4 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/err.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/tmio.h>
@@ -56,6 +58,8 @@ struct t7l66xb {
        spinlock_t              lock;
 
        struct resource         rscr;
+       struct clk              *clk48m;
+       struct clk              *clk32k;
        int                     irq;
        int                     irq_base;
 };
@@ -65,13 +69,11 @@ struct t7l66xb {
 static int t7l66xb_mmc_enable(struct platform_device *mmc)
 {
        struct platform_device *dev = to_platform_device(mmc->dev.parent);
-       struct t7l66xb_platform_data   *pdata = dev->dev.platform_data;
        struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
        unsigned long flags;
        u8 dev_ctl;
 
-       if (pdata->enable_clk32k)
-               pdata->enable_clk32k(dev);
+       clk_enable(t7l66xb->clk32k);
 
        spin_lock_irqsave(&t7l66xb->lock, flags);
 
@@ -87,7 +89,6 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc)
 static int t7l66xb_mmc_disable(struct platform_device *mmc)
 {
        struct platform_device *dev = to_platform_device(mmc->dev.parent);
-       struct t7l66xb_platform_data   *pdata = dev->dev.platform_data;
        struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
        unsigned long flags;
        u8 dev_ctl;
@@ -100,8 +101,7 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc)
 
        spin_unlock_irqrestore(&t7l66xb->lock, flags);
 
-       if (pdata->disable_clk32k)
-               pdata->disable_clk32k(dev);
+       clk_disable(t7l66xb->clk32k);
 
        return 0;
 }
@@ -258,18 +258,22 @@ static void t7l66xb_detach_irq(struct platform_device *dev)
 #ifdef CONFIG_PM
 static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state)
 {
+       struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
        struct t7l66xb_platform_data *pdata = dev->dev.platform_data;
 
        if (pdata && pdata->suspend)
                pdata->suspend(dev);
+       clk_disable(t7l66xb->clk48m);
 
        return 0;
 }
 
 static int t7l66xb_resume(struct platform_device *dev)
 {
+       struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
        struct t7l66xb_platform_data *pdata = dev->dev.platform_data;
 
+       clk_enable(t7l66xb->clk48m);
        if (pdata && pdata->resume)
                pdata->resume(dev);
 
@@ -309,6 +313,19 @@ static int t7l66xb_probe(struct platform_device *dev)
 
        t7l66xb->irq_base = pdata->irq_base;
 
+       t7l66xb->clk32k = clk_get(&dev->dev, "CLK_CK32K");
+       if (IS_ERR(t7l66xb->clk32k)) {
+               ret = PTR_ERR(t7l66xb->clk32k);
+               goto err_clk32k_get;
+       }
+
+       t7l66xb->clk48m = clk_get(&dev->dev, "CLK_CK48M");
+       if (IS_ERR(t7l66xb->clk48m)) {
+               ret = PTR_ERR(t7l66xb->clk48m);
+               clk_put(t7l66xb->clk32k);
+               goto err_clk48m_get;
+       }
+
        rscr = &t7l66xb->rscr;
        rscr->name = "t7l66xb-core";
        rscr->start = iomem->start;
@@ -325,6 +342,8 @@ static int t7l66xb_probe(struct platform_device *dev)
                goto err_ioremap;
        }
 
+       clk_enable(t7l66xb->clk48m);
+
        if (pdata && pdata->enable)
                pdata->enable(dev);
 
@@ -359,9 +378,13 @@ static int t7l66xb_probe(struct platform_device *dev)
        iounmap(t7l66xb->scr);
 err_ioremap:
        release_resource(&t7l66xb->rscr);
-err_noirq:
 err_request_scr:
        kfree(t7l66xb);
+       clk_put(t7l66xb->clk48m);
+err_clk48m_get:
+       clk_put(t7l66xb->clk32k);
+err_clk32k_get:
+err_noirq:
        return ret;
 }
 
@@ -372,7 +395,8 @@ static int t7l66xb_remove(struct platform_device *dev)
        int ret;
 
        ret = pdata->disable(dev);
-
+       clk_disable(t7l66xb->clk48m);
+       clk_put(t7l66xb->clk48m);
        t7l66xb_detach_irq(dev);
        iounmap(t7l66xb->scr);
        release_resource(&t7l66xb->rscr);
index a22b21ac6cf83989c0329e7fbb62c45db51b7751..43222c12fec14fc906993322c31f3cbad89f3e41 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/tmio.h>
@@ -24,18 +25,22 @@ enum {
 #ifdef CONFIG_PM
 static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state)
 {
-       struct tc6387xb_platform_data *pdata = platform_get_drvdata(dev);
+       struct clk *clk32k = platform_get_drvdata(dev);
+       struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
 
        if (pdata && pdata->suspend)
                pdata->suspend(dev);
+       clk_disable(clk32k);
 
        return 0;
 }
 
 static int tc6387xb_resume(struct platform_device *dev)
 {
-       struct tc6387xb_platform_data *pdata = platform_get_drvdata(dev);
+       struct clk *clk32k = platform_get_drvdata(dev);
+       struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
 
+       clk_enable(clk32k);
        if (pdata && pdata->resume)
                pdata->resume(dev);
 
@@ -51,10 +56,9 @@ static int tc6387xb_resume(struct platform_device *dev)
 static int tc6387xb_mmc_enable(struct platform_device *mmc)
 {
        struct platform_device *dev      = to_platform_device(mmc->dev.parent);
-       struct tc6387xb_platform_data *tc6387xb = dev->dev.platform_data;
+       struct clk *clk32k = platform_get_drvdata(dev);
 
-       if (tc6387xb->enable_clk32k)
-               tc6387xb->enable_clk32k(dev);
+       clk_enable(clk32k);
 
        return 0;
 }
@@ -62,10 +66,9 @@ static int tc6387xb_mmc_enable(struct platform_device *mmc)
 static int tc6387xb_mmc_disable(struct platform_device *mmc)
 {
        struct platform_device *dev      = to_platform_device(mmc->dev.parent);
-       struct tc6387xb_platform_data *tc6387xb = dev->dev.platform_data;
+       struct clk *clk32k = platform_get_drvdata(dev);
 
-       if (tc6387xb->disable_clk32k)
-               tc6387xb->disable_clk32k(dev);
+       clk_disable(clk32k);
 
        return 0;
 }
@@ -102,14 +105,14 @@ static struct mfd_cell tc6387xb_cells[] = {
 
 static int tc6387xb_probe(struct platform_device *dev)
 {
-       struct tc6387xb_platform_data *data = platform_get_drvdata(dev);
+       struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
        struct resource *iomem;
+       struct clk *clk32k;
        int irq, ret;
 
        iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
        if (!iomem) {
-               ret = -EINVAL;
-               goto err_resource;
+               return -EINVAL;
        }
 
        ret  = platform_get_irq(dev, 0);
@@ -118,8 +121,15 @@ static int tc6387xb_probe(struct platform_device *dev)
        else
                goto err_resource;
 
-       if (data && data->enable)
-               data->enable(dev);
+       clk32k = clk_get(&dev->dev, "CLK_CK32K");
+       if (IS_ERR(clk32k)) {
+               ret = PTR_ERR(clk32k);
+               goto err_resource;
+       }
+       platform_set_drvdata(dev, clk32k);
+
+       if (pdata && pdata->enable)
+               pdata->enable(dev);
 
        printk(KERN_INFO "Toshiba tc6387xb initialised\n");
 
@@ -134,18 +144,19 @@ static int tc6387xb_probe(struct platform_device *dev)
        if (!ret)
                return 0;
 
+       clk_put(clk32k);
 err_resource:
        return ret;
 }
 
 static int tc6387xb_remove(struct platform_device *dev)
 {
-       struct tc6387xb_platform_data *data = platform_get_drvdata(dev);
-
-       if (data && data->disable)
-               data->disable(dev);
+       struct clk *clk32k = platform_get_drvdata(dev);
 
-       /* FIXME - free the resources! */
+       mfd_remove_devices(&dev->dev);
+       clk_disable(clk32k);
+       clk_put(clk32k);
+       platform_set_drvdata(dev, NULL);
 
        return 0;
 }
index e4c1c788b5f81ffb912bcc96a7630904e036a26c..f856e9463a9f90ed3b9a11913ddf371c09e8a57f 100644 (file)
@@ -113,6 +113,8 @@ struct tc6393xb {
 enum {
        TC6393XB_CELL_NAND,
        TC6393XB_CELL_MMC,
+       TC6393XB_CELL_OHCI,
+       TC6393XB_CELL_FB,
 };
 
 /*--------------------------------------------------------------------------*/
@@ -170,6 +172,176 @@ static struct resource __devinitdata tc6393xb_mmc_resources[] = {
        },
 };
 
+const static struct resource tc6393xb_ohci_resources[] = {
+       {
+               .start  = 0x3000,
+               .end    = 0x31ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = 0x0300,
+               .end    = 0x03ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = 0x010000,
+               .end    = 0x017fff,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = 0x018000,
+               .end    = 0x01ffff,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = IRQ_TC6393_OHCI,
+               .end    = IRQ_TC6393_OHCI,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource __devinitdata tc6393xb_fb_resources[] = {
+       {
+               .start  = 0x5000,
+               .end    = 0x51ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = 0x0500,
+               .end    = 0x05ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = 0x100000,
+               .end    = 0x1fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = IRQ_TC6393_FB,
+               .end    = IRQ_TC6393_FB,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static int tc6393xb_ohci_enable(struct platform_device *dev)
+{
+       struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent);
+       unsigned long flags;
+       u16 ccr;
+       u8 fer;
+
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+
+       ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR);
+       ccr |= SCR_CCR_USBCK;
+       tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR);
+
+       fer = tmio_ioread8(tc6393xb->scr + SCR_FER);
+       fer |= SCR_FER_USBEN;
+       tmio_iowrite8(fer, tc6393xb->scr + SCR_FER);
+
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+
+       return 0;
+}
+
+static int tc6393xb_ohci_disable(struct platform_device *dev)
+{
+       struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent);
+       unsigned long flags;
+       u16 ccr;
+       u8 fer;
+
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+
+       fer = tmio_ioread8(tc6393xb->scr + SCR_FER);
+       fer &= ~SCR_FER_USBEN;
+       tmio_iowrite8(fer, tc6393xb->scr + SCR_FER);
+
+       ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR);
+       ccr &= ~SCR_CCR_USBCK;
+       tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR);
+
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+
+       return 0;
+}
+
+static int tc6393xb_fb_enable(struct platform_device *dev)
+{
+       struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent);
+       unsigned long flags;
+       u16 ccr;
+
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+
+       ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR);
+       ccr &= ~SCR_CCR_MCLK_MASK;
+       ccr |= SCR_CCR_MCLK_48;
+       tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR);
+
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+
+       return 0;
+}
+
+static int tc6393xb_fb_disable(struct platform_device *dev)
+{
+       struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent);
+       unsigned long flags;
+       u16 ccr;
+
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+
+       ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR);
+       ccr &= ~SCR_CCR_MCLK_MASK;
+       ccr |= SCR_CCR_MCLK_OFF;
+       tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR);
+
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+
+       return 0;
+}
+
+int tc6393xb_lcd_set_power(struct platform_device *fb, bool on)
+{
+       struct platform_device *dev = to_platform_device(fb->dev.parent);
+       struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+       u8 fer;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+
+       fer = ioread8(tc6393xb->scr + SCR_FER);
+       if (on)
+               fer |= SCR_FER_SLCDEN;
+       else
+               fer &= ~SCR_FER_SLCDEN;
+       iowrite8(fer, tc6393xb->scr + SCR_FER);
+
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(tc6393xb_lcd_set_power);
+
+int tc6393xb_lcd_mode(struct platform_device *fb,
+                                       const struct fb_videomode *mode) {
+       struct platform_device *dev = to_platform_device(fb->dev.parent);
+       struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+
+       iowrite16(mode->pixclock, tc6393xb->scr + SCR_PLL1CR + 0);
+       iowrite16(mode->pixclock >> 16, tc6393xb->scr + SCR_PLL1CR + 2);
+
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(tc6393xb_lcd_mode);
+
 static struct mfd_cell __devinitdata tc6393xb_cells[] = {
        [TC6393XB_CELL_NAND] = {
                .name = "tmio-nand",
@@ -182,6 +354,24 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = {
                .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources),
                .resources = tc6393xb_mmc_resources,
        },
+       [TC6393XB_CELL_OHCI] = {
+               .name = "tmio-ohci",
+               .num_resources = ARRAY_SIZE(tc6393xb_ohci_resources),
+               .resources = tc6393xb_ohci_resources,
+               .enable = tc6393xb_ohci_enable,
+               .suspend = tc6393xb_ohci_disable,
+               .resume = tc6393xb_ohci_enable,
+               .disable = tc6393xb_ohci_disable,
+       },
+       [TC6393XB_CELL_FB] = {
+               .name = "tmio-fb",
+               .num_resources = ARRAY_SIZE(tc6393xb_fb_resources),
+               .resources = tc6393xb_fb_resources,
+               .enable = tc6393xb_fb_enable,
+               .suspend = tc6393xb_fb_disable,
+               .resume = tc6393xb_fb_enable,
+               .disable = tc6393xb_fb_disable,
+       },
 };
 
 /*--------------------------------------------------------------------------*/
@@ -369,41 +559,12 @@ static void tc6393xb_detach_irq(struct platform_device *dev)
 
 /*--------------------------------------------------------------------------*/
 
-static int tc6393xb_hw_init(struct platform_device *dev)
-{
-       struct tc6393xb_platform_data *tcpd = dev->dev.platform_data;
-       struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
-       int i;
-
-       iowrite8(tc6393xb->suspend_state.fer,   tc6393xb->scr + SCR_FER);
-       iowrite16(tcpd->scr_pll2cr,             tc6393xb->scr + SCR_PLL2CR);
-       iowrite16(tc6393xb->suspend_state.ccr,  tc6393xb->scr + SCR_CCR);
-       iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN |
-                 SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN |
-                 BIT(15),                      tc6393xb->scr + SCR_MCR);
-       iowrite16(tcpd->scr_gper,               tc6393xb->scr + SCR_GPER);
-       iowrite8(0,                             tc6393xb->scr + SCR_IRR);
-       iowrite8(0xbf,                          tc6393xb->scr + SCR_IMR);
-
-       for (i = 0; i < 3; i++) {
-               iowrite8(tc6393xb->suspend_state.gpo_dsr[i],
-                                       tc6393xb->scr + SCR_GPO_DSR(i));
-               iowrite8(tc6393xb->suspend_state.gpo_doecr[i],
-                                       tc6393xb->scr + SCR_GPO_DOECR(i));
-               iowrite8(tc6393xb->suspend_state.gpi_bcr[i],
-                                       tc6393xb->scr + SCR_GPI_BCR(i));
-       }
-
-       return 0;
-}
-
 static int __devinit tc6393xb_probe(struct platform_device *dev)
 {
        struct tc6393xb_platform_data *tcpd = dev->dev.platform_data;
        struct tc6393xb *tc6393xb;
        struct resource *iomem, *rscr;
        int ret, temp;
-       int i;
 
        iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
        if (!iomem)
@@ -458,21 +619,16 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
        if (ret)
                goto err_enable;
 
-       tc6393xb->suspend_state.fer = 0;
-
-       for (i = 0; i < 3; i++) {
-               tc6393xb->suspend_state.gpo_dsr[i] =
-                       (tcpd->scr_gpo_dsr >> (8 * i)) & 0xff;
-               tc6393xb->suspend_state.gpo_doecr[i] =
-                       (tcpd->scr_gpo_doecr >> (8 * i)) & 0xff;
-       }
-
-       tc6393xb->suspend_state.ccr = SCR_CCR_UNK1 |
-                                       SCR_CCR_HCLK_48;
-
-       ret = tc6393xb_hw_init(dev);
-       if (ret)
-               goto err_hw_init;
+       iowrite8(0,                             tc6393xb->scr + SCR_FER);
+       iowrite16(tcpd->scr_pll2cr,             tc6393xb->scr + SCR_PLL2CR);
+       iowrite16(SCR_CCR_UNK1 | SCR_CCR_HCLK_48,
+                                               tc6393xb->scr + SCR_CCR);
+       iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN |
+                 SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN |
+                 BIT(15),                      tc6393xb->scr + SCR_MCR);
+       iowrite16(tcpd->scr_gper,               tc6393xb->scr + SCR_GPER);
+       iowrite8(0,                             tc6393xb->scr + SCR_IRR);
+       iowrite8(0xbf,                          tc6393xb->scr + SCR_IMR);
 
        printk(KERN_INFO "Toshiba tc6393xb revision %d at 0x%08lx, irq %d\n",
                        tmio_ioread8(tc6393xb->scr + SCR_REVID),
@@ -488,16 +644,33 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
 
        tc6393xb_attach_irq(dev);
 
+       if (tcpd->setup) {
+               ret = tcpd->setup(dev);
+               if (ret)
+                       goto err_setup;
+       }
+
        tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data;
        tc6393xb_cells[TC6393XB_CELL_NAND].platform_data =
                &tc6393xb_cells[TC6393XB_CELL_NAND];
        tc6393xb_cells[TC6393XB_CELL_NAND].data_size =
                sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]);
+
        tc6393xb_cells[TC6393XB_CELL_MMC].platform_data =
                &tc6393xb_cells[TC6393XB_CELL_MMC];
        tc6393xb_cells[TC6393XB_CELL_MMC].data_size =
                sizeof(tc6393xb_cells[TC6393XB_CELL_MMC]);
 
+       tc6393xb_cells[TC6393XB_CELL_OHCI].platform_data =
+               &tc6393xb_cells[TC6393XB_CELL_OHCI];
+       tc6393xb_cells[TC6393XB_CELL_OHCI].data_size =
+               sizeof(tc6393xb_cells[TC6393XB_CELL_OHCI]);
+
+       tc6393xb_cells[TC6393XB_CELL_FB].driver_data = tcpd->fb_data;
+       tc6393xb_cells[TC6393XB_CELL_FB].platform_data =
+               &tc6393xb_cells[TC6393XB_CELL_FB];
+       tc6393xb_cells[TC6393XB_CELL_FB].data_size =
+               sizeof(tc6393xb_cells[TC6393XB_CELL_FB]);
 
        ret = mfd_add_devices(&dev->dev, dev->id,
                        tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells),
@@ -506,12 +679,15 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
        if (!ret)
                return 0;
 
+       if (tcpd->teardown)
+               tcpd->teardown(dev);
+
+err_setup:
        tc6393xb_detach_irq(dev);
 
 err_gpio_add:
        if (tc6393xb->gpio.base != -1)
                temp = gpiochip_remove(&tc6393xb->gpio);
-err_hw_init:
        tcpd->disable(dev);
 err_clk_enable:
        clk_disable(tc6393xb->clk);
@@ -535,6 +711,10 @@ static int __devexit tc6393xb_remove(struct platform_device *dev)
        int ret;
 
        mfd_remove_devices(&dev->dev);
+
+       if (tcpd->teardown)
+               tcpd->teardown(dev);
+
        tc6393xb_detach_irq(dev);
 
        if (tc6393xb->gpio.base != -1) {
@@ -585,15 +765,37 @@ static int tc6393xb_resume(struct platform_device *dev)
        struct tc6393xb_platform_data *tcpd = dev->dev.platform_data;
        struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
        int ret;
+       int i;
 
        clk_enable(tc6393xb->clk);
 
        ret = tcpd->resume(dev);
-
        if (ret)
                return ret;
 
-       return tc6393xb_hw_init(dev);
+       if (!tcpd->resume_restore)
+               return 0;
+
+       iowrite8(tc6393xb->suspend_state.fer,   tc6393xb->scr + SCR_FER);
+       iowrite16(tcpd->scr_pll2cr,             tc6393xb->scr + SCR_PLL2CR);
+       iowrite16(tc6393xb->suspend_state.ccr,  tc6393xb->scr + SCR_CCR);
+       iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN |
+                 SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN |
+                 BIT(15),                      tc6393xb->scr + SCR_MCR);
+       iowrite16(tcpd->scr_gper,               tc6393xb->scr + SCR_GPER);
+       iowrite8(0,                             tc6393xb->scr + SCR_IRR);
+       iowrite8(0xbf,                          tc6393xb->scr + SCR_IMR);
+
+       for (i = 0; i < 3; i++) {
+               iowrite8(tc6393xb->suspend_state.gpo_dsr[i],
+                                       tc6393xb->scr + SCR_GPO_DSR(i));
+               iowrite8(tc6393xb->suspend_state.gpo_doecr[i],
+                                       tc6393xb->scr + SCR_GPO_DOECR(i));
+               iowrite8(tc6393xb->suspend_state.gpi_bcr[i],
+                                       tc6393xb->scr + SCR_GPI_BCR(i));
+       }
+
+       return 0;
 }
 #else
 #define tc6393xb_suspend NULL
diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl4030-core.c
new file mode 100644 (file)
index 0000000..fd9a016
--- /dev/null
@@ -0,0 +1,1193 @@
+/*
+ * twl4030_core.c - driver for TWL4030/TPS659x0 PM and audio CODEC devices
+ *
+ * Copyright (C) 2005-2006 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>
+ *
+ * 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/kernel_stat.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/random.h>
+#include <linux/kthread.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c/twl4030.h>
+
+
+/*
+ * The TWL4030 "Triton 2" is one of a family of a multi-function "Power
+ * Management and System Companion Device" chips originally designed for
+ * use in OMAP2 and OMAP 3 based systems.  Its control interfaces use I2C,
+ * often at around 3 Mbit/sec, including for interrupt handling.
+ *
+ * This driver core provides genirq support for the interrupts emitted,
+ * by the various modules, and exports register access primitives.
+ *
+ * FIXME this driver currently requires use of the first interrupt line
+ * (and associated registers).
+ */
+
+#define DRIVER_NAME                    "twl4030"
+
+#if defined(CONFIG_TWL4030_BCI_BATTERY) || \
+       defined(CONFIG_TWL4030_BCI_BATTERY_MODULE)
+#define twl_has_bci()          true
+#else
+#define twl_has_bci()          false
+#endif
+
+#if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE)
+#define twl_has_keypad()       true
+#else
+#define twl_has_keypad()       false
+#endif
+
+#if defined(CONFIG_GPIO_TWL4030) || defined(CONFIG_GPIO_TWL4030_MODULE)
+#define twl_has_gpio() true
+#else
+#define twl_has_gpio() false
+#endif
+
+#if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE)
+#define twl_has_madc() true
+#else
+#define twl_has_madc() false
+#endif
+
+#if defined(CONFIG_RTC_DRV_TWL4030) || defined(CONFIG_RTC_DRV_TWL4030_MODULE)
+#define twl_has_rtc()  true
+#else
+#define twl_has_rtc()  false
+#endif
+
+#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
+#define twl_has_usb()  true
+#else
+#define twl_has_usb()  false
+#endif
+
+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
+}
+
+/* Primary Interrupt Handler on TWL4030 Registers */
+
+/* Register Definitions */
+
+#define REG_PIH_ISR_P1                 (0x1)
+#define REG_PIH_ISR_P2                 (0x2)
+#define REG_PIH_SIR                    (0x3)
+
+/* Triton Core internal information (BEGIN) */
+
+/* Last - for index max*/
+#define TWL4030_MODULE_LAST            TWL4030_MODULE_SECURED_REG
+
+#define TWL4030_NUM_SLAVES             4
+
+
+/* Base Address defns for twl4030_map[] */
+
+/* subchip/slave 0 - USB ID */
+#define TWL4030_BASEADD_USB            0x0000
+
+/* subchip/slave 1 - AUD ID */
+#define TWL4030_BASEADD_AUDIO_VOICE    0x0000
+#define TWL4030_BASEADD_GPIO           0x0098
+#define TWL4030_BASEADD_INTBR          0x0085
+#define TWL4030_BASEADD_PIH            0x0080
+#define TWL4030_BASEADD_TEST           0x004C
+
+/* subchip/slave 2 - AUX ID */
+#define TWL4030_BASEADD_INTERRUPTS     0x00B9
+#define TWL4030_BASEADD_LED            0x00EE
+#define TWL4030_BASEADD_MADC           0x0000
+#define TWL4030_BASEADD_MAIN_CHARGE    0x0074
+#define TWL4030_BASEADD_PRECHARGE      0x00AA
+#define TWL4030_BASEADD_PWM0           0x00F8
+#define TWL4030_BASEADD_PWM1           0x00FB
+#define TWL4030_BASEADD_PWMA           0x00EF
+#define TWL4030_BASEADD_PWMB           0x00F1
+#define TWL4030_BASEADD_KEYPAD         0x00D2
+
+/* subchip/slave 3 - POWER ID */
+#define TWL4030_BASEADD_BACKUP         0x0014
+#define TWL4030_BASEADD_INT            0x002E
+#define TWL4030_BASEADD_PM_MASTER      0x0036
+#define TWL4030_BASEADD_PM_RECEIVER    0x005B
+#define TWL4030_BASEADD_RTC            0x001C
+#define TWL4030_BASEADD_SECURED_REG    0x0000
+
+/* Triton Core internal information (END) */
+
+
+/* Few power values */
+#define R_CFG_BOOT                     0x05
+#define R_PROTECT_KEY                  0x0E
+
+/* access control values for R_PROTECT_KEY */
+#define KEY_UNLOCK1                    0xce
+#define KEY_UNLOCK2                    0xec
+#define KEY_LOCK                       0x00
+
+/* some fields in R_CFG_BOOT */
+#define HFCLK_FREQ_19p2_MHZ            (1 << 0)
+#define HFCLK_FREQ_26_MHZ              (2 << 0)
+#define HFCLK_FREQ_38p4_MHZ            (3 << 0)
+#define HIGH_PERF_SQ                   (1 << 3)
+
+
+/*----------------------------------------------------------------------*/
+
+/**
+ * struct twl4030_mod_iregs - TWL module IMR/ISR regs to mask/clear at init
+ * @mod_no: TWL4030 module number (e.g., TWL4030_MODULE_GPIO)
+ * @sih_ctrl: address of module SIH_CTRL register
+ * @reg_cnt: number of IMR/ISR regs
+ * @imrs: pointer to array of TWL module interrupt mask register indices
+ * @isrs: pointer to array of TWL module interrupt status register indices
+ *
+ * Ties together TWL4030 modules and lists of IMR/ISR registers to mask/clear
+ * during twl_init_irq().
+ */
+struct twl4030_mod_iregs {
+       const u8 mod_no;
+       const u8 sih_ctrl;
+       const u8 reg_cnt;
+       const u8 *imrs;
+       const u8 *isrs;
+};
+
+/* TWL4030 INT module interrupt mask registers */
+static const u8 __initconst twl4030_int_imr_regs[] = {
+       TWL4030_INT_PWR_IMR1,
+       TWL4030_INT_PWR_IMR2,
+};
+
+/* TWL4030 INT module interrupt status registers */
+static const u8 __initconst twl4030_int_isr_regs[] = {
+       TWL4030_INT_PWR_ISR1,
+       TWL4030_INT_PWR_ISR2,
+};
+
+/* TWL4030 INTERRUPTS module interrupt mask registers */
+static const u8 __initconst twl4030_interrupts_imr_regs[] = {
+       TWL4030_INTERRUPTS_BCIIMR1A,
+       TWL4030_INTERRUPTS_BCIIMR1B,
+       TWL4030_INTERRUPTS_BCIIMR2A,
+       TWL4030_INTERRUPTS_BCIIMR2B,
+};
+
+/* TWL4030 INTERRUPTS module interrupt status registers */
+static const u8 __initconst twl4030_interrupts_isr_regs[] = {
+       TWL4030_INTERRUPTS_BCIISR1A,
+       TWL4030_INTERRUPTS_BCIISR1B,
+       TWL4030_INTERRUPTS_BCIISR2A,
+       TWL4030_INTERRUPTS_BCIISR2B,
+};
+
+/* TWL4030 MADC module interrupt mask registers */
+static const u8 __initconst twl4030_madc_imr_regs[] = {
+       TWL4030_MADC_IMR1,
+       TWL4030_MADC_IMR2,
+};
+
+/* TWL4030 MADC module interrupt status registers */
+static const u8 __initconst twl4030_madc_isr_regs[] = {
+       TWL4030_MADC_ISR1,
+       TWL4030_MADC_ISR2,
+};
+
+/* TWL4030 keypad module interrupt mask registers */
+static const u8 __initconst twl4030_keypad_imr_regs[] = {
+       TWL4030_KEYPAD_KEYP_IMR1,
+       TWL4030_KEYPAD_KEYP_IMR2,
+};
+
+/* TWL4030 keypad module interrupt status registers */
+static const u8 __initconst twl4030_keypad_isr_regs[] = {
+       TWL4030_KEYPAD_KEYP_ISR1,
+       TWL4030_KEYPAD_KEYP_ISR2,
+};
+
+/* TWL4030 GPIO module interrupt mask registers */
+static const u8 __initconst twl4030_gpio_imr_regs[] = {
+       REG_GPIO_IMR1A,
+       REG_GPIO_IMR1B,
+       REG_GPIO_IMR2A,
+       REG_GPIO_IMR2B,
+       REG_GPIO_IMR3A,
+       REG_GPIO_IMR3B,
+};
+
+/* TWL4030 GPIO module interrupt status registers */
+static const u8 __initconst twl4030_gpio_isr_regs[] = {
+       REG_GPIO_ISR1A,
+       REG_GPIO_ISR1B,
+       REG_GPIO_ISR2A,
+       REG_GPIO_ISR2B,
+       REG_GPIO_ISR3A,
+       REG_GPIO_ISR3B,
+};
+
+/* TWL4030 modules that have IMR/ISR registers that must be masked/cleared */
+static const struct twl4030_mod_iregs __initconst twl4030_mod_regs[] = {
+       {
+               .mod_no   = TWL4030_MODULE_INT,
+               .sih_ctrl = TWL4030_INT_PWR_SIH_CTRL,
+               .reg_cnt  = ARRAY_SIZE(twl4030_int_imr_regs),
+               .imrs     = twl4030_int_imr_regs,
+               .isrs     = twl4030_int_isr_regs,
+       },
+       {
+               .mod_no   = TWL4030_MODULE_INTERRUPTS,
+               .sih_ctrl = TWL4030_INTERRUPTS_BCISIHCTRL,
+               .reg_cnt  = ARRAY_SIZE(twl4030_interrupts_imr_regs),
+               .imrs     = twl4030_interrupts_imr_regs,
+               .isrs     = twl4030_interrupts_isr_regs,
+       },
+       {
+               .mod_no   = TWL4030_MODULE_MADC,
+               .sih_ctrl = TWL4030_MADC_SIH_CTRL,
+               .reg_cnt  = ARRAY_SIZE(twl4030_madc_imr_regs),
+               .imrs     = twl4030_madc_imr_regs,
+               .isrs     = twl4030_madc_isr_regs,
+       },
+       {
+               .mod_no   = TWL4030_MODULE_KEYPAD,
+               .sih_ctrl = TWL4030_KEYPAD_KEYP_SIH_CTRL,
+               .reg_cnt  = ARRAY_SIZE(twl4030_keypad_imr_regs),
+               .imrs     = twl4030_keypad_imr_regs,
+               .isrs     = twl4030_keypad_isr_regs,
+       },
+       {
+               .mod_no   = TWL4030_MODULE_GPIO,
+               .sih_ctrl = REG_GPIO_SIH_CTRL,
+               .reg_cnt  = ARRAY_SIZE(twl4030_gpio_imr_regs),
+               .imrs     = twl4030_gpio_imr_regs,
+               .isrs     = twl4030_gpio_isr_regs,
+       },
+};
+
+/*----------------------------------------------------------------*/
+
+/* is driver active, bound to a chip? */
+static bool inuse;
+
+/* Structure for each TWL4030 Slave */
+struct twl4030_client {
+       struct i2c_client *client;
+       u8 address;
+
+       /* max numb of i2c_msg required is for read =2 */
+       struct i2c_msg xfer_msg[2];
+
+       /* To lock access to xfer_msg */
+       struct mutex xfer_lock;
+};
+
+static struct twl4030_client twl4030_modules[TWL4030_NUM_SLAVES];
+
+
+/* mapping the module id to slave id and base address */
+struct twl4030mapping {
+       unsigned char sid;      /* Slave ID */
+       unsigned char base;     /* base address */
+};
+
+static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {
+       /*
+        * NOTE:  don't change this table without updating the
+        * <linux/i2c/twl4030.h> defines for TWL4030_MODULE_*
+        * so they continue to match the order in this table.
+        */
+
+       { 0, TWL4030_BASEADD_USB },
+
+       { 1, TWL4030_BASEADD_AUDIO_VOICE },
+       { 1, TWL4030_BASEADD_GPIO },
+       { 1, TWL4030_BASEADD_INTBR },
+       { 1, TWL4030_BASEADD_PIH },
+       { 1, TWL4030_BASEADD_TEST },
+
+       { 2, TWL4030_BASEADD_KEYPAD },
+       { 2, TWL4030_BASEADD_MADC },
+       { 2, TWL4030_BASEADD_INTERRUPTS },
+       { 2, TWL4030_BASEADD_LED },
+       { 2, TWL4030_BASEADD_MAIN_CHARGE },
+       { 2, TWL4030_BASEADD_PRECHARGE },
+       { 2, TWL4030_BASEADD_PWM0 },
+       { 2, TWL4030_BASEADD_PWM1 },
+       { 2, TWL4030_BASEADD_PWMA },
+       { 2, TWL4030_BASEADD_PWMB },
+
+       { 3, TWL4030_BASEADD_BACKUP },
+       { 3, TWL4030_BASEADD_INT },
+       { 3, TWL4030_BASEADD_PM_MASTER },
+       { 3, TWL4030_BASEADD_PM_RECEIVER },
+       { 3, TWL4030_BASEADD_RTC },
+       { 3, TWL4030_BASEADD_SECURED_REG },
+};
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * TWL4030 doesn't have PIH mask, hence dummy function for mask
+ * and unmask of the (eight) interrupts reported at that level ...
+ * masking is only available from SIH (secondary) modules.
+ */
+
+static void twl4030_i2c_ackirq(unsigned int irq)
+{
+}
+
+static void twl4030_i2c_disableint(unsigned int irq)
+{
+}
+
+static void twl4030_i2c_enableint(unsigned int irq)
+{
+}
+
+static struct irq_chip twl4030_irq_chip = {
+       .name   = "twl4030",
+       .ack    = twl4030_i2c_ackirq,
+       .mask   = twl4030_i2c_disableint,
+       .unmask = twl4030_i2c_enableint,
+};
+
+/*----------------------------------------------------------------------*/
+
+/* Exported Functions */
+
+/**
+ * twl4030_i2c_write - Writes a n bit register in TWL4030
+ * @mod_no: module number
+ * @value: an array of num_bytes+1 containing data to write
+ * @reg: register address (just offset will do)
+ * @num_bytes: number of bytes to transfer
+ *
+ * IMPORTANT: for 'value' parameter: Allocate value num_bytes+1 and
+ * valid data starts at Offset 1.
+ *
+ * Returns the result of operation - 0 is success
+ */
+int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, u8 num_bytes)
+{
+       int ret;
+       int sid;
+       struct twl4030_client *twl;
+       struct i2c_msg *msg;
+
+       if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
+               pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
+               return -EPERM;
+       }
+       sid = twl4030_map[mod_no].sid;
+       twl = &twl4030_modules[sid];
+
+       if (unlikely(!inuse)) {
+               pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid);
+               return -EPERM;
+       }
+       mutex_lock(&twl->xfer_lock);
+       /*
+        * [MSG1]: fill the register address data
+        * fill the data Tx buffer
+        */
+       msg = &twl->xfer_msg[0];
+       msg->addr = twl->address;
+       msg->len = num_bytes + 1;
+       msg->flags = 0;
+       msg->buf = value;
+       /* over write the first byte of buffer with the register address */
+       *value = twl4030_map[mod_no].base + reg;
+       ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 1);
+       mutex_unlock(&twl->xfer_lock);
+
+       /* i2cTransfer returns num messages.translate it pls.. */
+       if (ret >= 0)
+               ret = 0;
+       return ret;
+}
+EXPORT_SYMBOL(twl4030_i2c_write);
+
+/**
+ * twl4030_i2c_read - Reads a n bit register in TWL4030
+ * @mod_no: module number
+ * @value: an array of num_bytes containing data to be read
+ * @reg: register address (just offset will do)
+ * @num_bytes: number of bytes to transfer
+ *
+ * Returns result of operation - num_bytes is success else failure.
+ */
+int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, u8 num_bytes)
+{
+       int ret;
+       u8 val;
+       int sid;
+       struct twl4030_client *twl;
+       struct i2c_msg *msg;
+
+       if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
+               pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
+               return -EPERM;
+       }
+       sid = twl4030_map[mod_no].sid;
+       twl = &twl4030_modules[sid];
+
+       if (unlikely(!inuse)) {
+               pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid);
+               return -EPERM;
+       }
+       mutex_lock(&twl->xfer_lock);
+       /* [MSG1] fill the register address data */
+       msg = &twl->xfer_msg[0];
+       msg->addr = twl->address;
+       msg->len = 1;
+       msg->flags = 0; /* Read the register value */
+       val = twl4030_map[mod_no].base + reg;
+       msg->buf = &val;
+       /* [MSG2] fill the data rx buffer */
+       msg = &twl->xfer_msg[1];
+       msg->addr = twl->address;
+       msg->flags = I2C_M_RD;  /* Read the register value */
+       msg->len = num_bytes;   /* only n bytes */
+       msg->buf = value;
+       ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 2);
+       mutex_unlock(&twl->xfer_lock);
+
+       /* i2cTransfer returns num messages.translate it pls.. */
+       if (ret >= 0)
+               ret = 0;
+       return ret;
+}
+EXPORT_SYMBOL(twl4030_i2c_read);
+
+/**
+ * twl4030_i2c_write_u8 - Writes a 8 bit register in TWL4030
+ * @mod_no: module number
+ * @value: the value to be written 8 bit
+ * @reg: register address (just offset will do)
+ *
+ * Returns result of operation - 0 is success
+ */
+int twl4030_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
+{
+
+       /* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */
+       u8 temp_buffer[2] = { 0 };
+       /* offset 1 contains the data */
+       temp_buffer[1] = value;
+       return twl4030_i2c_write(mod_no, temp_buffer, reg, 1);
+}
+EXPORT_SYMBOL(twl4030_i2c_write_u8);
+
+/**
+ * twl4030_i2c_read_u8 - Reads a 8 bit register from TWL4030
+ * @mod_no: module number
+ * @value: the value read 8 bit
+ * @reg: register address (just offset will do)
+ *
+ * Returns result of operation - 0 is success
+ */
+int twl4030_i2c_read_u8(u8 mod_no, u8 *value, u8 reg)
+{
+       return twl4030_i2c_read(mod_no, value, reg, 1);
+}
+EXPORT_SYMBOL(twl4030_i2c_read_u8);
+
+/*----------------------------------------------------------------------*/
+
+static unsigned twl4030_irq_base;
+
+static struct completion irq_event;
+
+/*
+ * This thread processes interrupts reported by the Primary Interrupt Handler.
+ */
+static int twl4030_irq_thread(void *data)
+{
+       long irq = (long)data;
+       irq_desc_t *desc = irq_desc + irq;
+       static unsigned i2c_errors;
+       const static unsigned max_i2c_errors = 100;
+
+       current->flags |= PF_NOFREEZE;
+
+       while (!kthread_should_stop()) {
+               int ret;
+               int module_irq;
+               u8 pih_isr;
+
+               /* 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,
+                                         REG_PIH_ISR_P1);
+               if (ret) {
+                       pr_warning("%s: I2C error %d reading PIH ISR\n",
+                                       DRIVER_NAME, ret);
+                       if (++i2c_errors >= max_i2c_errors) {
+                               printk(KERN_ERR "Maximum I2C error count"
+                                               " exceeded.  Terminating %s.\n",
+                                               __func__);
+                               break;
+                       }
+                       complete(&irq_event);
+                       continue;
+               }
+
+               /* these handlers deal with the relevant SIH irq status */
+               local_irq_disable();
+               for (module_irq = twl4030_irq_base;
+                               pih_isr;
+                               pih_isr >>= 1, module_irq++) {
+                       if (pih_isr & 0x1) {
+                               irq_desc_t *d = irq_desc + module_irq;
+
+                               d->handle_irq(module_irq, d);
+                       }
+               }
+               local_irq_enable();
+
+               desc->chip->unmask(irq);
+       }
+
+       return 0;
+}
+
+/*
+ * do_twl4030_irq() is the desc->handle method for the twl4030 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 twl4030 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 void do_twl4030_irq(unsigned int irq, irq_desc_t *desc)
+{
+       const unsigned int cpu = smp_processor_id();
+
+       /*
+        * Earlier this was desc->triggered = 1;
+        */
+       desc->status |= IRQ_LEVEL;
+
+       /*
+        * Acknowledge, clear _AND_ disable the interrupt.
+        */
+       desc->chip->ack(irq);
+
+       if (!desc->depth) {
+               kstat_cpu(cpu).irqs[irq]++;
+
+               complete(&irq_event);
+       }
+}
+
+static struct task_struct * __init start_twl4030_irq_thread(long irq)
+{
+       struct task_struct *thread;
+
+       init_completion(&irq_event);
+       thread = kthread_run(twl4030_irq_thread, (void *)irq, "twl4030-irq");
+       if (!thread)
+               pr_err("%s: could not create twl4030 irq %ld thread!\n",
+                      DRIVER_NAME, irq);
+
+       return thread;
+}
+
+/*----------------------------------------------------------------------*/
+
+static int add_children(struct twl4030_platform_data *pdata)
+{
+       struct platform_device  *pdev = NULL;
+       struct twl4030_client   *twl = NULL;
+       int                     status = 0;
+
+       if (twl_has_bci() && pdata->bci) {
+               twl = &twl4030_modules[3];
+
+               pdev = platform_device_alloc("twl4030_bci", -1);
+               if (!pdev) {
+                       pr_debug("%s: can't alloc bci dev\n", DRIVER_NAME);
+                       status = -ENOMEM;
+                       goto err;
+               }
+
+               if (status == 0) {
+                       pdev->dev.parent = &twl->client->dev;
+                       status = platform_device_add_data(pdev, pdata->bci,
+                                       sizeof(*pdata->bci));
+                       if (status < 0) {
+                               dev_dbg(&twl->client->dev,
+                                       "can't add bci data, %d\n",
+                                       status);
+                               goto err;
+                       }
+               }
+
+               if (status == 0) {
+                       struct resource r = {
+                               .start = TWL4030_PWRIRQ_CHG_PRES,
+                               .flags = IORESOURCE_IRQ,
+                       };
+
+                       status = platform_device_add_resources(pdev, &r, 1);
+               }
+
+               if (status == 0)
+                       status = platform_device_add(pdev);
+
+               if (status < 0) {
+                       platform_device_put(pdev);
+                       dev_dbg(&twl->client->dev,
+                                       "can't create bci dev, %d\n",
+                                       status);
+                       goto err;
+               }
+       }
+
+       if (twl_has_gpio() && pdata->gpio) {
+               twl = &twl4030_modules[1];
+
+               pdev = platform_device_alloc("twl4030_gpio", -1);
+               if (!pdev) {
+                       pr_debug("%s: can't alloc gpio dev\n", DRIVER_NAME);
+                       status = -ENOMEM;
+                       goto err;
+               }
+
+               /* more driver model init */
+               if (status == 0) {
+                       pdev->dev.parent = &twl->client->dev;
+                       /* device_init_wakeup(&pdev->dev, 1); */
+
+                       status = platform_device_add_data(pdev, pdata->gpio,
+                                       sizeof(*pdata->gpio));
+                       if (status < 0) {
+                               dev_dbg(&twl->client->dev,
+                                       "can't add gpio data, %d\n",
+                                       status);
+                               goto err;
+                       }
+               }
+
+               /* GPIO module IRQ */
+               if (status == 0) {
+                       struct resource r = {
+                               .start = pdata->irq_base + 0,
+                               .flags = IORESOURCE_IRQ,
+                       };
+
+                       status = platform_device_add_resources(pdev, &r, 1);
+               }
+
+               if (status == 0)
+                       status = platform_device_add(pdev);
+
+               if (status < 0) {
+                       platform_device_put(pdev);
+                       dev_dbg(&twl->client->dev,
+                                       "can't create gpio dev, %d\n",
+                                       status);
+                       goto err;
+               }
+       }
+
+       if (twl_has_keypad() && pdata->keypad) {
+               pdev = platform_device_alloc("twl4030_keypad", -1);
+               if (pdev) {
+                       twl = &twl4030_modules[2];
+                       pdev->dev.parent = &twl->client->dev;
+                       device_init_wakeup(&pdev->dev, 1);
+                       status = platform_device_add_data(pdev, pdata->keypad,
+                                       sizeof(*pdata->keypad));
+                       if (status < 0) {
+                               dev_dbg(&twl->client->dev,
+                                       "can't add keypad data, %d\n",
+                                       status);
+                               platform_device_put(pdev);
+                               goto err;
+                       }
+                       status = platform_device_add(pdev);
+                       if (status < 0) {
+                               platform_device_put(pdev);
+                               dev_dbg(&twl->client->dev,
+                                               "can't create keypad dev, %d\n",
+                                               status);
+                               goto err;
+                       }
+               } else {
+                       pr_debug("%s: can't alloc keypad dev\n", DRIVER_NAME);
+                       status = -ENOMEM;
+                       goto err;
+               }
+       }
+
+       if (twl_has_madc() && pdata->madc) {
+               pdev = platform_device_alloc("twl4030_madc", -1);
+               if (pdev) {
+                       twl = &twl4030_modules[2];
+                       pdev->dev.parent = &twl->client->dev;
+                       device_init_wakeup(&pdev->dev, 1);
+                       status = platform_device_add_data(pdev, pdata->madc,
+                                       sizeof(*pdata->madc));
+                       if (status < 0) {
+                               platform_device_put(pdev);
+                               dev_dbg(&twl->client->dev,
+                                       "can't add madc data, %d\n",
+                                       status);
+                               goto err;
+                       }
+                       status = platform_device_add(pdev);
+                       if (status < 0) {
+                               platform_device_put(pdev);
+                               dev_dbg(&twl->client->dev,
+                                               "can't create madc dev, %d\n",
+                                               status);
+                               goto err;
+                       }
+               } else {
+                       pr_debug("%s: can't alloc madc dev\n", DRIVER_NAME);
+                       status = -ENOMEM;
+                       goto err;
+               }
+       }
+
+       if (twl_has_rtc()) {
+               twl = &twl4030_modules[3];
+
+               pdev = platform_device_alloc("twl4030_rtc", -1);
+               if (!pdev) {
+                       pr_debug("%s: can't alloc rtc dev\n", DRIVER_NAME);
+                       status = -ENOMEM;
+               } else {
+                       pdev->dev.parent = &twl->client->dev;
+                       device_init_wakeup(&pdev->dev, 1);
+               }
+
+               /*
+                * REVISIT platform_data here currently might use of
+                * "msecure" line ... but for now we just expect board
+                * setup to tell the chip "we are secure" at all times.
+                * Eventually, Linux might become more aware of such
+                * HW security concerns, and "least privilege".
+                */
+
+               /* RTC module IRQ */
+               if (status == 0) {
+                       struct resource r = {
+                               /* REVISIT don't hard-wire this stuff */
+                               .start = TWL4030_PWRIRQ_RTC,
+                               .flags = IORESOURCE_IRQ,
+                       };
+
+                       status = platform_device_add_resources(pdev, &r, 1);
+               }
+
+               if (status == 0)
+                       status = platform_device_add(pdev);
+
+               if (status < 0) {
+                       platform_device_put(pdev);
+                       dev_dbg(&twl->client->dev,
+                                       "can't create rtc dev, %d\n",
+                                       status);
+                       goto err;
+               }
+       }
+
+       if (twl_has_usb() && pdata->usb) {
+               twl = &twl4030_modules[0];
+
+               pdev = platform_device_alloc("twl4030_usb", -1);
+               if (!pdev) {
+                       pr_debug("%s: can't alloc usb dev\n", DRIVER_NAME);
+                       status = -ENOMEM;
+                       goto err;
+               }
+
+               if (status == 0) {
+                       pdev->dev.parent = &twl->client->dev;
+                       device_init_wakeup(&pdev->dev, 1);
+                       status = platform_device_add_data(pdev, pdata->usb,
+                                       sizeof(*pdata->usb));
+                       if (status < 0) {
+                               platform_device_put(pdev);
+                               dev_dbg(&twl->client->dev,
+                                       "can't add usb data, %d\n",
+                                       status);
+                               goto err;
+                       }
+               }
+
+               if (status == 0) {
+                       struct resource r = {
+                               .start = TWL4030_PWRIRQ_USB_PRES,
+                               .flags = IORESOURCE_IRQ,
+                       };
+
+                       status = platform_device_add_resources(pdev, &r, 1);
+               }
+
+               if (status == 0)
+                       status = platform_device_add(pdev);
+
+               if (status < 0) {
+                       platform_device_put(pdev);
+                       dev_dbg(&twl->client->dev,
+                                       "can't create usb dev, %d\n",
+                                       status);
+               }
+       }
+
+err:
+       if (status)
+               pr_err("failed to add twl4030's children (status %d)\n", status);
+       return status;
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * These three functions initialize the on-chip clock framework,
+ * letting it generate the right frequencies for USB, MADC, and
+ * other purposes.
+ */
+static inline int __init protect_pm_master(void)
+{
+       int e = 0;
+
+       e = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_LOCK,
+                       R_PROTECT_KEY);
+       return e;
+}
+
+static inline int __init unprotect_pm_master(void)
+{
+       int e = 0;
+
+       e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK1,
+                       R_PROTECT_KEY);
+       e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK2,
+                       R_PROTECT_KEY);
+       return e;
+}
+
+static void __init clocks_init(void)
+{
+       int e = 0;
+       struct clk *osc;
+       u32 rate;
+       u8 ctrl = HFCLK_FREQ_26_MHZ;
+
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+       if (cpu_is_omap2430())
+               osc = clk_get(NULL, "osc_ck");
+       else
+               osc = clk_get(NULL, "osc_sys_ck");
+#else
+       /* REVISIT for non-OMAP systems, pass the clock rate from
+        * board init code, using platform_data.
+        */
+       osc = ERR_PTR(-EIO);
+#endif
+       if (IS_ERR(osc)) {
+               printk(KERN_WARNING "Skipping twl4030 internal clock init and "
+                               "using bootloader value (unknown osc rate)\n");
+               return;
+       }
+
+       rate = clk_get_rate(osc);
+       clk_put(osc);
+
+       switch (rate) {
+       case 19200000:
+               ctrl = HFCLK_FREQ_19p2_MHZ;
+               break;
+       case 26000000:
+               ctrl = HFCLK_FREQ_26_MHZ;
+               break;
+       case 38400000:
+               ctrl = HFCLK_FREQ_38p4_MHZ;
+               break;
+       }
+
+       ctrl |= HIGH_PERF_SQ;
+       e |= unprotect_pm_master();
+       /* effect->MADC+USB ck en */
+       e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, ctrl, R_CFG_BOOT);
+       e |= protect_pm_master();
+
+       if (e < 0)
+               pr_err("%s: clock init err [%d]\n", DRIVER_NAME, e);
+}
+
+/*----------------------------------------------------------------------*/
+
+/**
+ * twl4030_i2c_clear_isr - clear TWL4030 SIH ISR regs via read + write
+ * @mod_no: TWL4030 module number
+ * @reg: register index to clear
+ * @cor: value of the <module>_SIH_CTRL.COR bit (1 or 0)
+ *
+ * Either reads (cor == 1) or writes (cor == 0) to a TWL4030 interrupt
+ * status register to ensure that any prior interrupts are cleared.
+ * Returns the status from the I2C read operation.
+ */
+static int __init twl4030_i2c_clear_isr(u8 mod_no, u8 reg, u8 cor)
+{
+       u8 tmp;
+
+       return (cor) ? twl4030_i2c_read_u8(mod_no, &tmp, reg) :
+               twl4030_i2c_write_u8(mod_no, 0xff, reg);
+}
+
+/**
+ * twl4030_read_cor_bit - are TWL module ISRs cleared by reads or writes?
+ * @mod_no: TWL4030 module number
+ * @reg: register index to clear
+ *
+ * Returns 1 if the TWL4030 SIH interrupt status registers (ISRs) for
+ * the specified TWL module are cleared by reads, or 0 if cleared by
+ * writes.
+ */
+static int twl4030_read_cor_bit(u8 mod_no, u8 reg)
+{
+       u8 tmp = 0;
+
+       WARN_ON(twl4030_i2c_read_u8(mod_no, &tmp, reg) < 0);
+
+       tmp &= TWL4030_SIH_CTRL_COR_MASK;
+       tmp >>= __ffs(TWL4030_SIH_CTRL_COR_MASK);
+
+       return tmp;
+}
+
+/**
+ * twl4030_mask_clear_intrs - mask and clear all TWL4030 interrupts
+ * @t: pointer to twl4030_mod_iregs array
+ * @t_sz: ARRAY_SIZE(t) (starting at 1)
+ *
+ * Mask all TWL4030 interrupt mask registers (IMRs) and clear all
+ * interrupt status registers (ISRs).  No return value, but will WARN if
+ * any I2C operations fail.
+ */
+static void __init twl4030_mask_clear_intrs(const struct twl4030_mod_iregs *t,
+                                           const u8 t_sz)
+{
+       int i, j;
+
+       /*
+        * N.B. - further efficiency is possible here.  Eight I2C
+        * operations on BCI and GPIO modules are avoidable if I2C
+        * burst read/write transactions were implemented.  Would
+        * probably save about 1ms of boot time and a small amount of
+        * power.
+        */
+       for (i = 0; i < t_sz; i++) {
+               const struct twl4030_mod_iregs tmr = t[i];
+               int cor;
+
+               /* Are ISRs cleared by reads or writes? */
+               cor = twl4030_read_cor_bit(tmr.mod_no, tmr.sih_ctrl);
+
+               for (j = 0; j < tmr.reg_cnt; j++) {
+
+                       /* Mask interrupts at the TWL4030 */
+                       WARN_ON(twl4030_i2c_write_u8(tmr.mod_no, 0xff,
+                                                    tmr.imrs[j]) < 0);
+
+                       /* Clear TWL4030 ISRs */
+                       WARN_ON(twl4030_i2c_clear_isr(tmr.mod_no,
+                                                     tmr.isrs[j], cor) < 0);
+               }
+       }
+}
+
+
+static void twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
+{
+       int     i;
+
+       /*
+        * Mask and clear all TWL4030 interrupts since initially we do
+        * not have any TWL4030 module interrupt handlers present
+        */
+       twl4030_mask_clear_intrs(twl4030_mod_regs,
+                                ARRAY_SIZE(twl4030_mod_regs));
+
+       twl4030_irq_base = irq_base;
+
+       /* install an irq handler for each of the PIH modules */
+       for (i = irq_base; i < irq_end; i++) {
+               set_irq_chip_and_handler(i, &twl4030_irq_chip,
+                               handle_simple_irq);
+               activate_irq(i);
+       }
+
+       /* install an irq handler to demultiplex the TWL4030 interrupt */
+       set_irq_data(irq_num, start_twl4030_irq_thread(irq_num));
+       set_irq_chained_handler(irq_num, do_twl4030_irq);
+}
+
+/*----------------------------------------------------------------------*/
+
+static int twl4030_remove(struct i2c_client *client)
+{
+       unsigned i;
+
+       /* FIXME undo twl_init_irq() */
+       if (twl4030_irq_base) {
+               dev_err(&client->dev, "can't yet clean up IRQs?\n");
+               return -ENOSYS;
+       }
+
+       for (i = 0; i < TWL4030_NUM_SLAVES; i++) {
+               struct twl4030_client   *twl = &twl4030_modules[i];
+
+               if (twl->client && twl->client != client)
+                       i2c_unregister_device(twl->client);
+               twl4030_modules[i].client = NULL;
+       }
+       inuse = false;
+       return 0;
+}
+
+/* NOTE:  this driver only handles a single twl4030/tps659x0 chip */
+static int
+twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       int                             status;
+       unsigned                        i;
+       struct twl4030_platform_data    *pdata = client->dev.platform_data;
+
+       if (!pdata) {
+               dev_dbg(&client->dev, "no platform data?\n");
+               return -EINVAL;
+       }
+
+       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
+               dev_dbg(&client->dev, "can't talk I2C?\n");
+               return -EIO;
+       }
+
+       if (inuse || twl4030_irq_base) {
+               dev_dbg(&client->dev, "driver is already in use\n");
+               return -EBUSY;
+       }
+
+       for (i = 0; i < TWL4030_NUM_SLAVES; i++) {
+               struct twl4030_client   *twl = &twl4030_modules[i];
+
+               twl->address = client->addr + i;
+               if (i == 0)
+                       twl->client = client;
+               else {
+                       twl->client = i2c_new_dummy(client->adapter,
+                                       twl->address);
+                       if (!twl->client) {
+                               dev_err(&twl->client->dev,
+                                       "can't attach client %d\n", i);
+                               status = -ENOMEM;
+                               goto fail;
+                       }
+                       strlcpy(twl->client->name, id->name,
+                                       sizeof(twl->client->name));
+               }
+               mutex_init(&twl->xfer_lock);
+       }
+       inuse = true;
+
+       /* setup clock framework */
+       clocks_init();
+
+       /* Maybe init the T2 Interrupt subsystem */
+       if (client->irq
+                       && pdata->irq_base
+                       && pdata->irq_end > pdata->irq_base) {
+               twl_init_irq(client->irq, pdata->irq_base, pdata->irq_end);
+               dev_info(&client->dev, "IRQ %d chains IRQs %d..%d\n",
+                               client->irq, pdata->irq_base, pdata->irq_end - 1);
+       }
+
+       status = add_children(pdata);
+fail:
+       if (status < 0)
+               twl4030_remove(client);
+       return status;
+}
+
+static const struct i2c_device_id twl4030_ids[] = {
+       { "twl4030", 0 },       /* "Triton 2" */
+       { "tps65950", 0 },      /* catalog version of twl4030 */
+       { "tps65930", 0 },      /* fewer LDOs and DACs; no charger */
+       { "tps65920", 0 },      /* fewer LDOs; no codec or charger */
+       { "twl5030", 0 },       /* T2 updated */
+       { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(i2c, twl4030_ids);
+
+/* One Client Driver , 4 Clients */
+static struct i2c_driver twl4030_driver = {
+       .driver.name    = DRIVER_NAME,
+       .id_table       = twl4030_ids,
+       .probe          = twl4030_probe,
+       .remove         = twl4030_remove,
+};
+
+static int __init twl4030_init(void)
+{
+       return i2c_add_driver(&twl4030_driver);
+}
+subsys_initcall(twl4030_init);
+
+static void __exit twl4030_exit(void)
+{
+       i2c_del_driver(&twl4030_driver);
+}
+module_exit(twl4030_exit);
+
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("I2C Core interface for TWL4030");
+MODULE_LICENSE("GPL");
index 25a7a5d08bce3bf8867c9f48eeda555df6a88a7f..bf87f675e7fa8a523be49287d9d99354ad6e31e3 100644 (file)
@@ -1217,7 +1217,7 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
 
        mutex_init(&wm8350->irq_mutex);
        INIT_WORK(&wm8350->irq_work, wm8350_irq_worker);
-       if (irq != NO_IRQ) {
+       if (irq) {
                ret = request_irq(irq, wm8350_irq, 0,
                                  "wm8350", wm8350);
                if (ret != 0) {
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
new file mode 100644 (file)
index 0000000..cdb4531
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * twl4030.h - header for TWL4030 PM and audio CODEC device
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * Based on tlv320aic23.c:
+ * Copyright (c) by Kai Svahn <kai.svahn@nokia.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
+ *
+ */
+
+#ifndef __TWL4030_H_
+#define __TWL4030_H_
+
+/*
+ * Using the twl4030 core we address registers using a pair
+ *     { module id, relative register offset }
+ * which that core then maps to the relevant
+ *     { i2c slave, absolute register address }
+ *
+ * The module IDs are meaningful only to the twl4030 core code,
+ * which uses them as array indices to look up the first register
+ * address each module uses within a given i2c slave.
+ */
+
+/* Slave 0 (i2c address 0x48) */
+#define TWL4030_MODULE_USB             0x00
+
+/* Slave 1 (i2c address 0x49) */
+#define TWL4030_MODULE_AUDIO_VOICE     0x01
+#define TWL4030_MODULE_GPIO            0x02
+#define TWL4030_MODULE_INTBR           0x03
+#define TWL4030_MODULE_PIH             0x04
+#define TWL4030_MODULE_TEST            0x05
+
+/* Slave 2 (i2c address 0x4a) */
+#define TWL4030_MODULE_KEYPAD          0x06
+#define TWL4030_MODULE_MADC            0x07
+#define TWL4030_MODULE_INTERRUPTS      0x08
+#define TWL4030_MODULE_LED             0x09
+#define TWL4030_MODULE_MAIN_CHARGE     0x0A
+#define TWL4030_MODULE_PRECHARGE       0x0B
+#define TWL4030_MODULE_PWM0            0x0C
+#define TWL4030_MODULE_PWM1            0x0D
+#define TWL4030_MODULE_PWMA            0x0E
+#define TWL4030_MODULE_PWMB            0x0F
+
+/* Slave 3 (i2c address 0x4b) */
+#define TWL4030_MODULE_BACKUP          0x10
+#define TWL4030_MODULE_INT             0x11
+#define TWL4030_MODULE_PM_MASTER       0x12
+#define TWL4030_MODULE_PM_RECEIVER     0x13
+#define TWL4030_MODULE_RTC             0x14
+#define TWL4030_MODULE_SECURED_REG     0x15
+
+/*
+ * Read and write single 8-bit registers
+ */
+int twl4030_i2c_write_u8(u8 mod_no, u8 val, u8 reg);
+int twl4030_i2c_read_u8(u8 mod_no, u8 *val, u8 reg);
+
+/*
+ * Read and write several 8-bit registers at once.
+ *
+ * IMPORTANT:  For twl4030_i2c_write(), allocate num_bytes + 1
+ * for the value, and populate your data starting at offset 1.
+ */
+int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, u8 num_bytes);
+int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, u8 num_bytes);
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * NOTE:  at up to 1024 registers, this is a big chip.
+ *
+ * Avoid putting register declarations in this file, instead of into
+ * a driver-private file, unless some of the registers in a block
+ * need to be shared with other drivers.  One example is blocks that
+ * have Secondary IRQ Handler (SIH) registers.
+ */
+
+#define TWL4030_SIH_CTRL_EXCLEN_MASK   BIT(0)
+#define TWL4030_SIH_CTRL_PENDDIS_MASK  BIT(1)
+#define TWL4030_SIH_CTRL_COR_MASK      BIT(2)
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * GPIO Block Register offsets (use TWL4030_MODULE_GPIO)
+ */
+
+#define REG_GPIODATAIN1                        0x0
+#define REG_GPIODATAIN2                        0x1
+#define REG_GPIODATAIN3                        0x2
+#define REG_GPIODATADIR1               0x3
+#define REG_GPIODATADIR2               0x4
+#define REG_GPIODATADIR3               0x5
+#define REG_GPIODATAOUT1               0x6
+#define REG_GPIODATAOUT2               0x7
+#define REG_GPIODATAOUT3               0x8
+#define REG_CLEARGPIODATAOUT1          0x9
+#define REG_CLEARGPIODATAOUT2          0xA
+#define REG_CLEARGPIODATAOUT3          0xB
+#define REG_SETGPIODATAOUT1            0xC
+#define REG_SETGPIODATAOUT2            0xD
+#define REG_SETGPIODATAOUT3            0xE
+#define REG_GPIO_DEBEN1                        0xF
+#define REG_GPIO_DEBEN2                        0x10
+#define REG_GPIO_DEBEN3                        0x11
+#define REG_GPIO_CTRL                  0x12
+#define REG_GPIOPUPDCTR1               0x13
+#define REG_GPIOPUPDCTR2               0x14
+#define REG_GPIOPUPDCTR3               0x15
+#define REG_GPIOPUPDCTR4               0x16
+#define REG_GPIOPUPDCTR5               0x17
+#define REG_GPIO_ISR1A                 0x19
+#define REG_GPIO_ISR2A                 0x1A
+#define REG_GPIO_ISR3A                 0x1B
+#define REG_GPIO_IMR1A                 0x1C
+#define REG_GPIO_IMR2A                 0x1D
+#define REG_GPIO_IMR3A                 0x1E
+#define REG_GPIO_ISR1B                 0x1F
+#define REG_GPIO_ISR2B                 0x20
+#define REG_GPIO_ISR3B                 0x21
+#define REG_GPIO_IMR1B                 0x22
+#define REG_GPIO_IMR2B                 0x23
+#define REG_GPIO_IMR3B                 0x24
+#define REG_GPIO_EDR1                  0x28
+#define REG_GPIO_EDR2                  0x29
+#define REG_GPIO_EDR3                  0x2A
+#define REG_GPIO_EDR4                  0x2B
+#define REG_GPIO_EDR5                  0x2C
+#define REG_GPIO_SIH_CTRL              0x2D
+
+/* Up to 18 signals are available as GPIOs, when their
+ * pins are not assigned to another use (such as ULPI/USB).
+ */
+#define TWL4030_GPIO_MAX               18
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Keypad register offsets (use TWL4030_MODULE_KEYPAD)
+ * ... SIH/interrupt only
+ */
+
+#define TWL4030_KEYPAD_KEYP_ISR1       0x11
+#define TWL4030_KEYPAD_KEYP_IMR1       0x12
+#define TWL4030_KEYPAD_KEYP_ISR2       0x13
+#define TWL4030_KEYPAD_KEYP_IMR2       0x14
+#define TWL4030_KEYPAD_KEYP_SIR                0x15    /* test register */
+#define TWL4030_KEYPAD_KEYP_EDR                0x16
+#define TWL4030_KEYPAD_KEYP_SIH_CTRL   0x17
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Multichannel ADC register offsets (use TWL4030_MODULE_MADC)
+ * ... SIH/interrupt only
+ */
+
+#define TWL4030_MADC_ISR1              0x61
+#define TWL4030_MADC_IMR1              0x62
+#define TWL4030_MADC_ISR2              0x63
+#define TWL4030_MADC_IMR2              0x64
+#define TWL4030_MADC_SIR               0x65    /* test register */
+#define TWL4030_MADC_EDR               0x66
+#define TWL4030_MADC_SIH_CTRL          0x67
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Battery charger register offsets (use TWL4030_MODULE_INTERRUPTS)
+ */
+
+#define TWL4030_INTERRUPTS_BCIISR1A    0x0
+#define TWL4030_INTERRUPTS_BCIISR2A    0x1
+#define TWL4030_INTERRUPTS_BCIIMR1A    0x2
+#define TWL4030_INTERRUPTS_BCIIMR2A    0x3
+#define TWL4030_INTERRUPTS_BCIISR1B    0x4
+#define TWL4030_INTERRUPTS_BCIISR2B    0x5
+#define TWL4030_INTERRUPTS_BCIIMR1B    0x6
+#define TWL4030_INTERRUPTS_BCIIMR2B    0x7
+#define TWL4030_INTERRUPTS_BCISIR1     0x8     /* test register */
+#define TWL4030_INTERRUPTS_BCISIR2     0x9     /* test register */
+#define TWL4030_INTERRUPTS_BCIEDR1     0xa
+#define TWL4030_INTERRUPTS_BCIEDR2     0xb
+#define TWL4030_INTERRUPTS_BCIEDR3     0xc
+#define TWL4030_INTERRUPTS_BCISIHCTRL  0xd
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Power Interrupt block register offsets (use TWL4030_MODULE_INT)
+ */
+
+#define TWL4030_INT_PWR_ISR1           0x0
+#define TWL4030_INT_PWR_IMR1           0x1
+#define TWL4030_INT_PWR_ISR2           0x2
+#define TWL4030_INT_PWR_IMR2           0x3
+#define TWL4030_INT_PWR_SIR            0x4     /* test register */
+#define TWL4030_INT_PWR_EDR1           0x5
+#define TWL4030_INT_PWR_EDR2           0x6
+#define TWL4030_INT_PWR_SIH_CTRL       0x7
+
+/*----------------------------------------------------------------------*/
+
+struct twl4030_bci_platform_data {
+       int *battery_tmp_tbl;
+       unsigned int tblsize;
+};
+
+/* TWL4030_GPIO_MAX (18) GPIOs, with interrupts */
+struct twl4030_gpio_platform_data {
+       int             gpio_base;
+       unsigned        irq_base, irq_end;
+
+       /* For gpio-N, bit (1 << N) in "pullups" is set if that pullup
+        * should be enabled.  Else, if that bit is set in "pulldowns",
+        * that pulldown is enabled.  Don't waste power by letting any
+        * digital inputs float...
+        */
+       u32             pullups;
+       u32             pulldowns;
+
+       int             (*setup)(struct device *dev,
+                               unsigned gpio, unsigned ngpio);
+       int             (*teardown)(struct device *dev,
+                               unsigned gpio, unsigned ngpio);
+};
+
+struct twl4030_madc_platform_data {
+       int             irq_line;
+};
+
+struct twl4030_keypad_data {
+       int rows;
+       int cols;
+       int *keymap;
+       int irq;
+       unsigned int keymapsize;
+       unsigned int rep:1;
+};
+
+enum twl4030_usb_mode {
+       T2_USB_MODE_ULPI = 1,
+       T2_USB_MODE_CEA2011_3PIN = 2,
+};
+
+struct twl4030_usb_data {
+       enum twl4030_usb_mode   usb_mode;
+};
+
+struct twl4030_platform_data {
+       unsigned                                irq_base, irq_end;
+       struct twl4030_bci_platform_data        *bci;
+       struct twl4030_gpio_platform_data       *gpio;
+       struct twl4030_madc_platform_data       *madc;
+       struct twl4030_keypad_data              *keypad;
+       struct twl4030_usb_data                 *usb;
+
+       /* REVISIT more to come ... _nothing_ should be hard-wired */
+};
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * FIXME completely stop using TWL4030_IRQ_BASE ... instead, pass the
+ * IRQ data to subsidiary devices using platform device resources.
+ */
+
+/* IRQ information-need base */
+#include <mach/irqs.h>
+/* TWL4030 interrupts */
+
+/* #define TWL4030_MODIRQ_GPIO         (TWL4030_IRQ_BASE + 0) */
+#define TWL4030_MODIRQ_KEYPAD          (TWL4030_IRQ_BASE + 1)
+#define TWL4030_MODIRQ_BCI             (TWL4030_IRQ_BASE + 2)
+#define TWL4030_MODIRQ_MADC            (TWL4030_IRQ_BASE + 3)
+/* #define TWL4030_MODIRQ_USB          (TWL4030_IRQ_BASE + 4) */
+#define TWL4030_MODIRQ_PWR             (TWL4030_IRQ_BASE + 5)
+
+#define TWL4030_PWRIRQ_PWRBTN          (TWL4030_PWR_IRQ_BASE + 0)
+#define TWL4030_PWRIRQ_CHG_PRES                (TWL4030_PWR_IRQ_BASE + 1)
+#define TWL4030_PWRIRQ_USB_PRES                (TWL4030_PWR_IRQ_BASE + 2)
+#define TWL4030_PWRIRQ_RTC             (TWL4030_PWR_IRQ_BASE + 3)
+#define TWL4030_PWRIRQ_HOT_DIE         (TWL4030_PWR_IRQ_BASE + 4)
+#define TWL4030_PWRIRQ_PWROK_TIMEOUT   (TWL4030_PWR_IRQ_BASE + 5)
+#define TWL4030_PWRIRQ_MBCHG           (TWL4030_PWR_IRQ_BASE + 6)
+#define TWL4030_PWRIRQ_SC_DETECT       (TWL4030_PWR_IRQ_BASE + 7)
+
+/* Rest are unsued currently*/
+
+/* Offsets to Power Registers */
+#define TWL4030_VDAC_DEV_GRP           0x3B
+#define TWL4030_VDAC_DEDICATED         0x3E
+#define TWL4030_VAUX1_DEV_GRP          0x17
+#define TWL4030_VAUX1_DEDICATED                0x1A
+#define TWL4030_VAUX2_DEV_GRP          0x1B
+#define TWL4030_VAUX2_DEDICATED                0x1E
+#define TWL4030_VAUX3_DEV_GRP          0x1F
+#define TWL4030_VAUX3_DEDICATED                0x22
+
+/* TWL4030 GPIO interrupt definitions */
+
+#define TWL4030_GPIO_IRQ_NO(n)         (TWL4030_GPIO_IRQ_BASE + (n))
+#define TWL4030_GPIO_IS_ENABLE         1
+
+/*
+ * Exported TWL4030 GPIO APIs
+ *
+ * WARNING -- use standard GPIO and IRQ calls instead; these will vanish.
+ */
+int twl4030_get_gpio_datain(int gpio);
+int twl4030_request_gpio(int gpio);
+int twl4030_set_gpio_debounce(int gpio, int enable);
+int twl4030_free_gpio(int gpio);
+
+#if defined(CONFIG_TWL4030_BCI_BATTERY) || \
+       defined(CONFIG_TWL4030_BCI_BATTERY_MODULE)
+       extern int twl4030charger_usb_en(int enable);
+#else
+       static inline int twl4030charger_usb_en(int enable) { return 0; }
+#endif
+
+#endif /* End of __TWL4030_H */
diff --git a/include/linux/mfd/da903x.h b/include/linux/mfd/da903x.h
new file mode 100644 (file)
index 0000000..cad314c
--- /dev/null
@@ -0,0 +1,201 @@
+#ifndef __LINUX_PMIC_DA903X_H
+#define __LINUX_PMIC_DA903X_H
+
+/* Unified sub device IDs for DA9030/DA9034 */
+enum {
+       DA9030_ID_LED_1,
+       DA9030_ID_LED_2,
+       DA9030_ID_LED_3,
+       DA9030_ID_LED_4,
+       DA9030_ID_LED_PC,
+       DA9030_ID_VIBRA,
+       DA9030_ID_WLED,
+       DA9030_ID_BUCK1,
+       DA9030_ID_BUCK2,
+       DA9030_ID_LDO1,
+       DA9030_ID_LDO2,
+       DA9030_ID_LDO3,
+       DA9030_ID_LDO4,
+       DA9030_ID_LDO5,
+       DA9030_ID_LDO6,
+       DA9030_ID_LDO7,
+       DA9030_ID_LDO8,
+       DA9030_ID_LDO9,
+       DA9030_ID_LDO10,
+       DA9030_ID_LDO11,
+       DA9030_ID_LDO12,
+       DA9030_ID_LDO13,
+       DA9030_ID_LDO14,
+       DA9030_ID_LDO15,
+       DA9030_ID_LDO16,
+       DA9030_ID_LDO17,
+       DA9030_ID_LDO18,
+       DA9030_ID_LDO19,
+       DA9030_ID_LDO_INT,      /* LDO Internal */
+
+       DA9034_ID_LED_1,
+       DA9034_ID_LED_2,
+       DA9034_ID_VIBRA,
+       DA9034_ID_WLED,
+       DA9034_ID_TOUCH,
+
+       DA9034_ID_BUCK1,
+       DA9034_ID_BUCK2,
+       DA9034_ID_LDO1,
+       DA9034_ID_LDO2,
+       DA9034_ID_LDO3,
+       DA9034_ID_LDO4,
+       DA9034_ID_LDO5,
+       DA9034_ID_LDO6,
+       DA9034_ID_LDO7,
+       DA9034_ID_LDO8,
+       DA9034_ID_LDO9,
+       DA9034_ID_LDO10,
+       DA9034_ID_LDO11,
+       DA9034_ID_LDO12,
+       DA9034_ID_LDO13,
+       DA9034_ID_LDO14,
+       DA9034_ID_LDO15,
+};
+
+/*
+ * DA9030/DA9034 LEDs sub-devices uses generic "struct led_info"
+ * as the platform_data
+ */
+
+/* DA9030 flags for "struct led_info"
+ */
+#define DA9030_LED_RATE_ON     (0 << 5)
+#define DA9030_LED_RATE_052S   (1 << 5)
+#define DA9030_LED_DUTY_1_16   (0 << 3)
+#define DA9030_LED_DUTY_1_8    (1 << 3)
+#define DA9030_LED_DUTY_1_4    (2 << 3)
+#define DA9030_LED_DUTY_1_2    (3 << 3)
+
+#define DA9030_VIBRA_MODE_1P3V (0 << 1)
+#define DA9030_VIBRA_MODE_2P7V (1 << 1)
+#define DA9030_VIBRA_FREQ_1HZ  (0 << 2)
+#define DA9030_VIBRA_FREQ_2HZ  (1 << 2)
+#define DA9030_VIBRA_FREQ_4HZ  (2 << 2)
+#define DA9030_VIBRA_FREQ_8HZ  (3 << 2)
+#define DA9030_VIBRA_DUTY_ON   (0 << 4)
+#define DA9030_VIBRA_DUTY_75P  (1 << 4)
+#define DA9030_VIBRA_DUTY_50P  (2 << 4)
+#define DA9030_VIBRA_DUTY_25P  (3 << 4)
+
+/* DA9034 flags for "struct led_info" */
+#define DA9034_LED_RAMP                (1 << 7)
+
+/* DA9034 touch screen platform data */
+struct da9034_touch_pdata {
+       int     interval_ms;    /* sampling interval while pen down */
+       int     x_inverted;
+       int     y_inverted;
+};
+
+struct da903x_subdev_info {
+       int             id;
+       const char      *name;
+       void            *platform_data;
+};
+
+struct da903x_platform_data {
+       int num_subdevs;
+       struct da903x_subdev_info *subdevs;
+};
+
+/* bit definitions for DA9030 events */
+#define DA9030_EVENT_ONKEY             (1 << 0)
+#define        DA9030_EVENT_PWREN              (1 << 1)
+#define        DA9030_EVENT_EXTON              (1 << 2)
+#define        DA9030_EVENT_CHDET              (1 << 3)
+#define        DA9030_EVENT_TBAT               (1 << 4)
+#define        DA9030_EVENT_VBATMON            (1 << 5)
+#define        DA9030_EVENT_VBATMON_TXON       (1 << 6)
+#define        DA9030_EVENT_CHIOVER            (1 << 7)
+#define        DA9030_EVENT_TCTO               (1 << 8)
+#define        DA9030_EVENT_CCTO               (1 << 9)
+#define        DA9030_EVENT_ADC_READY          (1 << 10)
+#define        DA9030_EVENT_VBUS_4P4           (1 << 11)
+#define        DA9030_EVENT_VBUS_4P0           (1 << 12)
+#define        DA9030_EVENT_SESS_VALID         (1 << 13)
+#define        DA9030_EVENT_SRP_DETECT         (1 << 14)
+#define        DA9030_EVENT_WATCHDOG           (1 << 15)
+#define        DA9030_EVENT_LDO15              (1 << 16)
+#define        DA9030_EVENT_LDO16              (1 << 17)
+#define        DA9030_EVENT_LDO17              (1 << 18)
+#define        DA9030_EVENT_LDO18              (1 << 19)
+#define        DA9030_EVENT_LDO19              (1 << 20)
+#define        DA9030_EVENT_BUCK2              (1 << 21)
+
+/* bit definitions for DA9034 events */
+#define DA9034_EVENT_ONKEY             (1 << 0)
+#define DA9034_EVENT_EXTON             (1 << 2)
+#define DA9034_EVENT_CHDET             (1 << 3)
+#define DA9034_EVENT_TBAT              (1 << 4)
+#define DA9034_EVENT_VBATMON           (1 << 5)
+#define DA9034_EVENT_REV_IOVER         (1 << 6)
+#define DA9034_EVENT_CH_IOVER          (1 << 7)
+#define DA9034_EVENT_CH_TCTO           (1 << 8)
+#define DA9034_EVENT_CH_CCTO           (1 << 9)
+#define DA9034_EVENT_USB_DEV           (1 << 10)
+#define DA9034_EVENT_OTGCP_IOVER       (1 << 11)
+#define DA9034_EVENT_VBUS_4P55         (1 << 12)
+#define DA9034_EVENT_VBUS_3P8          (1 << 13)
+#define DA9034_EVENT_SESS_1P8          (1 << 14)
+#define DA9034_EVENT_SRP_READY         (1 << 15)
+#define DA9034_EVENT_ADC_MAN           (1 << 16)
+#define DA9034_EVENT_ADC_AUTO4         (1 << 17)
+#define DA9034_EVENT_ADC_AUTO5         (1 << 18)
+#define DA9034_EVENT_ADC_AUTO6         (1 << 19)
+#define DA9034_EVENT_PEN_DOWN          (1 << 20)
+#define DA9034_EVENT_TSI_READY         (1 << 21)
+#define DA9034_EVENT_UART_TX           (1 << 22)
+#define DA9034_EVENT_UART_RX           (1 << 23)
+#define DA9034_EVENT_HEADSET           (1 << 25)
+#define DA9034_EVENT_HOOKSWITCH                (1 << 26)
+#define DA9034_EVENT_WATCHDOG          (1 << 27)
+
+extern int da903x_register_notifier(struct device *dev,
+               struct notifier_block *nb, unsigned int events);
+extern int da903x_unregister_notifier(struct device *dev,
+               struct notifier_block *nb, unsigned int events);
+
+/* Status Query Interface */
+#define DA9030_STATUS_ONKEY            (1 << 0)
+#define DA9030_STATUS_PWREN1           (1 << 1)
+#define DA9030_STATUS_EXTON            (1 << 2)
+#define DA9030_STATUS_CHDET            (1 << 3)
+#define DA9030_STATUS_TBAT             (1 << 4)
+#define DA9030_STATUS_VBATMON          (1 << 5)
+#define DA9030_STATUS_VBATMON_TXON     (1 << 6)
+#define DA9030_STATUS_MCLKDET          (1 << 7)
+
+#define DA9034_STATUS_ONKEY            (1 << 0)
+#define DA9034_STATUS_EXTON            (1 << 2)
+#define DA9034_STATUS_CHDET            (1 << 3)
+#define DA9034_STATUS_TBAT             (1 << 4)
+#define DA9034_STATUS_VBATMON          (1 << 5)
+#define DA9034_STATUS_PEN_DOWN         (1 << 6)
+#define DA9034_STATUS_MCLKDET          (1 << 7)
+#define DA9034_STATUS_USB_DEV          (1 << 8)
+#define DA9034_STATUS_HEADSET          (1 << 9)
+#define DA9034_STATUS_HOOKSWITCH       (1 << 10)
+#define DA9034_STATUS_REMCON           (1 << 11)
+#define DA9034_STATUS_VBUS_VALID_4P55  (1 << 12)
+#define DA9034_STATUS_VBUS_VALID_3P8   (1 << 13)
+#define DA9034_STATUS_SESS_VALID_1P8   (1 << 14)
+#define DA9034_STATUS_SRP_READY                (1 << 15)
+
+extern int da903x_query_status(struct device *dev, unsigned int status);
+
+
+/* NOTE: the two functions below are not intended for use outside
+ * of the DA9034 sub-device drivers
+ */
+extern int da903x_write(struct device *dev, int reg, uint8_t val);
+extern int da903x_read(struct device *dev, int reg, uint8_t *val);
+extern int da903x_update(struct device *dev, int reg, uint8_t val, uint8_t mask);
+extern int da903x_set_bits(struct device *dev, int reg, uint8_t bit_mask);
+extern int da903x_clr_bits(struct device *dev, int reg, uint8_t bit_mask);
+#endif /* __LINUX_PMIC_DA903X_H */
index e83c7f2036f9484ce63b3253d6b85fc94a8237c8..b4629818aea581bf33fad4708bda37c42012cec4 100644 (file)
@@ -15,8 +15,6 @@
 #include <linux/mfd/tmio.h>
 
 struct t7l66xb_platform_data {
-       int (*enable_clk32k)(struct platform_device *dev);
-       void (*disable_clk32k)(struct platform_device *dev);
        int (*enable)(struct platform_device *dev);
        int (*disable)(struct platform_device *dev);
        int (*suspend)(struct platform_device *dev);
index fa06e0610b8e79e2545c3debc5529d7072e42aaf..b4888209494a4d04107f7c66a802b5411ca870ca 100644 (file)
@@ -11,9 +11,6 @@
 #define MFD_TC6387XB_H
 
 struct tc6387xb_platform_data {
-       int (*enable_clk32k)(struct platform_device *dev);
-       void (*disable_clk32k)(struct platform_device *dev);
-
        int (*enable)(struct platform_device *dev);
        int (*disable)(struct platform_device *dev);
        int (*suspend)(struct platform_device *dev);
index fec7b3f7a81f7599bd972056ecd09b162a0063d3..626e448205c543ed8d6b2cd3a361d07d67719c4a 100644 (file)
 #ifndef MFD_TC6393XB_H
 #define MFD_TC6393XB_H
 
+#include <linux/fb.h>
+
 /* Also one should provide the CK3P6MI clock */
 struct tc6393xb_platform_data {
        u16     scr_pll2cr;     /* PLL2 Control */
        u16     scr_gper;       /* GP Enable */
-       u32     scr_gpo_doecr;  /* GPO Data OE Control */
-       u32     scr_gpo_dsr;    /* GPO Data Set */
 
        int     (*enable)(struct platform_device *dev);
        int     (*disable)(struct platform_device *dev);
@@ -31,15 +31,28 @@ struct tc6393xb_platform_data {
 
        int     irq_base;       /* base for subdevice irqs */
        int     gpio_base;
+       int     (*setup)(struct platform_device *dev);
+       void    (*teardown)(struct platform_device *dev);
 
        struct tmio_nand_data   *nand_data;
+       struct tmio_fb_data     *fb_data;
+
+       unsigned resume_restore : 1; /* make special actions
+                                       to preserve the state
+                                       on suspend/resume */
 };
 
+extern int tc6393xb_lcd_mode(struct platform_device *fb,
+                            const struct fb_videomode *mode);
+extern int tc6393xb_lcd_set_power(struct platform_device *fb, bool on);
+
 /*
  * Relative to irq_base
  */
 #define        IRQ_TC6393_NAND         0
 #define        IRQ_TC6393_MMC          1
+#define        IRQ_TC6393_OHCI         2
+#define        IRQ_TC6393_FB           4
 
 #define        TC6393XB_NR_IRQS        8