Merge tag 'mfd_3.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 28 Mar 2012 20:56:35 +0000 (13:56 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 28 Mar 2012 20:56:35 +0000 (13:56 -0700)
Pull MFD changes from Samuel Ortiz:
 - 4 new drivers: Freescale i.MX on-chip Anatop, Ricoh's RC5T583 and
   TI's TPS65090 and TPS65217.
 - New variants support (8420, 8520 ab9540), cleanups and bug fixes for
   the abx500 and db8500 ST-E chipsets.
 - Some minor fixes and update for the wm8994 from Mark.
 - The beginning of a long term TWL cleanup effort coming from the TI
   folks.
 - Various fixes and cleanups for the s5m, TPS659xx, pm860x, and MAX8997
   drivers.

Fix up trivial conflicts due to duplicate patches and header file
cleanups (<linux/device.h> removal etc).

* tag 'mfd_3.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (97 commits)
  gpio/twl: Add DT support to gpio-twl4030 driver
  gpio/twl: Allocate irq_desc dynamically for SPARSE_IRQ support
  mfd: Detach twl6040 from the pmic mfd driver
  mfd: Replace twl-* pr_ macros by the dev_ equivalent and do various cleanups
  mfd: Micro-optimization on twl4030 IRQ handler
  mfd: Make twl4030 SIH SPARSE_IRQ capable
  mfd: Move twl-core IRQ allocation into twl[4030|6030]-irq files
  mfd: Remove references already defineid in header file from twl-core
  mfd: Remove unneeded header from twl-core
  mfd: Make twl-core not depend on pdata->irq_base/end
  ARM: OMAP2+: board-omap4-*: Do not use anymore TWL6030_IRQ_BASE in board files
  mfd: Return twl6030_mmc_card_detect IRQ for board setup
  Revert "mfd: Add platform data for MAX8997 haptic driver"
  mfd: Add support for TPS65090
  mfd: Add some da9052-i2c section annotations
  mfd: Build rtc5t583 only if I2C config is selected to y.
  mfd: Add anatop mfd driver
  mfd: Fix compilation error in tps65910.h
  mfd: Add 8420 variant to db8500-prcmu
  mfd: Add 8520 PRCMU variant to db8500-prcmu
  ...

69 files changed:
Documentation/devicetree/bindings/gpio/gpio-twl4030.txt [new file with mode: 0644]
arch/arm/mach-omap2/board-4430sdp.c
arch/arm/mach-omap2/board-omap4panda.c
arch/arm/mach-s3c64xx/mach-crag6410-module.c
arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
drivers/cpufreq/db8500-cpufreq.c
drivers/gpio/gpio-stmpe.c
drivers/gpio/gpio-twl4030.c
drivers/hwmon/mc13783-adc.c
drivers/input/misc/88pm860x_onkey.c
drivers/input/touchscreen/mc13783_ts.c
drivers/leds/leds-88pm860x.c
drivers/mfd/88pm860x-core.c
drivers/mfd/88pm860x-i2c.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/ab8500-core.c
drivers/mfd/ab8500-i2c.c
drivers/mfd/anatop-mfd.c [new file with mode: 0644]
drivers/mfd/asic3.c
drivers/mfd/da9052-core.c
drivers/mfd/da9052-i2c.c
drivers/mfd/da9052-spi.c
drivers/mfd/db8500-prcmu.c
drivers/mfd/dbx500-prcmu-regs.h
drivers/mfd/mc13xxx-core.c
drivers/mfd/mfd-core.c
drivers/mfd/omap-usb-host.c
drivers/mfd/pcf50633-core.c
drivers/mfd/pcf50633-gpio.c
drivers/mfd/pcf50633-irq.c
drivers/mfd/rc5t583-irq.c [new file with mode: 0644]
drivers/mfd/rc5t583.c [new file with mode: 0644]
drivers/mfd/s5m-core.c
drivers/mfd/s5m-irq.c
drivers/mfd/sm501.c
drivers/mfd/stmpe.c
drivers/mfd/tps65090.c [new file with mode: 0644]
drivers/mfd/tps65217.c [new file with mode: 0644]
drivers/mfd/tps65910-irq.c
drivers/mfd/tps65910.c
drivers/mfd/twl-core.c
drivers/mfd/twl-core.h
drivers/mfd/twl4030-irq.c
drivers/mfd/twl6030-irq.c
drivers/mfd/wm831x-spi.c
drivers/mfd/wm8400-core.c
drivers/mfd/wm8994-core.c
drivers/mfd/wm8994-regmap.c
drivers/rtc/rtc-88pm860x.c
drivers/video/backlight/88pm860x_bl.c
include/linux/i2c/twl.h
include/linux/mfd/88pm860x.h
include/linux/mfd/abx500.h
include/linux/mfd/abx500/ab8500-gpio.h
include/linux/mfd/abx500/ab8500-sysctrl.h
include/linux/mfd/abx500/ab8500.h
include/linux/mfd/anatop.h [new file with mode: 0644]
include/linux/mfd/da9052/da9052.h
include/linux/mfd/db8500-prcmu.h
include/linux/mfd/dbx500-prcmu.h
include/linux/mfd/mc13xxx.h
include/linux/mfd/rc5t583.h [new file with mode: 0644]
include/linux/mfd/stmpe.h
include/linux/mfd/tps65090.h [new file with mode: 0644]
include/linux/mfd/tps65217.h [new file with mode: 0644]
include/linux/mfd/tps65910.h
include/linux/mfd/wm8994/pdata.h
include/linux/regulator/ab8500.h

diff --git a/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt b/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt
new file mode 100644 (file)
index 0000000..16695d9
--- /dev/null
@@ -0,0 +1,23 @@
+twl4030 GPIO controller bindings
+
+Required properties:
+- compatible:
+  - "ti,twl4030-gpio" for twl4030 GPIO controller
+- #gpio-cells : Should be two.
+  - first cell is the pin number
+  - second cell is used to specify optional parameters (unused)
+- gpio-controller : Marks the device node as a GPIO controller.
+- #interrupt-cells : Should be 2.
+- interrupt-controller: Mark the device node as an interrupt controller
+  The first cell is the GPIO number.
+  The second cell is not used.
+
+Example:
+
+twl_gpio: gpio {
+    compatible = "ti,twl4030-gpio";
+    #gpio-cells = <2>;
+    gpio-controller;
+    #interrupt-cells = <2>;
+    interrupt-controller;
+};
index 30768c2f53fd2bdb81d7c3f403c713fb501595ea..37dcb1bc025ea05674d3972d831455a462e43c7f 100644 (file)
@@ -490,21 +490,22 @@ static struct platform_device omap_vwlan_device = {
 
 static int omap4_twl6030_hsmmc_late_init(struct device *dev)
 {
-       int ret = 0;
+       int irq = 0;
        struct platform_device *pdev = container_of(dev,
                                struct platform_device, dev);
        struct omap_mmc_platform_data *pdata = dev->platform_data;
 
        /* Setting MMC1 Card detect Irq */
        if (pdev->id == 0) {
-               ret = twl6030_mmc_card_detect_config();
-               if (ret)
+               irq = twl6030_mmc_card_detect_config();
+               if (irq < 0) {
                        pr_err("Failed configuring MMC1 card detect\n");
-               pdata->slots[0].card_detect_irq = TWL6030_IRQ_BASE +
-                                               MMCDETECT_INTR_OFFSET;
+                       return irq;
+               }
+               pdata->slots[0].card_detect_irq = irq;
                pdata->slots[0].card_detect = twl6030_mmc_card_detect;
        }
-       return ret;
+       return 0;
 }
 
 static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
index e9071a57c37b669ca69561a255773c401f487c5b..8bf8e99c358e494b235d3460954dad789e1b2754 100644 (file)
@@ -238,7 +238,7 @@ struct wl12xx_platform_data omap_panda_wlan_data  __initdata = {
 
 static int omap4_twl6030_hsmmc_late_init(struct device *dev)
 {
-       int ret = 0;
+       int irq = 0;
        struct platform_device *pdev = container_of(dev,
                                struct platform_device, dev);
        struct omap_mmc_platform_data *pdata = dev->platform_data;
@@ -249,14 +249,15 @@ static int omap4_twl6030_hsmmc_late_init(struct device *dev)
        }
        /* Setting MMC1 Card detect Irq */
        if (pdev->id == 0) {
-               ret = twl6030_mmc_card_detect_config();
-                if (ret)
+               irq = twl6030_mmc_card_detect_config();
+               if (irq < 0) {
                        dev_err(dev, "%s: Error card detect config(%d)\n",
-                               __func__, ret);
-                else
-                       pdata->slots[0].card_detect = twl6030_mmc_card_detect;
+                               __func__, irq);
+                       return irq;
+               }
+               pdata->slots[0].card_detect = twl6030_mmc_card_detect;
        }
-       return ret;
+       return 0;
 }
 
 static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
index b6a67728cc88f957a9ee7513596fd2e41cedf3be..0ace108c3e3d710264f4c88dfa5676702723fbfc 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/mfd/wm831x/gpio.h>
 #include <linux/mfd/wm8994/pdata.h>
 
+#include <linux/regulator/machine.h>
+
 #include <sound/wm5100.h>
 #include <sound/wm8996.h>
 #include <sound/wm8962.h>
@@ -153,6 +155,14 @@ static const struct i2c_board_info wm1259_devs[] = {
        },
 };
 
+static struct regulator_init_data wm8994_ldo1 = {
+       .supply_regulator = "WALLVDD",
+};
+
+static struct regulator_init_data wm8994_ldo2 = {
+       .supply_regulator = "WALLVDD",
+};
+
 static struct wm8994_pdata wm8994_pdata = {
        .gpio_base = CODEC_GPIO_BASE,
        .gpio_defaults = {
@@ -160,8 +170,8 @@ static struct wm8994_pdata wm8994_pdata = {
        },
        .irq_base = CODEC_IRQ_BASE,
        .ldo = {
-               { .supply = "WALLVDD" },
-               { .supply = "WALLVDD" },
+                { .init_data = &wm8994_ldo1, },
+                { .init_data = &wm8994_ldo2, },
        },
 };
 
index d2d4131435a680b61fcb6f84f6b092affe72f5cd..7d34c52798b5dd1e7162d13eb63866cff62e2079 100644 (file)
@@ -13,7 +13,7 @@
 
 #define MOP500_AB8500_IRQ_BASE         IRQ_BOARD_START
 #define MOP500_AB8500_IRQ_END          (MOP500_AB8500_IRQ_BASE \
-                                        + AB8500_NR_IRQS)
+                                        + AB8500_MAX_NR_IRQS)
 
 /* TC35892 */
 #define TC35892_NR_INTERNAL_IRQS       8
index f5002015d82ea277c4e3e946a03e209a15f3eb64..a22ffa5bff9f85ca9ba961dc8896aa8be65c8fa3 100644 (file)
@@ -22,11 +22,11 @@ static struct cpufreq_frequency_table freq_table[] = {
        },
        [1] = {
                .index = 1,
-               .frequency = 300000,
+               .frequency = 400000,
        },
        [2] = {
                .index = 2,
-               .frequency = 600000,
+               .frequency = 800000,
        },
        [3] = {
                /* Used for MAX_OPP, if available */
@@ -113,12 +113,9 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
 
        BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
 
-       if (!prcmu_is_u8400()) {
-               freq_table[1].frequency = 400000;
-               freq_table[2].frequency = 800000;
-               if (prcmu_has_arm_maxopp())
-                       freq_table[3].frequency = 1000000;
-       }
+       if (prcmu_has_arm_maxopp())
+               freq_table[3].frequency = 1000000;
+
        pr_info("db8500-cpufreq : Available frequencies:\n");
        for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
                pr_info("  %d Mhz\n", freq_table[i].frequency/1000);
index 87a68a896abf7a0a010aa6395db5b0a53ba9ba41..094c5c4fd7f2ad05cd11060b504e9f4ad8e3ffd1 100644 (file)
@@ -307,13 +307,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
        struct stmpe_gpio_platform_data *pdata;
        struct stmpe_gpio *stmpe_gpio;
        int ret;
-       int irq;
+       int irq = 0;
 
        pdata = stmpe->pdata->gpio;
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
 
        stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL);
        if (!stmpe_gpio)
@@ -330,21 +328,28 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
        stmpe_gpio->chip.dev = &pdev->dev;
        stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
 
-       stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
+       if (irq >= 0)
+               stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
+       else
+               dev_info(&pdev->dev,
+                       "device configured in no-irq mode; "
+                       "irqs are not available\n");
 
        ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
        if (ret)
                goto out_free;
 
-       ret = stmpe_gpio_irq_init(stmpe_gpio);
-       if (ret)
-               goto out_disable;
+       if (irq >= 0) {
+               ret = stmpe_gpio_irq_init(stmpe_gpio);
+               if (ret)
+                       goto out_disable;
 
-       ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT,
-                                  "stmpe-gpio", stmpe_gpio);
-       if (ret) {
-               dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
-               goto out_removeirq;
+               ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq,
+                               IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio);
+               if (ret) {
+                       dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
+                       goto out_removeirq;
+               }
        }
 
        ret = gpiochip_add(&stmpe_gpio->chip);
@@ -361,9 +366,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
        return 0;
 
 out_freeirq:
-       free_irq(irq, stmpe_gpio);
+       if (irq >= 0)
+               free_irq(irq, stmpe_gpio);
 out_removeirq:
-       stmpe_gpio_irq_remove(stmpe_gpio);
+       if (irq >= 0)
+               stmpe_gpio_irq_remove(stmpe_gpio);
 out_disable:
        stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
 out_free:
@@ -391,8 +398,10 @@ static int __devexit stmpe_gpio_remove(struct platform_device *pdev)
 
        stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
 
-       free_irq(irq, stmpe_gpio);
-       stmpe_gpio_irq_remove(stmpe_gpio);
+       if (irq >= 0) {
+               free_irq(irq, stmpe_gpio);
+               stmpe_gpio_irq_remove(stmpe_gpio);
+       }
        platform_set_drvdata(pdev, NULL);
        kfree(stmpe_gpio);
 
index b8b4f228757c8777aca6554f39fcd7a05255f3be..94256fe7bf36de35556421d2a1d04ace98b3e59c 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/irq.h>
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/irqdomain.h>
 
 #include <linux/i2c/twl.h>
 
@@ -256,7 +258,8 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
                 * and vMMC2 power supplies based on card presence.
                 */
                pdata = chip->dev->platform_data;
-               value |= pdata->mmc_cd & 0x03;
+               if (pdata)
+                       value |= pdata->mmc_cd & 0x03;
 
                status = gpio_twl4030_write(REG_GPIO_CTRL, value);
        }
@@ -395,59 +398,70 @@ static int gpio_twl4030_remove(struct platform_device *pdev);
 static int __devinit gpio_twl4030_probe(struct platform_device *pdev)
 {
        struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
-       int ret;
+       struct device_node *node = pdev->dev.of_node;
+       int ret, irq_base;
 
        /* maybe setup IRQs */
-       if (pdata->irq_base) {
-               if (is_module()) {
-                       dev_err(&pdev->dev,
-                               "can't dispatch IRQs from modules\n");
-                       goto no_irqs;
-               }
-               ret = twl4030_sih_setup(TWL4030_MODULE_GPIO);
-               if (ret < 0)
-                       return ret;
-               WARN_ON(ret != pdata->irq_base);
-               twl4030_gpio_irq_base = ret;
+       if (is_module()) {
+               dev_err(&pdev->dev, "can't dispatch IRQs from modules\n");
+               goto no_irqs;
+       }
+
+       irq_base = irq_alloc_descs(-1, 0, TWL4030_GPIO_MAX, 0);
+       if (irq_base < 0) {
+               dev_err(&pdev->dev, "Failed to alloc irq_descs\n");
+               return irq_base;
        }
 
+       irq_domain_add_legacy(node, TWL4030_GPIO_MAX, irq_base, 0,
+                             &irq_domain_simple_ops, NULL);
+
+       ret = twl4030_sih_setup(&pdev->dev, TWL4030_MODULE_GPIO, irq_base);
+       if (ret < 0)
+               return ret;
+
+       twl4030_gpio_irq_base = irq_base;
+
 no_irqs:
-       /*
-        * NOTE:  boards may waste power if they don't set pullups
-        * and pulldowns correctly ... default for non-ULPI pins is
-        * pulldown, and some other pins may have external pullups
-        * or pulldowns.  Careful!
-        */
-       ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns);
-       if (ret)
-               dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n",
-                               pdata->pullups, pdata->pulldowns,
-                               ret);
-
-       ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd);
-       if (ret)
-               dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n",
-                               pdata->debounce, pdata->mmc_cd,
-                               ret);
-
-       twl_gpiochip.base = pdata->gpio_base;
+       twl_gpiochip.base = -1;
        twl_gpiochip.ngpio = TWL4030_GPIO_MAX;
        twl_gpiochip.dev = &pdev->dev;
 
-       /* NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE,
-        * is (still) clear if use_leds is set.
-        */
-       if (pdata->use_leds)
-               twl_gpiochip.ngpio += 2;
+       if (pdata) {
+               twl_gpiochip.base = pdata->gpio_base;
+
+               /*
+                * NOTE:  boards may waste power if they don't set pullups
+                * and pulldowns correctly ... default for non-ULPI pins is
+                * pulldown, and some other pins may have external pullups
+                * or pulldowns.  Careful!
+                */
+               ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns);
+               if (ret)
+                       dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n",
+                                       pdata->pullups, pdata->pulldowns,
+                                       ret);
+
+               ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd);
+               if (ret)
+                       dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n",
+                                       pdata->debounce, pdata->mmc_cd,
+                                       ret);
+
+               /*
+                * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE,
+                * is (still) clear if use_leds is set.
+                */
+               if (pdata->use_leds)
+                       twl_gpiochip.ngpio += 2;
+       }
 
        ret = gpiochip_add(&twl_gpiochip);
        if (ret < 0) {
-               dev_err(&pdev->dev,
-                               "could not register gpiochip, %d\n",
-                               ret);
+               dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
                twl_gpiochip.ngpio = 0;
                gpio_twl4030_remove(pdev);
-       } else if (pdata->setup) {
+       } else if (pdata && pdata->setup) {
                int status;
 
                status = pdata->setup(&pdev->dev,
@@ -465,7 +479,7 @@ static int gpio_twl4030_remove(struct platform_device *pdev)
        struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
        int status;
 
-       if (pdata->teardown) {
+       if (pdata && pdata->teardown) {
                status = pdata->teardown(&pdev->dev,
                                pdata->gpio_base, TWL4030_GPIO_MAX);
                if (status) {
@@ -486,12 +500,21 @@ static int gpio_twl4030_remove(struct platform_device *pdev)
        return -EIO;
 }
 
+static const struct of_device_id twl_gpio_match[] = {
+       { .compatible = "ti,twl4030-gpio", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, twl_gpio_match);
+
 /* Note:  this hardware lives inside an I2C-based multi-function device. */
 MODULE_ALIAS("platform:twl4030_gpio");
 
 static struct platform_driver gpio_twl4030_driver = {
-       .driver.name    = "twl4030_gpio",
-       .driver.owner   = THIS_MODULE,
+       .driver = {
+               .name   = "twl4030_gpio",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(twl_gpio_match),
+       },
        .probe          = gpio_twl4030_probe,
        .remove         = gpio_twl4030_remove,
 };
index 6c6b240a782eebdbe3d3908435a17c3bc50ba513..ce86c5e3c2c2ae6211694b92ff50e19573cb35ec 100644 (file)
@@ -59,7 +59,7 @@ static int mc13783_adc_read(struct device *dev,
 
        ret = mc13xxx_adc_do_conversion(priv->mc13xxx,
                        MC13XXX_ADC_MODE_MULT_CHAN,
-                       channel, sample);
+                       channel, 0, 0, sample);
        if (ret)
                return ret;
 
index f2e0cbc5ab646c76267731f1a1280041ba50c1ca..f9ce1835e4d71c7a2cf3f53231fd1703e3386b7a 100644 (file)
@@ -105,6 +105,8 @@ static int __devinit pm860x_onkey_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, info);
+       device_init_wakeup(&pdev->dev, 1);
+
        return 0;
 
 out_irq:
@@ -129,10 +131,34 @@ static int __devexit pm860x_onkey_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_onkey_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+       if (device_may_wakeup(dev))
+               chip->wakeup_flag |= 1 << PM8607_IRQ_ONKEY;
+       return 0;
+}
+static int pm860x_onkey_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+       if (device_may_wakeup(dev))
+               chip->wakeup_flag &= ~(1 << PM8607_IRQ_ONKEY);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_onkey_pm_ops, pm860x_onkey_suspend, pm860x_onkey_resume);
+
 static struct platform_driver pm860x_onkey_driver = {
        .driver         = {
                .name   = "88pm860x-onkey",
                .owner  = THIS_MODULE,
+               .pm     = &pm860x_onkey_pm_ops,
        },
        .probe          = pm860x_onkey_probe,
        .remove         = __devexit_p(pm860x_onkey_remove),
index ede02743eac1997b426a7970f96429a486ea4059..48dc5b0d26f1a0b59039532318967ec5c500b862 100644 (file)
@@ -39,6 +39,7 @@ struct mc13783_ts_priv {
        struct delayed_work work;
        struct workqueue_struct *workq;
        unsigned int sample[4];
+       struct mc13xxx_ts_platform_data *touch;
 };
 
 static irqreturn_t mc13783_ts_handler(int irq, void *data)
@@ -125,7 +126,9 @@ static void mc13783_ts_work(struct work_struct *work)
        unsigned int channel = 12;
 
        if (mc13xxx_adc_do_conversion(priv->mc13xxx,
-                               mode, channel, priv->sample) == 0)
+                               mode, channel,
+                               priv->touch->ato, priv->touch->atox,
+                               priv->sample) == 0)
                mc13783_ts_report_sample(priv);
 }
 
@@ -179,6 +182,12 @@ static int __init mc13783_ts_probe(struct platform_device *pdev)
        INIT_DELAYED_WORK(&priv->work, mc13783_ts_work);
        priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
        priv->idev = idev;
+       priv->touch = dev_get_platdata(&pdev->dev);
+       if (!priv->touch) {
+               dev_err(&pdev->dev, "missing platform data\n");
+               ret = -ENODEV;
+               goto err_free_mem;
+       }
 
        /*
         * We need separate workqueue because mc13783_adc_do_conversion
index 4ca00624bd1860ed3b1f29e27ea79b59b47dc46d..5b61aaf7ac0f3faa565430fd1acafef8162afd20 100644 (file)
@@ -114,6 +114,27 @@ static inline int __blink_ctl_mask(int port)
        return ret;
 }
 
+static int led_power_set(struct pm860x_chip *chip, int port, int on)
+{
+       int ret = -EINVAL;
+
+       switch (port) {
+       case PM8606_LED1_RED:
+       case PM8606_LED1_GREEN:
+       case PM8606_LED1_BLUE:
+               ret = on ? pm8606_osc_enable(chip, RGB1_ENABLE) :
+                       pm8606_osc_disable(chip, RGB1_ENABLE);
+               break;
+       case PM8606_LED2_RED:
+       case PM8606_LED2_GREEN:
+       case PM8606_LED2_BLUE:
+               ret = on ? pm8606_osc_enable(chip, RGB2_ENABLE) :
+                       pm8606_osc_disable(chip, RGB2_ENABLE);
+               break;
+       }
+       return ret;
+}
+
 static void pm860x_led_work(struct work_struct *work)
 {
 
@@ -126,6 +147,7 @@ static void pm860x_led_work(struct work_struct *work)
        chip = led->chip;
        mutex_lock(&led->lock);
        if ((led->current_brightness == 0) && led->brightness) {
+               led_power_set(chip, led->port, 1);
                if (led->iset) {
                        pm860x_set_bits(led->i2c, __led_off(led->port),
                                        LED_CURRENT_MASK, led->iset);
@@ -149,6 +171,7 @@ static void pm860x_led_work(struct work_struct *work)
                                        LED_CURRENT_MASK, 0);
                        mask = __blink_ctl_mask(led->port);
                        pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0);
+                       led_power_set(chip, led->port, 0);
                }
        }
        led->current_brightness = led->brightness;
index 17dfe9bb6d2745c2bb5f6123b1afbc6c6d997ca6..87bd5ba38d5b649db355f252d326fe28116041c0 100644 (file)
@@ -503,6 +503,101 @@ static void device_irq_exit(struct pm860x_chip *chip)
                free_irq(chip->core_irq, chip);
 }
 
+int pm8606_osc_enable(struct pm860x_chip *chip, unsigned short client)
+{
+       int ret = -EIO;
+       struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
+               chip->client : chip->companion;
+
+       dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
+       dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
+                       __func__, chip->osc_vote,
+                       chip->osc_status);
+
+       mutex_lock(&chip->osc_lock);
+       /* Update voting status */
+       chip->osc_vote |= client;
+       /* If reference group is off - turn on*/
+       if (chip->osc_status != PM8606_REF_GP_OSC_ON) {
+               chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
+               /* Enable Reference group Vsys */
+               if (pm860x_set_bits(i2c, PM8606_VSYS,
+                               PM8606_VSYS_EN, PM8606_VSYS_EN))
+                       goto out;
+
+               /*Enable Internal Oscillator */
+               if (pm860x_set_bits(i2c, PM8606_MISC,
+                               PM8606_MISC_OSC_EN, PM8606_MISC_OSC_EN))
+                       goto out;
+               /* Update status (only if writes succeed) */
+               chip->osc_status = PM8606_REF_GP_OSC_ON;
+       }
+       mutex_unlock(&chip->osc_lock);
+
+       dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
+                       __func__, chip->osc_vote,
+                       chip->osc_status, ret);
+       return 0;
+out:
+       mutex_unlock(&chip->osc_lock);
+       return ret;
+}
+EXPORT_SYMBOL(pm8606_osc_enable);
+
+int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client)
+{
+       int ret = -EIO;
+       struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
+               chip->client : chip->companion;
+
+       dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
+       dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
+                       __func__, chip->osc_vote,
+                       chip->osc_status);
+
+       mutex_lock(&chip->osc_lock);
+       /*Update voting status */
+       chip->osc_vote &= ~(client);
+       /* If reference group is off and this is the last client to release
+        * - turn off */
+       if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) &&
+                       (chip->osc_vote == REF_GP_NO_CLIENTS)) {
+               chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
+               /* Disable Reference group Vsys */
+               if (pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0))
+                       goto out;
+               /* Disable Internal Oscillator */
+               if (pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0))
+                       goto out;
+               chip->osc_status = PM8606_REF_GP_OSC_OFF;
+       }
+       mutex_unlock(&chip->osc_lock);
+
+       dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
+                       __func__, chip->osc_vote,
+                       chip->osc_status, ret);
+       return 0;
+out:
+       mutex_unlock(&chip->osc_lock);
+       return ret;
+}
+EXPORT_SYMBOL(pm8606_osc_disable);
+
+static void __devinit device_osc_init(struct i2c_client *i2c)
+{
+       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+
+       mutex_init(&chip->osc_lock);
+       /* init portofino reference group voting and status */
+       /* Disable Reference group Vsys */
+       pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0);
+       /* Disable Internal Oscillator */
+       pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0);
+
+       chip->osc_vote = REF_GP_NO_CLIENTS;
+       chip->osc_status = PM8606_REF_GP_OSC_OFF;
+}
+
 static void __devinit device_bk_init(struct pm860x_chip *chip,
                                     struct pm860x_platform_data *pdata)
 {
@@ -767,6 +862,15 @@ out:
        return;
 }
 
+static void __devinit device_8606_init(struct pm860x_chip *chip,
+                                      struct i2c_client *i2c,
+                                      struct pm860x_platform_data *pdata)
+{
+       device_osc_init(i2c);
+       device_bk_init(chip, pdata);
+       device_led_init(chip, pdata);
+}
+
 int __devinit pm860x_device_init(struct pm860x_chip *chip,
                       struct pm860x_platform_data *pdata)
 {
@@ -774,8 +878,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
 
        switch (chip->id) {
        case CHIP_PM8606:
-               device_bk_init(chip, pdata);
-               device_led_init(chip, pdata);
+               device_8606_init(chip, chip->client, pdata);
                break;
        case CHIP_PM8607:
                device_8607_init(chip, chip->client, pdata);
@@ -785,8 +888,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
        if (chip->companion) {
                switch (chip->id) {
                case CHIP_PM8607:
-                       device_bk_init(chip, pdata);
-                       device_led_init(chip, pdata);
+                       device_8606_init(chip, chip->companion, pdata);
                        break;
                case CHIP_PM8606:
                        device_8607_init(chip, chip->companion, pdata);
index f93dd9571c3c81e8b44f26dc51d54b0901039cd6..b2cfdc458561fb5fcba59a6dc11e0a9b70c6b55a 100644 (file)
@@ -334,10 +334,35 @@ static int __devexit pm860x_remove(struct i2c_client *client)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_suspend(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct pm860x_chip *chip = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(dev) && chip->wakeup_flag)
+               enable_irq_wake(chip->core_irq);
+       return 0;
+}
+
+static int pm860x_resume(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct pm860x_chip *chip = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(dev) && chip->wakeup_flag)
+               disable_irq_wake(chip->core_irq);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume);
+
 static struct i2c_driver pm860x_driver = {
        .driver = {
                .name   = "88PM860x",
                .owner  = THIS_MODULE,
+               .pm     = &pm860x_pm_ops,
        },
        .probe          = pm860x_probe,
        .remove         = __devexit_p(pm860x_remove),
index 243e0c663c37be28fc2282dc98be2e9715f7804a..29f463cc09cbc5dc56ec215a225548be8a65b900 100644 (file)
@@ -143,6 +143,21 @@ config TPS6507X
          This driver can also be built as a module.  If so, the module
          will be called tps6507x.
 
+config MFD_TPS65217
+       tristate "TPS65217 Power Management / White LED chips"
+       depends on I2C
+       select MFD_CORE
+       select REGMAP_I2C
+       help
+         If you say yes here you get support for the TPS65217 series of
+         Power Management / White LED chips.
+         These include voltage regulators, lithium ion/polymer battery
+         charger, wled and other features that are often used in portable
+         devices.
+
+         This driver can also be built as a module.  If so, the module
+         will be called tps65217.
+
 config MFD_TPS6586X
        bool "TPS6586x Power Management chips"
        depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
@@ -162,6 +177,7 @@ config MFD_TPS65910
        depends on I2C=y && GPIOLIB
        select MFD_CORE
        select GPIO_TPS65910
+       select REGMAP_I2C
        help
          if you say yes here you get support for the TPS65910 series of
          Power Management chips.
@@ -171,7 +187,7 @@ config MFD_TPS65912
        depends on GPIOLIB
 
 config MFD_TPS65912_I2C
-       bool "TPS95612 Power Management chip with I2C"
+       bool "TPS65912 Power Management chip with I2C"
        select MFD_CORE
        select MFD_TPS65912
        depends on I2C=y && GPIOLIB
@@ -400,7 +416,7 @@ config MFD_MAX8997
        depends on I2C=y && GENERIC_HARDIRQS
        select MFD_CORE
        help
-         Say yes here to support for Maxim Semiconductor MAX8998/8966.
+         Say yes here to support for Maxim Semiconductor MAX8997/8966.
          This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic,
          MUIC controls on chip.
          This driver provides common support for accessing the device;
@@ -812,6 +828,18 @@ config MFD_PM8XXX_IRQ
 config TPS65911_COMPARATOR
        tristate
 
+config MFD_TPS65090
+       bool "TPS65090 Power Management chips"
+       depends on I2C=y && GENERIC_HARDIRQS
+       select MFD_CORE
+       select REGMAP_I2C
+       help
+         If you say yes here you get support for the TPS65090 series of
+         Power Management chips.
+         This driver provides common support for accessing the device,
+         additional drivers must be enabled in order to use the
+         functionality of the device.
+
 config MFD_AAT2870_CORE
        bool "Support for the AnalogicTech AAT2870"
        select MFD_CORE
@@ -831,6 +859,28 @@ config MFD_INTEL_MSIC
          Passage) chip. This chip embeds audio, battery, GPIO, etc.
          devices used in Intel Medfield platforms.
 
+config MFD_RC5T583
+       bool "Ricoh RC5T583 Power Management system device"
+       depends on I2C=y && GENERIC_HARDIRQS
+       select MFD_CORE
+       select REGMAP_I2C
+       help
+         Select this option to get support for the RICOH583 Power
+         Management system device.
+         This driver provides common support for accessing the device
+         through i2c interface. The device supports multiple sub-devices
+         like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey.
+         Additional drivers must be enabled in order to use the
+         different functionality of the device.
+
+config MFD_ANATOP
+       bool "Support for Freescale i.MX on-chip ANATOP controller"
+       depends on SOC_IMX6Q
+       help
+         Select this option to enable Freescale i.MX on-chip ANATOP
+         MFD controller. This controller embeds regulator and
+         thermal devices for Freescale i.MX platforms.
+
 endmenu
 endif
 
index b953bab934f7f872a7f53307a865a7efa22312ac..05fa538c5efe942ebd5146e57689fc607a34955c 100644 (file)
@@ -38,6 +38,7 @@ obj-$(CONFIG_MFD_WM8994)      += wm8994-core.o wm8994-irq.o wm8994-regmap.o
 obj-$(CONFIG_TPS6105X)         += tps6105x.o
 obj-$(CONFIG_TPS65010)         += tps65010.o
 obj-$(CONFIG_TPS6507X)         += tps6507x.o
+obj-$(CONFIG_MFD_TPS65217)     += tps65217.o
 obj-$(CONFIG_MFD_TPS65910)     += tps65910.o tps65910-irq.o
 tps65912-objs                   := tps65912-core.o tps65912-irq.o
 obj-$(CONFIG_MFD_TPS65912)     += tps65912.o
@@ -109,6 +110,9 @@ obj-$(CONFIG_MFD_OMAP_USB_HOST)     += omap-usb-host.o
 obj-$(CONFIG_MFD_PM8921_CORE)  += pm8921-core.o
 obj-$(CONFIG_MFD_PM8XXX_IRQ)   += pm8xxx-irq.o
 obj-$(CONFIG_TPS65911_COMPARATOR)      += tps65911-comparator.o
+obj-$(CONFIG_MFD_TPS65090)     += tps65090.o
 obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
 obj-$(CONFIG_MFD_INTEL_MSIC)   += intel_msic.o
+obj-$(CONFIG_MFD_RC5T583)      += rc5t583.o rc5t583-irq.o
 obj-$(CONFIG_MFD_S5M_CORE)     += s5m-core.o s5m-irq.o
+obj-$(CONFIG_MFD_ANATOP)       += anatop-mfd.o
index d295941c9a3db63ab75408470ac8edfefbdb2cb2..1f08704f7ae8ecab27c3247d4009f0c71de91b83 100644 (file)
@@ -32,6 +32,7 @@
 #define AB8500_IT_SOURCE6_REG          0x05
 #define AB8500_IT_SOURCE7_REG          0x06
 #define AB8500_IT_SOURCE8_REG          0x07
+#define AB9540_IT_SOURCE13_REG         0x0C
 #define AB8500_IT_SOURCE19_REG         0x12
 #define AB8500_IT_SOURCE20_REG         0x13
 #define AB8500_IT_SOURCE21_REG         0x14
@@ -53,6 +54,7 @@
 #define AB8500_IT_LATCH9_REG           0x28
 #define AB8500_IT_LATCH10_REG          0x29
 #define AB8500_IT_LATCH12_REG          0x2B
+#define AB9540_IT_LATCH13_REG          0x2C
 #define AB8500_IT_LATCH19_REG          0x32
 #define AB8500_IT_LATCH20_REG          0x33
 #define AB8500_IT_LATCH21_REG          0x34
 #define AB8500_IT_MASK24_REG           0x57
 
 #define AB8500_REV_REG                 0x80
+#define AB8500_IC_NAME_REG             0x82
 #define AB8500_SWITCH_OFF_STATUS       0x00
 
 #define AB8500_TURN_ON_STATUS          0x00
 
+#define AB9540_MODEM_CTRL2_REG                 0x23
+#define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT       BIT(2)
+
 /*
  * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
- * numbers are indexed into this array with (num / 8).
+ * numbers are indexed into this array with (num / 8). The interupts are
+ * defined in linux/mfd/ab8500.h
  *
  * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
  * offset 0.
  */
+/* AB8500 support */
 static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
        0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
 };
 
+/* AB9540 support */
+static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
+       0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24,
+};
+
+static const char ab8500_version_str[][7] = {
+       [AB8500_VERSION_AB8500] = "AB8500",
+       [AB8500_VERSION_AB8505] = "AB8505",
+       [AB8500_VERSION_AB9540] = "AB9540",
+       [AB8500_VERSION_AB8540] = "AB8540",
+};
+
 static int ab8500_get_chip_id(struct device *dev)
 {
        struct ab8500 *ab8500;
@@ -127,9 +147,7 @@ static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
 
        dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
 
-       ret = mutex_lock_interruptible(&ab8500->lock);
-       if (ret)
-               return ret;
+       mutex_lock(&ab8500->lock);
 
        ret = ab8500->write(ab8500, addr, data);
        if (ret < 0)
@@ -156,9 +174,7 @@ static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
         * bank on higher 8 bits and reg in lower */
        u16 addr = ((u16)bank) << 8 | reg;
 
-       ret = mutex_lock_interruptible(&ab8500->lock);
-       if (ret)
-               return ret;
+       mutex_lock(&ab8500->lock);
 
        ret = ab8500->read(ab8500, addr);
        if (ret < 0)
@@ -185,31 +201,38 @@ static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
        u8 reg, u8 bitmask, u8 bitvalues)
 {
        int ret;
-       u8 data;
        /* put the u8 bank and u8 reg together into a an u16.
         * bank on higher 8 bits and reg in lower */
        u16 addr = ((u16)bank) << 8 | reg;
 
-       ret = mutex_lock_interruptible(&ab8500->lock);
-       if (ret)
-               return ret;
+       mutex_lock(&ab8500->lock);
 
-       ret = ab8500->read(ab8500, addr);
-       if (ret < 0) {
-               dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
-                       addr, ret);
-               goto out;
-       }
+       if (ab8500->write_masked == NULL) {
+               u8 data;
 
-       data = (u8)ret;
-       data = (~bitmask & data) | (bitmask & bitvalues);
+               ret = ab8500->read(ab8500, addr);
+               if (ret < 0) {
+                       dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
+                               addr, ret);
+                       goto out;
+               }
 
-       ret = ab8500->write(ab8500, addr, data);
-       if (ret < 0)
-               dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
-                       addr, ret);
+               data = (u8)ret;
+               data = (~bitmask & data) | (bitmask & bitvalues);
+
+               ret = ab8500->write(ab8500, addr, data);
+               if (ret < 0)
+                       dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
+                               addr, ret);
 
-       dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, data);
+               dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr,
+                       data);
+               goto out;
+       }
+       ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues);
+       if (ret < 0)
+               dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr,
+                       ret);
 out:
        mutex_unlock(&ab8500->lock);
        return ret;
@@ -248,7 +271,7 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
        struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
        int i;
 
-       for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
+       for (i = 0; i < ab8500->mask_size; i++) {
                u8 old = ab8500->oldmask[i];
                u8 new = ab8500->mask[i];
                int reg;
@@ -256,14 +279,17 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
                if (new == old)
                        continue;
 
-               /* Interrupt register 12 doesn't exist prior to version 2.0 */
-               if (ab8500_irq_regoffset[i] == 11 &&
-                       ab8500->chip_id < AB8500_CUT2P0)
+               /*
+                * Interrupt register 12 doesn't exist prior to AB8500 version
+                * 2.0
+                */
+               if (ab8500->irq_reg_offset[i] == 11 &&
+                       is_ab8500_1p1_or_earlier(ab8500))
                        continue;
 
                ab8500->oldmask[i] = new;
 
-               reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
+               reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
                set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
        }
 
@@ -306,13 +332,16 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
 
        dev_vdbg(ab8500->dev, "interrupt\n");
 
-       for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
-               int regoffset = ab8500_irq_regoffset[i];
+       for (i = 0; i < ab8500->mask_size; i++) {
+               int regoffset = ab8500->irq_reg_offset[i];
                int status;
                u8 value;
 
-               /* Interrupt register 12 doesn't exist prior to version 2.0 */
-               if (regoffset == 11 && ab8500->chip_id < AB8500_CUT2P0)
+               /*
+                * Interrupt register 12 doesn't exist prior to AB8500 version
+                * 2.0
+                */
+               if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500))
                        continue;
 
                status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
@@ -336,8 +365,16 @@ static int ab8500_irq_init(struct ab8500 *ab8500)
 {
        int base = ab8500->irq_base;
        int irq;
+       int num_irqs;
+
+       if (is_ab9540(ab8500))
+               num_irqs = AB9540_NR_IRQS;
+       else if (is_ab8505(ab8500))
+               num_irqs = AB8505_NR_IRQS;
+       else
+               num_irqs = AB8500_NR_IRQS;
 
-       for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
+       for (irq = base; irq < base + num_irqs; irq++) {
                irq_set_chip_data(irq, ab8500);
                irq_set_chip_and_handler(irq, &ab8500_irq_chip,
                                         handle_simple_irq);
@@ -356,8 +393,16 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
 {
        int base = ab8500->irq_base;
        int irq;
+       int num_irqs;
 
-       for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
+       if (is_ab9540(ab8500))
+               num_irqs = AB9540_NR_IRQS;
+       else if (is_ab8505(ab8500))
+               num_irqs = AB8505_NR_IRQS;
+       else
+               num_irqs = AB8500_NR_IRQS;
+
+       for (irq = base; irq < base + num_irqs; irq++) {
 #ifdef CONFIG_ARM
                set_irq_flags(irq, 0);
 #endif
@@ -366,6 +411,7 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
        }
 }
 
+/* AB8500 GPIO Resources */
 static struct resource __devinitdata ab8500_gpio_resources[] = {
        {
                .name   = "GPIO_INT6",
@@ -375,6 +421,28 @@ static struct resource __devinitdata ab8500_gpio_resources[] = {
        }
 };
 
+/* AB9540 GPIO Resources */
+static struct resource __devinitdata ab9540_gpio_resources[] = {
+       {
+               .name   = "GPIO_INT6",
+               .start  = AB8500_INT_GPIO6R,
+               .end    = AB8500_INT_GPIO41F,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .name   = "GPIO_INT14",
+               .start  = AB9540_INT_GPIO50R,
+               .end    = AB9540_INT_GPIO54R,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .name   = "GPIO_INT15",
+               .start  = AB9540_INT_GPIO50F,
+               .end    = AB9540_INT_GPIO54F,
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
 static struct resource __devinitdata ab8500_gpadc_resources[] = {
        {
                .name   = "HW_CONV_END",
@@ -490,12 +558,6 @@ static struct resource __devinitdata ab8500_charger_resources[] = {
                .end = AB8500_INT_USB_LINK_STATUS,
                .flags = IORESOURCE_IRQ,
        },
-       {
-               .name = "USB_CHARGE_DET_DONE",
-               .start = AB8500_INT_USB_CHG_DET_DONE,
-               .end = AB8500_INT_USB_CHG_DET_DONE,
-               .flags = IORESOURCE_IRQ,
-       },
        {
                .name = "VBUS_OVV",
                .start = AB8500_INT_VBUS_OVV,
@@ -534,14 +596,8 @@ static struct resource __devinitdata ab8500_charger_resources[] = {
        },
        {
                .name = "USB_CHARGER_NOT_OKR",
-               .start = AB8500_INT_USB_CHARGER_NOT_OK,
-               .end = AB8500_INT_USB_CHARGER_NOT_OK,
-               .flags = IORESOURCE_IRQ,
-       },
-       {
-               .name = "USB_CHARGER_NOT_OKF",
-               .start = AB8500_INT_USB_CHARGER_NOT_OKF,
-               .end = AB8500_INT_USB_CHARGER_NOT_OKF,
+               .start = AB8500_INT_USB_CHARGER_NOT_OKR,
+               .end = AB8500_INT_USB_CHARGER_NOT_OKR,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -616,6 +672,12 @@ static struct resource __devinitdata ab8500_fg_resources[] = {
                .end = AB8500_INT_CC_INT_CALIB,
                .flags = IORESOURCE_IRQ,
        },
+       {
+               .name = "CCEOC",
+               .start = AB8500_INT_CCEOC,
+               .end = AB8500_INT_CCEOC,
+               .flags = IORESOURCE_IRQ,
+       },
 };
 
 static struct resource __devinitdata ab8500_chargalg_resources[] = {};
@@ -630,8 +692,8 @@ static struct resource __devinitdata ab8500_debug_resources[] = {
        },
        {
                .name   = "IRQ_LAST",
-               .start  = AB8500_INT_USB_CHARGER_NOT_OKF,
-               .end    = AB8500_INT_USB_CHARGER_NOT_OKF,
+               .start  = AB8500_INT_XTAL32K_KO,
+               .end    = AB8500_INT_XTAL32K_KO,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -691,7 +753,7 @@ static struct resource __devinitdata ab8500_temp_resources[] = {
        },
 };
 
-static struct mfd_cell __devinitdata ab8500_devs[] = {
+static struct mfd_cell __devinitdata abx500_common_devs[] = {
 #ifdef CONFIG_DEBUG_FS
        {
                .name = "ab8500-debug",
@@ -705,11 +767,6 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
        {
                .name = "ab8500-regulator",
        },
-       {
-               .name = "ab8500-gpio",
-               .num_resources = ARRAY_SIZE(ab8500_gpio_resources),
-               .resources = ab8500_gpio_resources,
-       },
        {
                .name = "ab8500-gpadc",
                .num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
@@ -748,11 +805,7 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
        {
                .name = "ab8500-codec",
        },
-       {
-               .name = "ab8500-usb",
-               .num_resources = ARRAY_SIZE(ab8500_usb_resources),
-               .resources = ab8500_usb_resources,
-       },
+
        {
                .name = "ab8500-poweron-key",
                .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
@@ -781,6 +834,32 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
        },
 };
 
+static struct mfd_cell __devinitdata ab8500_devs[] = {
+       {
+               .name = "ab8500-gpio",
+               .num_resources = ARRAY_SIZE(ab8500_gpio_resources),
+               .resources = ab8500_gpio_resources,
+       },
+       {
+               .name = "ab8500-usb",
+               .num_resources = ARRAY_SIZE(ab8500_usb_resources),
+               .resources = ab8500_usb_resources,
+       },
+};
+
+static struct mfd_cell __devinitdata ab9540_devs[] = {
+       {
+               .name = "ab8500-gpio",
+               .num_resources = ARRAY_SIZE(ab9540_gpio_resources),
+               .resources = ab9540_gpio_resources,
+       },
+       {
+               .name = "ab9540-usb",
+               .num_resources = ARRAY_SIZE(ab8500_usb_resources),
+               .resources = ab8500_usb_resources,
+       },
+};
+
 static ssize_t show_chip_id(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
@@ -842,9 +921,64 @@ static ssize_t show_turn_on_status(struct device *dev,
        return sprintf(buf, "%#x\n", value);
 }
 
+static ssize_t show_ab9540_dbbrstn(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct ab8500 *ab8500;
+       int ret;
+       u8 value;
+
+       ab8500 = dev_get_drvdata(dev);
+
+       ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2,
+               AB9540_MODEM_CTRL2_REG, &value);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%d\n",
+                       (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0);
+}
+
+static ssize_t store_ab9540_dbbrstn(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct ab8500 *ab8500;
+       int ret = count;
+       int err;
+       u8 bitvalues;
+
+       ab8500 = dev_get_drvdata(dev);
+
+       if (count > 0) {
+               switch (buf[0]) {
+               case '0':
+                       bitvalues = 0;
+                       break;
+               case '1':
+                       bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT;
+                       break;
+               default:
+                       goto exit;
+               }
+
+               err = mask_and_set_register_interruptible(ab8500,
+                       AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG,
+                       AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues);
+               if (err)
+                       dev_info(ab8500->dev,
+                               "Failed to set DBBRSTN %c, err %#x\n",
+                               buf[0], err);
+       }
+
+exit:
+       return ret;
+}
+
 static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
 static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
 static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
+static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR,
+                       show_ab9540_dbbrstn, store_ab9540_dbbrstn);
 
 static struct attribute *ab8500_sysfs_entries[] = {
        &dev_attr_chip_id.attr,
@@ -853,11 +987,23 @@ static struct attribute *ab8500_sysfs_entries[] = {
        NULL,
 };
 
+static struct attribute *ab9540_sysfs_entries[] = {
+       &dev_attr_chip_id.attr,
+       &dev_attr_switch_off_status.attr,
+       &dev_attr_turn_on_status.attr,
+       &dev_attr_dbbrstn.attr,
+       NULL,
+};
+
 static struct attribute_group ab8500_attr_group = {
        .attrs  = ab8500_sysfs_entries,
 };
 
-int __devinit ab8500_init(struct ab8500 *ab8500)
+static struct attribute_group ab9540_attr_group = {
+       .attrs  = ab9540_sysfs_entries,
+};
+
+int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
 {
        struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
        int ret;
@@ -870,25 +1016,45 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
        mutex_init(&ab8500->lock);
        mutex_init(&ab8500->irq_lock);
 
+       if (version != AB8500_VERSION_UNDEFINED)
+               ab8500->version = version;
+       else {
+               ret = get_register_interruptible(ab8500, AB8500_MISC,
+                       AB8500_IC_NAME_REG, &value);
+               if (ret < 0)
+                       return ret;
+
+               ab8500->version = value;
+       }
+
        ret = get_register_interruptible(ab8500, AB8500_MISC,
                AB8500_REV_REG, &value);
        if (ret < 0)
                return ret;
 
-       switch (value) {
-       case AB8500_CUT1P0:
-       case AB8500_CUT1P1:
-       case AB8500_CUT2P0:
-       case AB8500_CUT3P0:
-       case AB8500_CUT3P3:
-               dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
-               break;
-       default:
-               dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value);
-               return -EINVAL;
-       }
        ab8500->chip_id = value;
 
+       dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n",
+                       ab8500_version_str[ab8500->version],
+                       ab8500->chip_id >> 4,
+                       ab8500->chip_id & 0x0F);
+
+       /* Configure AB8500 or AB9540 IRQ */
+       if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
+               ab8500->mask_size = AB9540_NUM_IRQ_REGS;
+               ab8500->irq_reg_offset = ab9540_irq_regoffset;
+       } else {
+               ab8500->mask_size = AB8500_NUM_IRQ_REGS;
+               ab8500->irq_reg_offset = ab8500_irq_regoffset;
+       }
+       ab8500->mask = kzalloc(ab8500->mask_size, GFP_KERNEL);
+       if (!ab8500->mask)
+               return -ENOMEM;
+       ab8500->oldmask = kzalloc(ab8500->mask_size, GFP_KERNEL);
+       if (!ab8500->oldmask) {
+               ret = -ENOMEM;
+               goto out_freemask;
+       }
        /*
         * ab8500 has switched off due to (SWITCH_OFF_STATUS):
         * 0x01 Swoff bit programming
@@ -911,30 +1077,33 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
                plat->init(ab8500);
 
        /* Clear and mask all interrupts */
-       for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
-               /* Interrupt register 12 doesn't exist prior to version 2.0 */
-               if (ab8500_irq_regoffset[i] == 11 &&
-                       ab8500->chip_id < AB8500_CUT2P0)
+       for (i = 0; i < ab8500->mask_size; i++) {
+               /*
+                * Interrupt register 12 doesn't exist prior to AB8500 version
+                * 2.0
+                */
+               if (ab8500->irq_reg_offset[i] == 11 &&
+                               is_ab8500_1p1_or_earlier(ab8500))
                        continue;
 
                get_register_interruptible(ab8500, AB8500_INTERRUPT,
-                       AB8500_IT_LATCH1_REG + ab8500_irq_regoffset[i],
+                       AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
                        &value);
                set_register_interruptible(ab8500, AB8500_INTERRUPT,
-                       AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i], 0xff);
+                       AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff);
        }
 
        ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
        if (ret)
-               return ret;
+               goto out_freeoldmask;
 
-       for (i = 0; i < AB8500_NUM_IRQ_REGS; i++)
+       for (i = 0; i < ab8500->mask_size; i++)
                ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
 
        if (ab8500->irq_base) {
                ret = ab8500_irq_init(ab8500);
                if (ret)
-                       return ret;
+                       goto out_freeoldmask;
 
                ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
                                           IRQF_ONESHOT | IRQF_NO_SUSPEND,
@@ -943,17 +1112,34 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
                        goto out_removeirq;
        }
 
-       ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
-                             ARRAY_SIZE(ab8500_devs), NULL,
+       ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
+                             ARRAY_SIZE(abx500_common_devs), NULL,
                              ab8500->irq_base);
+
        if (ret)
                goto out_freeirq;
 
-       ret = sysfs_create_group(&ab8500->dev->kobj, &ab8500_attr_group);
+       if (is_ab9540(ab8500))
+               ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
+                             ARRAY_SIZE(ab9540_devs), NULL,
+                             ab8500->irq_base);
+       else
+               ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
+                             ARRAY_SIZE(ab9540_devs), NULL,
+                             ab8500->irq_base);
        if (ret)
-               dev_err(ab8500->dev, "error creating sysfs entries\n");
+               goto out_freeirq;
 
-       return ret;
+       if (is_ab9540(ab8500))
+               ret = sysfs_create_group(&ab8500->dev->kobj,
+                                       &ab9540_attr_group);
+       else
+               ret = sysfs_create_group(&ab8500->dev->kobj,
+                                       &ab8500_attr_group);
+       if (ret)
+               dev_err(ab8500->dev, "error creating sysfs entries\n");
+       else
+               return ret;
 
 out_freeirq:
        if (ab8500->irq_base)
@@ -961,18 +1147,27 @@ out_freeirq:
 out_removeirq:
        if (ab8500->irq_base)
                ab8500_irq_remove(ab8500);
+out_freeoldmask:
+       kfree(ab8500->oldmask);
+out_freemask:
+       kfree(ab8500->mask);
 
        return ret;
 }
 
 int __devexit ab8500_exit(struct ab8500 *ab8500)
 {
-       sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
+       if (is_ab9540(ab8500))
+               sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
+       else
+               sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
        mfd_remove_devices(ab8500->dev);
        if (ab8500->irq_base) {
                free_irq(ab8500->irq, ab8500);
                ab8500_irq_remove(ab8500);
        }
+       kfree(ab8500->oldmask);
+       kfree(ab8500->mask);
 
        return 0;
 }
index 087fecd71ce032b2ad459467c02aef47197f13ea..b83045f102bed1c93251b41716f4ffc06f8f88f1 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/db8500-prcmu.h>
+#include <linux/mfd/dbx500-prcmu.h>
 
 static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
 {
@@ -23,6 +23,18 @@ static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
        return ret;
 }
 
+static int ab8500_i2c_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
+       u8 data)
+{
+       int ret;
+
+       ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data,
+               &mask, 1);
+       if (ret < 0)
+               dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
+       return ret;
+}
+
 static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
 {
        int ret;
@@ -38,6 +50,7 @@ static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
 
 static int __devinit ab8500_i2c_probe(struct platform_device *plf)
 {
+       const struct platform_device_id *platid = platform_get_device_id(plf);
        struct ab8500 *ab8500;
        struct resource *resource;
        int ret;
@@ -58,13 +71,15 @@ static int __devinit ab8500_i2c_probe(struct platform_device *plf)
 
        ab8500->read = ab8500_i2c_read;
        ab8500->write = ab8500_i2c_write;
+       ab8500->write_masked = ab8500_i2c_write_masked;
 
        platform_set_drvdata(plf, ab8500);
 
-       ret = ab8500_init(ab8500);
+       ret = ab8500_init(ab8500, platid->driver_data);
        if (ret)
                kfree(ab8500);
 
+
        return ret;
 }
 
@@ -78,13 +93,22 @@ static int __devexit ab8500_i2c_remove(struct platform_device *plf)
        return 0;
 }
 
+static const struct platform_device_id ab8500_id[] = {
+       { "ab8500-i2c", AB8500_VERSION_AB8500 },
+       { "ab8505-i2c", AB8500_VERSION_AB8505 },
+       { "ab9540-i2c", AB8500_VERSION_AB9540 },
+       { "ab8540-i2c", AB8500_VERSION_AB8540 },
+       { }
+};
+
 static struct platform_driver ab8500_i2c_driver = {
        .driver = {
                .name = "ab8500-i2c",
                .owner = THIS_MODULE,
        },
        .probe  = ab8500_i2c_probe,
-       .remove = __devexit_p(ab8500_i2c_remove)
+       .remove = __devexit_p(ab8500_i2c_remove),
+       .id_table = ab8500_id,
 };
 
 static int __init ab8500_i2c_init(void)
diff --git a/drivers/mfd/anatop-mfd.c b/drivers/mfd/anatop-mfd.c
new file mode 100644 (file)
index 0000000..2af4248
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Anatop MFD driver
+ *
+ * Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ * Copyright (C) 2012 Linaro
+ *
+ *  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.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *  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.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/mfd/anatop.h>
+
+u32 anatop_get_bits(struct anatop *adata, u32 addr, int bit_shift,
+                   int bit_width)
+{
+       u32 val, mask;
+
+       if (bit_width == 32)
+               mask = ~0;
+       else
+               mask = (1 << bit_width) - 1;
+
+       val = readl(adata->ioreg + addr);
+       val = (val >> bit_shift) & mask;
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(anatop_get_bits);
+
+void anatop_set_bits(struct anatop *adata, u32 addr, int bit_shift,
+                    int bit_width, u32 data)
+{
+       u32 val, mask;
+
+       if (bit_width == 32)
+               mask = ~0;
+       else
+               mask = (1 << bit_width) - 1;
+
+       spin_lock(&adata->reglock);
+       val = readl(adata->ioreg + addr) & ~(mask << bit_shift);
+       writel((data << bit_shift) | val, adata->ioreg + addr);
+       spin_unlock(&adata->reglock);
+}
+EXPORT_SYMBOL_GPL(anatop_set_bits);
+
+static const struct of_device_id of_anatop_match[] = {
+       { .compatible = "fsl,imx6q-anatop", },
+       { },
+};
+
+static int __devinit of_anatop_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       void *ioreg;
+       struct anatop *drvdata;
+
+       ioreg = of_iomap(np, 0);
+       if (!ioreg)
+               return -EADDRNOTAVAIL;
+       drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+       if (!drvdata)
+               return -ENOMEM;
+       drvdata->ioreg = ioreg;
+       spin_lock_init(&drvdata->reglock);
+       platform_set_drvdata(pdev, drvdata);
+       of_platform_populate(np, of_anatop_match, NULL, dev);
+
+       return 0;
+}
+
+static int __devexit of_anatop_remove(struct platform_device *pdev)
+{
+       struct anatop *drvdata;
+       drvdata = platform_get_drvdata(pdev);
+       iounmap(drvdata->ioreg);
+
+       return 0;
+}
+
+static struct platform_driver anatop_of_driver = {
+       .driver = {
+               .name = "anatop-mfd",
+               .owner = THIS_MODULE,
+               .of_match_table = of_anatop_match,
+       },
+       .probe          = of_anatop_probe,
+       .remove         = of_anatop_remove,
+};
+
+static int __init anatop_init(void)
+{
+       return platform_driver_register(&anatop_of_driver);
+}
+postcore_initcall(anatop_init);
+
+static void __exit anatop_exit(void)
+{
+       platform_driver_unregister(&anatop_of_driver);
+}
+module_exit(anatop_exit);
+
+MODULE_AUTHOR("Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>");
+MODULE_DESCRIPTION("ANATOP MFD driver");
+MODULE_LICENSE("GPL v2");
index b85bbd7f0d1980f16e78a49cae46658b1158627b..1895cf9fab8c1b1c491cbc611335775f014760e0 100644 (file)
@@ -525,6 +525,11 @@ static void asic3_gpio_set(struct gpio_chip *chip,
        return;
 }
 
+static int asic3_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       return (offset < ASIC3_NUM_GPIOS) ? IRQ_BOARD_START + offset : -ENXIO;
+}
+
 static __init int asic3_gpio_probe(struct platform_device *pdev,
                                   u16 *gpio_config, int num)
 {
@@ -976,6 +981,7 @@ static int __init asic3_probe(struct platform_device *pdev)
        asic->gpio.set = asic3_gpio_set;
        asic->gpio.direction_input = asic3_gpio_direction_input;
        asic->gpio.direction_output = asic3_gpio_direction_output;
+       asic->gpio.to_irq = asic3_gpio_to_irq;
 
        ret = asic3_gpio_probe(pdev,
                               pdata->gpio_config,
index 5ddde2a9176afa32a8211d2951fc36cbccc85d64..7ff313fe9fb112afd5175dc9b091d224ea936f7e 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
-#include <linux/mutex.h>
 #include <linux/mfd/core.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -647,8 +646,6 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id)
        struct irq_desc *desc;
        int ret;
 
-       mutex_init(&da9052->io_lock);
-
        if (pdata && pdata->init != NULL)
                pdata->init(da9052);
 
index 44b97c70a61f9671342c2bd23aad0416e7239d25..36b88e395499f1673ecb57eee39b0c6a3fa920cd 100644 (file)
@@ -74,24 +74,27 @@ static int __devinit da9052_i2c_probe(struct i2c_client *client,
 
        ret = da9052_i2c_enable_multiwrite(da9052);
        if (ret < 0)
-               goto err;
+               goto err_regmap;
 
        ret = da9052_device_init(da9052, id->driver_data);
        if (ret != 0)
-               goto err;
+               goto err_regmap;
 
        return 0;
 
+err_regmap:
+       regmap_exit(da9052->regmap);
 err:
        kfree(da9052);
        return ret;
 }
 
-static int da9052_i2c_remove(struct i2c_client *client)
+static int __devexit da9052_i2c_remove(struct i2c_client *client)
 {
        struct da9052 *da9052 = i2c_get_clientdata(client);
 
        da9052_device_exit(da9052);
+       regmap_exit(da9052->regmap);
        kfree(da9052);
 
        return 0;
@@ -107,7 +110,7 @@ static struct i2c_device_id da9052_i2c_id[] = {
 
 static struct i2c_driver da9052_i2c_driver = {
        .probe = da9052_i2c_probe,
-       .remove = da9052_i2c_remove,
+       .remove = __devexit_p(da9052_i2c_remove),
        .id_table = da9052_i2c_id,
        .driver = {
                .name = "da9052",
index cdbc7cad326fdb360dd081c02ced384232da8724..6faf149e8d94c8d2b90c3ef69edc6d2e98a0fa6d 100644 (file)
@@ -21,7 +21,7 @@
 
 #include <linux/mfd/da9052/da9052.h>
 
-static int da9052_spi_probe(struct spi_device *spi)
+static int __devinit da9052_spi_probe(struct spi_device *spi)
 {
        int ret;
        const struct spi_device_id *id = spi_get_device_id(spi);
@@ -52,20 +52,23 @@ static int da9052_spi_probe(struct spi_device *spi)
 
        ret = da9052_device_init(da9052, id->driver_data);
        if (ret != 0)
-               goto err;
+               goto err_regmap;
 
        return 0;
 
+err_regmap:
+       regmap_exit(da9052->regmap);
 err:
        kfree(da9052);
        return ret;
 }
 
-static int da9052_spi_remove(struct spi_device *spi)
+static int __devexit da9052_spi_remove(struct spi_device *spi)
 {
        struct da9052 *da9052 = dev_get_drvdata(&spi->dev);
 
        da9052_device_exit(da9052);
+       regmap_exit(da9052->regmap);
        kfree(da9052);
 
        return 0;
index af8e0efedbe477a3ba096c6678dd0a84ac948e2f..ebc1e8658226bbfca7505f2d109d119a9598e690 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/mfd/dbx500-prcmu.h>
 #include <linux/regulator/db8500-prcmu.h>
 #include <linux/regulator/machine.h>
+#include <asm/hardware/gic.h>
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/db8500-regs.h>
 /* Offset for the firmware version within the TCPM */
 #define PRCMU_FW_VERSION_OFFSET 0xA4
 
-/* PRCMU project numbers, defined by PRCMU FW */
-#define PRCMU_PROJECT_ID_8500V1_0 1
-#define PRCMU_PROJECT_ID_8500V2_0 2
-#define PRCMU_PROJECT_ID_8400V2_0 3
-
 /* Index of different voltages to be used when accessing AVSData */
 #define PRCM_AVS_BASE          0x2FC
 #define PRCM_AVS_VBB_RET       (PRCM_AVS_BASE + 0x0)
 #define PRCM_REQ_MB1_ARM_OPP                   (PRCM_REQ_MB1 + 0x0)
 #define PRCM_REQ_MB1_APE_OPP                   (PRCM_REQ_MB1 + 0x1)
 #define PRCM_REQ_MB1_PLL_ON_OFF                        (PRCM_REQ_MB1 + 0x4)
+#define PLL_SOC0_OFF   0x1
+#define PLL_SOC0_ON    0x2
 #define PLL_SOC1_OFF   0x4
 #define PLL_SOC1_ON    0x8
 
 #define WAKEUP_BIT_GPIO7 BIT(30)
 #define WAKEUP_BIT_GPIO8 BIT(31)
 
+static struct {
+       bool valid;
+       struct prcmu_fw_version version;
+} fw_info;
+
 /*
  * This vector maps irq numbers to the bits in the bit field used in
  * communication with the PRCMU firmware.
@@ -341,11 +344,13 @@ static struct {
  * mb1_transfer - state needed for mailbox 1 communication.
  * @lock:      The transaction lock.
  * @work:      The transaction completion structure.
+ * @ape_opp:   The current APE OPP.
  * @ack:       Reply ("acknowledge") data.
  */
 static struct {
        struct mutex lock;
        struct completion work;
+       u8 ape_opp;
        struct {
                u8 header;
                u8 arm_opp;
@@ -413,79 +418,102 @@ static struct {
 static atomic_t ac_wake_req_state = ATOMIC_INIT(0);
 
 /* Spinlocks */
+static DEFINE_SPINLOCK(prcmu_lock);
 static DEFINE_SPINLOCK(clkout_lock);
-static DEFINE_SPINLOCK(gpiocr_lock);
 
 /* Global var to runtime determine TCDM base for v2 or v1 */
 static __iomem void *tcdm_base;
 
 struct clk_mgt {
-       unsigned int offset;
+       void __iomem *reg;
        u32 pllsw;
+       int branch;
+       bool clk38div;
+};
+
+enum {
+       PLL_RAW,
+       PLL_FIX,
+       PLL_DIV
 };
 
 static DEFINE_SPINLOCK(clk_mgt_lock);
 
-#define CLK_MGT_ENTRY(_name)[PRCMU_##_name] = { (PRCM_##_name##_MGT_OFF), 0 }
+#define CLK_MGT_ENTRY(_name, _branch, _clk38div)[PRCMU_##_name] = \
+       { (PRCM_##_name##_MGT), 0 , _branch, _clk38div}
 struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
-       CLK_MGT_ENTRY(SGACLK),
-       CLK_MGT_ENTRY(UARTCLK),
-       CLK_MGT_ENTRY(MSP02CLK),
-       CLK_MGT_ENTRY(MSP1CLK),
-       CLK_MGT_ENTRY(I2CCLK),
-       CLK_MGT_ENTRY(SDMMCCLK),
-       CLK_MGT_ENTRY(SLIMCLK),
-       CLK_MGT_ENTRY(PER1CLK),
-       CLK_MGT_ENTRY(PER2CLK),
-       CLK_MGT_ENTRY(PER3CLK),
-       CLK_MGT_ENTRY(PER5CLK),
-       CLK_MGT_ENTRY(PER6CLK),
-       CLK_MGT_ENTRY(PER7CLK),
-       CLK_MGT_ENTRY(LCDCLK),
-       CLK_MGT_ENTRY(BMLCLK),
-       CLK_MGT_ENTRY(HSITXCLK),
-       CLK_MGT_ENTRY(HSIRXCLK),
-       CLK_MGT_ENTRY(HDMICLK),
-       CLK_MGT_ENTRY(APEATCLK),
-       CLK_MGT_ENTRY(APETRACECLK),
-       CLK_MGT_ENTRY(MCDECLK),
-       CLK_MGT_ENTRY(IPI2CCLK),
-       CLK_MGT_ENTRY(DSIALTCLK),
-       CLK_MGT_ENTRY(DMACLK),
-       CLK_MGT_ENTRY(B2R2CLK),
-       CLK_MGT_ENTRY(TVCLK),
-       CLK_MGT_ENTRY(SSPCLK),
-       CLK_MGT_ENTRY(RNGCLK),
-       CLK_MGT_ENTRY(UICCCLK),
+       CLK_MGT_ENTRY(SGACLK, PLL_DIV, false),
+       CLK_MGT_ENTRY(UARTCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(MSP02CLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(MSP1CLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(I2CCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(SDMMCCLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(SLIMCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(PER1CLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(PER2CLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(PER3CLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(PER5CLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(PER6CLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(PER7CLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(LCDCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(BMLCLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(HSITXCLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(HSIRXCLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(HDMICLK, PLL_FIX, false),
+       CLK_MGT_ENTRY(APEATCLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(APETRACECLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(MCDECLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(IPI2CCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(DSIALTCLK, PLL_FIX, false),
+       CLK_MGT_ENTRY(DMACLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(B2R2CLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(TVCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(SSPCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(RNGCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(UICCCLK, PLL_FIX, false),
+};
+
+struct dsiclk {
+       u32 divsel_mask;
+       u32 divsel_shift;
+       u32 divsel;
+};
+
+static struct dsiclk dsiclk[2] = {
+       {
+               .divsel_mask = PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_MASK,
+               .divsel_shift = PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_SHIFT,
+               .divsel = PRCM_DSI_PLLOUT_SEL_PHI,
+       },
+       {
+               .divsel_mask = PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_MASK,
+               .divsel_shift = PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_SHIFT,
+               .divsel = PRCM_DSI_PLLOUT_SEL_PHI,
+       }
 };
 
-static struct regulator *hwacc_regulator[NUM_HW_ACC];
-static struct regulator *hwacc_ret_regulator[NUM_HW_ACC];
-
-static bool hwacc_enabled[NUM_HW_ACC];
-static bool hwacc_ret_enabled[NUM_HW_ACC];
-
-static const char *hwacc_regulator_name[NUM_HW_ACC] = {
-       [HW_ACC_SVAMMDSP]       = "hwacc-sva-mmdsp",
-       [HW_ACC_SVAPIPE]        = "hwacc-sva-pipe",
-       [HW_ACC_SIAMMDSP]       = "hwacc-sia-mmdsp",
-       [HW_ACC_SIAPIPE]        = "hwacc-sia-pipe",
-       [HW_ACC_SGA]            = "hwacc-sga",
-       [HW_ACC_B2R2]           = "hwacc-b2r2",
-       [HW_ACC_MCDE]           = "hwacc-mcde",
-       [HW_ACC_ESRAM1]         = "hwacc-esram1",
-       [HW_ACC_ESRAM2]         = "hwacc-esram2",
-       [HW_ACC_ESRAM3]         = "hwacc-esram3",
-       [HW_ACC_ESRAM4]         = "hwacc-esram4",
+struct dsiescclk {
+       u32 en;
+       u32 div_mask;
+       u32 div_shift;
 };
 
-static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
-       [HW_ACC_SVAMMDSP]       = "hwacc-sva-mmdsp-ret",
-       [HW_ACC_SIAMMDSP]       = "hwacc-sia-mmdsp-ret",
-       [HW_ACC_ESRAM1]         = "hwacc-esram1-ret",
-       [HW_ACC_ESRAM2]         = "hwacc-esram2-ret",
-       [HW_ACC_ESRAM3]         = "hwacc-esram3-ret",
-       [HW_ACC_ESRAM4]         = "hwacc-esram4-ret",
+static struct dsiescclk dsiescclk[3] = {
+       {
+               .en = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_EN,
+               .div_mask = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_MASK,
+               .div_shift = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_SHIFT,
+       },
+       {
+               .en = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_EN,
+               .div_mask = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_MASK,
+               .div_shift = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_SHIFT,
+       },
+       {
+               .en = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_EN,
+               .div_mask = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_MASK,
+               .div_shift = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_SHIFT,
+       }
 };
 
 /*
@@ -503,9 +531,6 @@ static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
 /* PLLDIV=12, PLLSW=4 (PLLDDR) */
 #define PRCMU_DSI_CLOCK_SETTING                0x0000008C
 
-/* PLLDIV=8, PLLSW=4 (PLLDDR) */
-#define PRCMU_DSI_CLOCK_SETTING_U8400  0x00000088
-
 /* DPI 50000000 Hz */
 #define PRCMU_DPI_CLOCK_SETTING                ((1 << PRCMU_CLK_PLL_SW_SHIFT) | \
                                          (16 << PRCMU_CLK_PLL_DIV_SHIFT))
@@ -514,9 +539,6 @@ static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
 /* D=101, N=1, R=4, SELDIV2=0 */
 #define PRCMU_PLLDSI_FREQ_SETTING      0x00040165
 
-/* D=70, N=1, R=3, SELDIV2=0 */
-#define PRCMU_PLLDSI_FREQ_SETTING_U8400        0x00030146
-
 #define PRCMU_ENABLE_PLLDSI            0x00000001
 #define PRCMU_DISABLE_PLLDSI           0x00000000
 #define PRCMU_RELEASE_RESET_DSS                0x0000400C
@@ -528,30 +550,17 @@ static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
 
 #define PRCMU_PLLDSI_LOCKP_LOCKED      0x3
 
-static struct {
-       u8 project_number;
-       u8 api_version;
-       u8 func_version;
-       u8 errata;
-} prcmu_version;
-
-
 int db8500_prcmu_enable_dsipll(void)
 {
        int i;
-       unsigned int plldsifreq;
 
        /* Clear DSIPLL_RESETN */
        writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR);
        /* Unclamp DSIPLL in/out */
        writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR);
 
-       if (prcmu_is_u8400())
-               plldsifreq = PRCMU_PLLDSI_FREQ_SETTING_U8400;
-       else
-               plldsifreq = PRCMU_PLLDSI_FREQ_SETTING;
        /* Set DSI PLL FREQ */
-       writel(plldsifreq, PRCM_PLLDSI_FREQ);
+       writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ);
        writel(PRCMU_DSI_PLLOUT_SEL_SETTING, PRCM_DSI_PLLOUT_SEL);
        /* Enable Escape clocks */
        writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
@@ -583,12 +592,6 @@ int db8500_prcmu_disable_dsipll(void)
 int db8500_prcmu_set_display_clocks(void)
 {
        unsigned long flags;
-       unsigned int dsiclk;
-
-       if (prcmu_is_u8400())
-               dsiclk = PRCMU_DSI_CLOCK_SETTING_U8400;
-       else
-               dsiclk = PRCMU_DSI_CLOCK_SETTING;
 
        spin_lock_irqsave(&clk_mgt_lock, flags);
 
@@ -596,7 +599,7 @@ int db8500_prcmu_set_display_clocks(void)
        while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
                cpu_relax();
 
-       writel(dsiclk, PRCM_HDMICLK_MGT);
+       writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT);
        writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT);
        writel(PRCMU_DPI_CLOCK_SETTING, PRCM_LCDCLK_MGT);
 
@@ -608,43 +611,41 @@ int db8500_prcmu_set_display_clocks(void)
        return 0;
 }
 
-/**
- * prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1.
- */
-void prcmu_enable_spi2(void)
+u32 db8500_prcmu_read(unsigned int reg)
+{
+       return readl(_PRCMU_BASE + reg);
+}
+
+void db8500_prcmu_write(unsigned int reg, u32 value)
 {
-       u32 reg;
        unsigned long flags;
 
-       spin_lock_irqsave(&gpiocr_lock, flags);
-       reg = readl(PRCM_GPIOCR);
-       writel(reg | PRCM_GPIOCR_SPI2_SELECT, PRCM_GPIOCR);
-       spin_unlock_irqrestore(&gpiocr_lock, flags);
+       spin_lock_irqsave(&prcmu_lock, flags);
+       writel(value, (_PRCMU_BASE + reg));
+       spin_unlock_irqrestore(&prcmu_lock, flags);
 }
 
-/**
- * prcmu_disable_spi2 - Disables pin muxing for SPI2 on OtherAlternateC1.
- */
-void prcmu_disable_spi2(void)
+void db8500_prcmu_write_masked(unsigned int reg, u32 mask, u32 value)
 {
-       u32 reg;
+       u32 val;
        unsigned long flags;
 
-       spin_lock_irqsave(&gpiocr_lock, flags);
-       reg = readl(PRCM_GPIOCR);
-       writel(reg & ~PRCM_GPIOCR_SPI2_SELECT, PRCM_GPIOCR);
-       spin_unlock_irqrestore(&gpiocr_lock, flags);
+       spin_lock_irqsave(&prcmu_lock, flags);
+       val = readl(_PRCMU_BASE + reg);
+       val = ((val & ~mask) | (value & mask));
+       writel(val, (_PRCMU_BASE + reg));
+       spin_unlock_irqrestore(&prcmu_lock, flags);
 }
 
-bool prcmu_has_arm_maxopp(void)
+struct prcmu_fw_version *prcmu_get_fw_version(void)
 {
-       return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) &
-               PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK;
+       return fw_info.valid ? &fw_info.version : NULL;
 }
 
-bool prcmu_is_u8400(void)
+bool prcmu_has_arm_maxopp(void)
 {
-       return prcmu_version.project_number == PRCMU_PROJECT_ID_8400V2_0;
+       return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) &
+               PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK;
 }
 
 /**
@@ -787,6 +788,124 @@ int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll)
        return 0;
 }
 
+u8 db8500_prcmu_get_power_state_result(void)
+{
+       return readb(tcdm_base + PRCM_ACK_MB0_AP_PWRSTTR_STATUS);
+}
+
+/* This function decouple the gic from the prcmu */
+int db8500_prcmu_gic_decouple(void)
+{
+       u32 val = readl(PRCM_A9_MASK_REQ);
+
+       /* Set bit 0 register value to 1 */
+       writel(val | PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ,
+              PRCM_A9_MASK_REQ);
+
+       /* Make sure the register is updated */
+       readl(PRCM_A9_MASK_REQ);
+
+       /* Wait a few cycles for the gic mask completion */
+       udelay(1);
+
+       return 0;
+}
+
+/* This function recouple the gic with the prcmu */
+int db8500_prcmu_gic_recouple(void)
+{
+       u32 val = readl(PRCM_A9_MASK_REQ);
+
+       /* Set bit 0 register value to 0 */
+       writel(val & ~PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ, PRCM_A9_MASK_REQ);
+
+       return 0;
+}
+
+#define PRCMU_GIC_NUMBER_REGS 5
+
+/*
+ * This function checks if there are pending irq on the gic. It only
+ * makes sense if the gic has been decoupled before with the
+ * db8500_prcmu_gic_decouple function. Disabling an interrupt only
+ * disables the forwarding of the interrupt to any CPU interface. It
+ * does not prevent the interrupt from changing state, for example
+ * becoming pending, or active and pending if it is already
+ * active. Hence, we have to check the interrupt is pending *and* is
+ * active.
+ */
+bool db8500_prcmu_gic_pending_irq(void)
+{
+       u32 pr; /* Pending register */
+       u32 er; /* Enable register */
+       void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
+       int i;
+
+        /* 5 registers. STI & PPI not skipped */
+       for (i = 0; i < PRCMU_GIC_NUMBER_REGS; i++) {
+
+               pr = readl_relaxed(dist_base + GIC_DIST_PENDING_SET + i * 4);
+               er = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+               if (pr & er)
+                       return true; /* There is a pending interrupt */
+       }
+
+       return false;
+}
+
+/*
+ * This function checks if there are pending interrupt on the
+ * prcmu which has been delegated to monitor the irqs with the
+ * db8500_prcmu_copy_gic_settings function.
+ */
+bool db8500_prcmu_pending_irq(void)
+{
+       u32 it, im;
+       int i;
+
+       for (i = 0; i < PRCMU_GIC_NUMBER_REGS - 1; i++) {
+               it = readl(PRCM_ARMITVAL31TO0 + i * 4);
+               im = readl(PRCM_ARMITMSK31TO0 + i * 4);
+               if (it & im)
+                       return true; /* There is a pending interrupt */
+       }
+
+       return false;
+}
+
+/*
+ * This function checks if the specified cpu is in in WFI. It's usage
+ * makes sense only if the gic is decoupled with the db8500_prcmu_gic_decouple
+ * function. Of course passing smp_processor_id() to this function will
+ * always return false...
+ */
+bool db8500_prcmu_is_cpu_in_wfi(int cpu)
+{
+       return readl(PRCM_ARM_WFI_STANDBY) & cpu ? PRCM_ARM_WFI_STANDBY_WFI1 :
+                    PRCM_ARM_WFI_STANDBY_WFI0;
+}
+
+/*
+ * This function copies the gic SPI settings to the prcmu in order to
+ * monitor them and abort/finish the retention/off sequence or state.
+ */
+int db8500_prcmu_copy_gic_settings(void)
+{
+       u32 er; /* Enable register */
+       void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
+       int i;
+
+        /* We skip the STI and PPI */
+       for (i = 0; i < PRCMU_GIC_NUMBER_REGS - 1; i++) {
+               er = readl_relaxed(dist_base +
+                                  GIC_DIST_ENABLE_SET + (i + 1) * 4);
+               writel(er, PRCM_ARMITMSK31TO0 + i * 4);
+       }
+
+       return 0;
+}
+
 /* This function should only be called while mb0_transfer.lock is held. */
 static void config_wakeups(void)
 {
@@ -909,23 +1028,23 @@ int db8500_prcmu_get_arm_opp(void)
 }
 
 /**
- * prcmu_get_ddr_opp - get the current DDR OPP
+ * db8500_prcmu_get_ddr_opp - get the current DDR OPP
  *
  * Returns: the current DDR OPP
  */
-int prcmu_get_ddr_opp(void)
+int db8500_prcmu_get_ddr_opp(void)
 {
        return readb(PRCM_DDR_SUBSYS_APE_MINBW);
 }
 
 /**
- * set_ddr_opp - set the appropriate DDR OPP
+ * db8500_set_ddr_opp - set the appropriate DDR OPP
  * @opp: The new DDR operating point to which transition is to be made
  * Returns: 0 on success, non-zero on failure
  *
  * This function sets the operating point of the DDR.
  */
-int prcmu_set_ddr_opp(u8 opp)
+int db8500_prcmu_set_ddr_opp(u8 opp)
 {
        if (opp < DDR_100_OPP || opp > DDR_25_OPP)
                return -EINVAL;
@@ -935,25 +1054,82 @@ int prcmu_set_ddr_opp(u8 opp)
 
        return 0;
 }
+
+/* Divide the frequency of certain clocks by 2 for APE_50_PARTLY_25_OPP. */
+static void request_even_slower_clocks(bool enable)
+{
+       void __iomem *clock_reg[] = {
+               PRCM_ACLK_MGT,
+               PRCM_DMACLK_MGT
+       };
+       unsigned long flags;
+       unsigned int i;
+
+       spin_lock_irqsave(&clk_mgt_lock, flags);
+
+       /* Grab the HW semaphore. */
+       while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+               cpu_relax();
+
+       for (i = 0; i < ARRAY_SIZE(clock_reg); i++) {
+               u32 val;
+               u32 div;
+
+               val = readl(clock_reg[i]);
+               div = (val & PRCM_CLK_MGT_CLKPLLDIV_MASK);
+               if (enable) {
+                       if ((div <= 1) || (div > 15)) {
+                               pr_err("prcmu: Bad clock divider %d in %s\n",
+                                       div, __func__);
+                               goto unlock_and_return;
+                       }
+                       div <<= 1;
+               } else {
+                       if (div <= 2)
+                               goto unlock_and_return;
+                       div >>= 1;
+               }
+               val = ((val & ~PRCM_CLK_MGT_CLKPLLDIV_MASK) |
+                       (div & PRCM_CLK_MGT_CLKPLLDIV_MASK));
+               writel(val, clock_reg[i]);
+       }
+
+unlock_and_return:
+       /* Release the HW semaphore. */
+       writel(0, PRCM_SEM);
+
+       spin_unlock_irqrestore(&clk_mgt_lock, flags);
+}
+
 /**
- * set_ape_opp - set the appropriate APE OPP
+ * db8500_set_ape_opp - set the appropriate APE OPP
  * @opp: The new APE operating point to which transition is to be made
  * Returns: 0 on success, non-zero on failure
  *
  * This function sets the operating point of the APE.
  */
-int prcmu_set_ape_opp(u8 opp)
+int db8500_prcmu_set_ape_opp(u8 opp)
 {
        int r = 0;
 
+       if (opp == mb1_transfer.ape_opp)
+               return 0;
+
        mutex_lock(&mb1_transfer.lock);
 
+       if (mb1_transfer.ape_opp == APE_50_PARTLY_25_OPP)
+               request_even_slower_clocks(false);
+
+       if ((opp != APE_100_OPP) && (mb1_transfer.ape_opp != APE_100_OPP))
+               goto skip_message;
+
        while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
                cpu_relax();
 
        writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
        writeb(ARM_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_ARM_OPP));
-       writeb(opp, (tcdm_base + PRCM_REQ_MB1_APE_OPP));
+       writeb(((opp == APE_50_PARTLY_25_OPP) ? APE_50_OPP : opp),
+               (tcdm_base + PRCM_REQ_MB1_APE_OPP));
 
        writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
        wait_for_completion(&mb1_transfer.work);
@@ -962,17 +1138,24 @@ int prcmu_set_ape_opp(u8 opp)
                (mb1_transfer.ack.ape_opp != opp))
                r = -EIO;
 
+skip_message:
+       if ((!r && (opp == APE_50_PARTLY_25_OPP)) ||
+               (r && (mb1_transfer.ape_opp == APE_50_PARTLY_25_OPP)))
+               request_even_slower_clocks(true);
+       if (!r)
+               mb1_transfer.ape_opp = opp;
+
        mutex_unlock(&mb1_transfer.lock);
 
        return r;
 }
 
 /**
- * prcmu_get_ape_opp - get the current APE OPP
+ * db8500_prcmu_get_ape_opp - get the current APE OPP
  *
  * Returns: the current APE OPP
  */
-int prcmu_get_ape_opp(void)
+int db8500_prcmu_get_ape_opp(void)
 {
        return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_APE_OPP);
 }
@@ -1056,7 +1239,9 @@ static int request_pll(u8 clock, bool enable)
 {
        int r = 0;
 
-       if (clock == PRCMU_PLLSOC1)
+       if (clock == PRCMU_PLLSOC0)
+               clock = (enable ? PLL_SOC0_ON : PLL_SOC0_OFF);
+       else if (clock == PRCMU_PLLSOC1)
                clock = (enable ? PLL_SOC1_ON : PLL_SOC1_OFF);
        else
                return -EINVAL;
@@ -1080,132 +1265,6 @@ static int request_pll(u8 clock, bool enable)
        return r;
 }
 
-/**
- * prcmu_set_hwacc - set the power state of a h/w accelerator
- * @hwacc_dev: The hardware accelerator (enum hw_acc_dev).
- * @state: The new power state (enum hw_acc_state).
- *
- * This function sets the power state of a hardware accelerator.
- * This function should not be called from interrupt context.
- *
- * NOTE! Deprecated, to be removed when all users switched over to use the
- * regulator framework API.
- */
-int prcmu_set_hwacc(u16 hwacc_dev, u8 state)
-{
-       int r = 0;
-       bool ram_retention = false;
-       bool enable, enable_ret;
-
-       /* check argument */
-       BUG_ON(hwacc_dev >= NUM_HW_ACC);
-
-       /* get state of switches */
-       enable = hwacc_enabled[hwacc_dev];
-       enable_ret = hwacc_ret_enabled[hwacc_dev];
-
-       /* set flag if retention is possible */
-       switch (hwacc_dev) {
-       case HW_ACC_SVAMMDSP:
-       case HW_ACC_SIAMMDSP:
-       case HW_ACC_ESRAM1:
-       case HW_ACC_ESRAM2:
-       case HW_ACC_ESRAM3:
-       case HW_ACC_ESRAM4:
-               ram_retention = true;
-               break;
-       }
-
-       /* check argument */
-       BUG_ON(state > HW_ON);
-       BUG_ON(state == HW_OFF_RAMRET && !ram_retention);
-
-       /* modify enable flags */
-       switch (state) {
-       case HW_OFF:
-               enable_ret = false;
-               enable = false;
-               break;
-       case HW_ON:
-               enable = true;
-               break;
-       case HW_OFF_RAMRET:
-               enable_ret = true;
-               enable = false;
-               break;
-       }
-
-       /* get regulator (lazy) */
-       if (hwacc_regulator[hwacc_dev] == NULL) {
-               hwacc_regulator[hwacc_dev] = regulator_get(NULL,
-                       hwacc_regulator_name[hwacc_dev]);
-               if (IS_ERR(hwacc_regulator[hwacc_dev])) {
-                       pr_err("prcmu: failed to get supply %s\n",
-                               hwacc_regulator_name[hwacc_dev]);
-                       r = PTR_ERR(hwacc_regulator[hwacc_dev]);
-                       goto out;
-               }
-       }
-
-       if (ram_retention) {
-               if (hwacc_ret_regulator[hwacc_dev] == NULL) {
-                       hwacc_ret_regulator[hwacc_dev] = regulator_get(NULL,
-                               hwacc_ret_regulator_name[hwacc_dev]);
-                       if (IS_ERR(hwacc_ret_regulator[hwacc_dev])) {
-                               pr_err("prcmu: failed to get supply %s\n",
-                                       hwacc_ret_regulator_name[hwacc_dev]);
-                               r = PTR_ERR(hwacc_ret_regulator[hwacc_dev]);
-                               goto out;
-                       }
-               }
-       }
-
-       /* set regulators */
-       if (ram_retention) {
-               if (enable_ret && !hwacc_ret_enabled[hwacc_dev]) {
-                       r = regulator_enable(hwacc_ret_regulator[hwacc_dev]);
-                       if (r < 0) {
-                               pr_err("prcmu_set_hwacc: ret enable failed\n");
-                               goto out;
-                       }
-                       hwacc_ret_enabled[hwacc_dev] = true;
-               }
-       }
-
-       if (enable && !hwacc_enabled[hwacc_dev]) {
-               r = regulator_enable(hwacc_regulator[hwacc_dev]);
-               if (r < 0) {
-                       pr_err("prcmu_set_hwacc: enable failed\n");
-                       goto out;
-               }
-               hwacc_enabled[hwacc_dev] = true;
-       }
-
-       if (!enable && hwacc_enabled[hwacc_dev]) {
-               r = regulator_disable(hwacc_regulator[hwacc_dev]);
-               if (r < 0) {
-                       pr_err("prcmu_set_hwacc: disable failed\n");
-                       goto out;
-               }
-               hwacc_enabled[hwacc_dev] = false;
-       }
-
-       if (ram_retention) {
-               if (!enable_ret && hwacc_ret_enabled[hwacc_dev]) {
-                       r = regulator_disable(hwacc_ret_regulator[hwacc_dev]);
-                       if (r < 0) {
-                               pr_err("prcmu_set_hwacc: ret disable failed\n");
-                               goto out;
-                       }
-                       hwacc_ret_enabled[hwacc_dev] = false;
-               }
-       }
-
-out:
-       return r;
-}
-EXPORT_SYMBOL(prcmu_set_hwacc);
-
 /**
  * db8500_prcmu_set_epod - set the state of a EPOD (power domain)
  * @epod_id: The EPOD to set
@@ -1375,7 +1434,7 @@ static int request_timclk(bool enable)
        return 0;
 }
 
-static int request_reg_clock(u8 clock, bool enable)
+static int request_clock(u8 clock, bool enable)
 {
        u32 val;
        unsigned long flags;
@@ -1386,14 +1445,14 @@ static int request_reg_clock(u8 clock, bool enable)
        while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
                cpu_relax();
 
-       val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
+       val = readl(clk_mgt[clock].reg);
        if (enable) {
                val |= (PRCM_CLK_MGT_CLKEN | clk_mgt[clock].pllsw);
        } else {
                clk_mgt[clock].pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
                val &= ~(PRCM_CLK_MGT_CLKEN | PRCM_CLK_MGT_CLKPLLSW_MASK);
        }
-       writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
+       writel(val, clk_mgt[clock].reg);
 
        /* Release the HW semaphore. */
        writel(0, PRCM_SEM);
@@ -1413,7 +1472,7 @@ static int request_sga_clock(u8 clock, bool enable)
                writel(val | PRCM_CGATING_BYPASS_ICN2, PRCM_CGATING_BYPASS);
        }
 
-       ret = request_reg_clock(clock, enable);
+       ret = request_clock(clock, enable);
 
        if (!ret && !enable) {
                val = readl(PRCM_CGATING_BYPASS);
@@ -1423,6 +1482,78 @@ static int request_sga_clock(u8 clock, bool enable)
        return ret;
 }
 
+static inline bool plldsi_locked(void)
+{
+       return (readl(PRCM_PLLDSI_LOCKP) &
+               (PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10 |
+                PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3)) ==
+               (PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10 |
+                PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3);
+}
+
+static int request_plldsi(bool enable)
+{
+       int r = 0;
+       u32 val;
+
+       writel((PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP |
+               PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI), (enable ?
+               PRCM_MMIP_LS_CLAMP_CLR : PRCM_MMIP_LS_CLAMP_SET));
+
+       val = readl(PRCM_PLLDSI_ENABLE);
+       if (enable)
+               val |= PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
+       else
+               val &= ~PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
+       writel(val, PRCM_PLLDSI_ENABLE);
+
+       if (enable) {
+               unsigned int i;
+               bool locked = plldsi_locked();
+
+               for (i = 10; !locked && (i > 0); --i) {
+                       udelay(100);
+                       locked = plldsi_locked();
+               }
+               if (locked) {
+                       writel(PRCM_APE_RESETN_DSIPLL_RESETN,
+                               PRCM_APE_RESETN_SET);
+               } else {
+                       writel((PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP |
+                               PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI),
+                               PRCM_MMIP_LS_CLAMP_SET);
+                       val &= ~PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
+                       writel(val, PRCM_PLLDSI_ENABLE);
+                       r = -EAGAIN;
+               }
+       } else {
+               writel(PRCM_APE_RESETN_DSIPLL_RESETN, PRCM_APE_RESETN_CLR);
+       }
+       return r;
+}
+
+static int request_dsiclk(u8 n, bool enable)
+{
+       u32 val;
+
+       val = readl(PRCM_DSI_PLLOUT_SEL);
+       val &= ~dsiclk[n].divsel_mask;
+       val |= ((enable ? dsiclk[n].divsel : PRCM_DSI_PLLOUT_SEL_OFF) <<
+               dsiclk[n].divsel_shift);
+       writel(val, PRCM_DSI_PLLOUT_SEL);
+       return 0;
+}
+
+static int request_dsiescclk(u8 n, bool enable)
+{
+       u32 val;
+
+       val = readl(PRCM_DSITVCLK_DIV);
+       enable ? (val |= dsiescclk[n].en) : (val &= ~dsiescclk[n].en);
+       writel(val, PRCM_DSITVCLK_DIV);
+       return 0;
+}
+
 /**
  * db8500_prcmu_request_clock() - Request for a clock to be enabled or disabled.
  * @clock:      The clock for which the request is made.
@@ -1433,21 +1564,435 @@ static int request_sga_clock(u8 clock, bool enable)
  */
 int db8500_prcmu_request_clock(u8 clock, bool enable)
 {
-       switch(clock) {
-       case PRCMU_SGACLK:
+       if (clock == PRCMU_SGACLK)
                return request_sga_clock(clock, enable);
-       case PRCMU_TIMCLK:
+       else if (clock < PRCMU_NUM_REG_CLOCKS)
+               return request_clock(clock, enable);
+       else if (clock == PRCMU_TIMCLK)
                return request_timclk(enable);
-       case PRCMU_SYSCLK:
+       else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+               return request_dsiclk((clock - PRCMU_DSI0CLK), enable);
+       else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+               return request_dsiescclk((clock - PRCMU_DSI0ESCCLK), enable);
+       else if (clock == PRCMU_PLLDSI)
+               return request_plldsi(enable);
+       else if (clock == PRCMU_SYSCLK)
                return request_sysclk(enable);
-       case PRCMU_PLLSOC1:
+       else if ((clock == PRCMU_PLLSOC0) || (clock == PRCMU_PLLSOC1))
                return request_pll(clock, enable);
+       else
+               return -EINVAL;
+}
+
+static unsigned long pll_rate(void __iomem *reg, unsigned long src_rate,
+       int branch)
+{
+       u64 rate;
+       u32 val;
+       u32 d;
+       u32 div = 1;
+
+       val = readl(reg);
+
+       rate = src_rate;
+       rate *= ((val & PRCM_PLL_FREQ_D_MASK) >> PRCM_PLL_FREQ_D_SHIFT);
+
+       d = ((val & PRCM_PLL_FREQ_N_MASK) >> PRCM_PLL_FREQ_N_SHIFT);
+       if (d > 1)
+               div *= d;
+
+       d = ((val & PRCM_PLL_FREQ_R_MASK) >> PRCM_PLL_FREQ_R_SHIFT);
+       if (d > 1)
+               div *= d;
+
+       if (val & PRCM_PLL_FREQ_SELDIV2)
+               div *= 2;
+
+       if ((branch == PLL_FIX) || ((branch == PLL_DIV) &&
+               (val & PRCM_PLL_FREQ_DIV2EN) &&
+               ((reg == PRCM_PLLSOC0_FREQ) ||
+                (reg == PRCM_PLLDDR_FREQ))))
+               div *= 2;
+
+       (void)do_div(rate, div);
+
+       return (unsigned long)rate;
+}
+
+#define ROOT_CLOCK_RATE 38400000
+
+static unsigned long clock_rate(u8 clock)
+{
+       u32 val;
+       u32 pllsw;
+       unsigned long rate = ROOT_CLOCK_RATE;
+
+       val = readl(clk_mgt[clock].reg);
+
+       if (val & PRCM_CLK_MGT_CLK38) {
+               if (clk_mgt[clock].clk38div && (val & PRCM_CLK_MGT_CLK38DIV))
+                       rate /= 2;
+               return rate;
+       }
+
+       val |= clk_mgt[clock].pllsw;
+       pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
+
+       if (pllsw == PRCM_CLK_MGT_CLKPLLSW_SOC0)
+               rate = pll_rate(PRCM_PLLSOC0_FREQ, rate, clk_mgt[clock].branch);
+       else if (pllsw == PRCM_CLK_MGT_CLKPLLSW_SOC1)
+               rate = pll_rate(PRCM_PLLSOC1_FREQ, rate, clk_mgt[clock].branch);
+       else if (pllsw == PRCM_CLK_MGT_CLKPLLSW_DDR)
+               rate = pll_rate(PRCM_PLLDDR_FREQ, rate, clk_mgt[clock].branch);
+       else
+               return 0;
+
+       if ((clock == PRCMU_SGACLK) &&
+               (val & PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN)) {
+               u64 r = (rate * 10);
+
+               (void)do_div(r, 25);
+               return (unsigned long)r;
+       }
+       val &= PRCM_CLK_MGT_CLKPLLDIV_MASK;
+       if (val)
+               return rate / val;
+       else
+               return 0;
+}
+
+static unsigned long dsiclk_rate(u8 n)
+{
+       u32 divsel;
+       u32 div = 1;
+
+       divsel = readl(PRCM_DSI_PLLOUT_SEL);
+       divsel = ((divsel & dsiclk[n].divsel_mask) >> dsiclk[n].divsel_shift);
+
+       if (divsel == PRCM_DSI_PLLOUT_SEL_OFF)
+               divsel = dsiclk[n].divsel;
+
+       switch (divsel) {
+       case PRCM_DSI_PLLOUT_SEL_PHI_4:
+               div *= 2;
+       case PRCM_DSI_PLLOUT_SEL_PHI_2:
+               div *= 2;
+       case PRCM_DSI_PLLOUT_SEL_PHI:
+               return pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
+                       PLL_RAW) / div;
        default:
-               break;
+               return 0;
+       }
+}
+
+static unsigned long dsiescclk_rate(u8 n)
+{
+       u32 div;
+
+       div = readl(PRCM_DSITVCLK_DIV);
+       div = ((div & dsiescclk[n].div_mask) >> (dsiescclk[n].div_shift));
+       return clock_rate(PRCMU_TVCLK) / max((u32)1, div);
+}
+
+unsigned long prcmu_clock_rate(u8 clock)
+{
+       if (clock < PRCMU_NUM_REG_CLOCKS)
+               return clock_rate(clock);
+       else if (clock == PRCMU_TIMCLK)
+               return ROOT_CLOCK_RATE / 16;
+       else if (clock == PRCMU_SYSCLK)
+               return ROOT_CLOCK_RATE;
+       else if (clock == PRCMU_PLLSOC0)
+               return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+       else if (clock == PRCMU_PLLSOC1)
+               return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+       else if (clock == PRCMU_PLLDDR)
+               return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+       else if (clock == PRCMU_PLLDSI)
+               return pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
+                       PLL_RAW);
+       else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+               return dsiclk_rate(clock - PRCMU_DSI0CLK);
+       else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+               return dsiescclk_rate(clock - PRCMU_DSI0ESCCLK);
+       else
+               return 0;
+}
+
+static unsigned long clock_source_rate(u32 clk_mgt_val, int branch)
+{
+       if (clk_mgt_val & PRCM_CLK_MGT_CLK38)
+               return ROOT_CLOCK_RATE;
+       clk_mgt_val &= PRCM_CLK_MGT_CLKPLLSW_MASK;
+       if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_SOC0)
+               return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, branch);
+       else if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_SOC1)
+               return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, branch);
+       else if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_DDR)
+               return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, branch);
+       else
+               return 0;
+}
+
+static u32 clock_divider(unsigned long src_rate, unsigned long rate)
+{
+       u32 div;
+
+       div = (src_rate / rate);
+       if (div == 0)
+               return 1;
+       if (rate < (src_rate / div))
+               div++;
+       return div;
+}
+
+static long round_clock_rate(u8 clock, unsigned long rate)
+{
+       u32 val;
+       u32 div;
+       unsigned long src_rate;
+       long rounded_rate;
+
+       val = readl(clk_mgt[clock].reg);
+       src_rate = clock_source_rate((val | clk_mgt[clock].pllsw),
+               clk_mgt[clock].branch);
+       div = clock_divider(src_rate, rate);
+       if (val & PRCM_CLK_MGT_CLK38) {
+               if (clk_mgt[clock].clk38div) {
+                       if (div > 2)
+                               div = 2;
+               } else {
+                       div = 1;
+               }
+       } else if ((clock == PRCMU_SGACLK) && (div == 3)) {
+               u64 r = (src_rate * 10);
+
+               (void)do_div(r, 25);
+               if (r <= rate)
+                       return (unsigned long)r;
+       }
+       rounded_rate = (src_rate / min(div, (u32)31));
+
+       return rounded_rate;
+}
+
+#define MIN_PLL_VCO_RATE 600000000ULL
+#define MAX_PLL_VCO_RATE 1680640000ULL
+
+static long round_plldsi_rate(unsigned long rate)
+{
+       long rounded_rate = 0;
+       unsigned long src_rate;
+       unsigned long rem;
+       u32 r;
+
+       src_rate = clock_rate(PRCMU_HDMICLK);
+       rem = rate;
+
+       for (r = 7; (rem > 0) && (r > 0); r--) {
+               u64 d;
+
+               d = (r * rate);
+               (void)do_div(d, src_rate);
+               if (d < 6)
+                       d = 6;
+               else if (d > 255)
+                       d = 255;
+               d *= src_rate;
+               if (((2 * d) < (r * MIN_PLL_VCO_RATE)) ||
+                       ((r * MAX_PLL_VCO_RATE) < (2 * d)))
+                       continue;
+               (void)do_div(d, r);
+               if (rate < d) {
+                       if (rounded_rate == 0)
+                               rounded_rate = (long)d;
+                       break;
+               }
+               if ((rate - d) < rem) {
+                       rem = (rate - d);
+                       rounded_rate = (long)d;
+               }
+       }
+       return rounded_rate;
+}
+
+static long round_dsiclk_rate(unsigned long rate)
+{
+       u32 div;
+       unsigned long src_rate;
+       long rounded_rate;
+
+       src_rate = pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
+               PLL_RAW);
+       div = clock_divider(src_rate, rate);
+       rounded_rate = (src_rate / ((div > 2) ? 4 : div));
+
+       return rounded_rate;
+}
+
+static long round_dsiescclk_rate(unsigned long rate)
+{
+       u32 div;
+       unsigned long src_rate;
+       long rounded_rate;
+
+       src_rate = clock_rate(PRCMU_TVCLK);
+       div = clock_divider(src_rate, rate);
+       rounded_rate = (src_rate / min(div, (u32)255));
+
+       return rounded_rate;
+}
+
+long prcmu_round_clock_rate(u8 clock, unsigned long rate)
+{
+       if (clock < PRCMU_NUM_REG_CLOCKS)
+               return round_clock_rate(clock, rate);
+       else if (clock == PRCMU_PLLDSI)
+               return round_plldsi_rate(rate);
+       else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+               return round_dsiclk_rate(rate);
+       else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+               return round_dsiescclk_rate(rate);
+       else
+               return (long)prcmu_clock_rate(clock);
+}
+
+static void set_clock_rate(u8 clock, unsigned long rate)
+{
+       u32 val;
+       u32 div;
+       unsigned long src_rate;
+       unsigned long flags;
+
+       spin_lock_irqsave(&clk_mgt_lock, flags);
+
+       /* Grab the HW semaphore. */
+       while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+               cpu_relax();
+
+       val = readl(clk_mgt[clock].reg);
+       src_rate = clock_source_rate((val | clk_mgt[clock].pllsw),
+               clk_mgt[clock].branch);
+       div = clock_divider(src_rate, rate);
+       if (val & PRCM_CLK_MGT_CLK38) {
+               if (clk_mgt[clock].clk38div) {
+                       if (div > 1)
+                               val |= PRCM_CLK_MGT_CLK38DIV;
+                       else
+                               val &= ~PRCM_CLK_MGT_CLK38DIV;
+               }
+       } else if (clock == PRCMU_SGACLK) {
+               val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK |
+                       PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN);
+               if (div == 3) {
+                       u64 r = (src_rate * 10);
+
+                       (void)do_div(r, 25);
+                       if (r <= rate) {
+                               val |= PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN;
+                               div = 0;
+                       }
+               }
+               val |= min(div, (u32)31);
+       } else {
+               val &= ~PRCM_CLK_MGT_CLKPLLDIV_MASK;
+               val |= min(div, (u32)31);
+       }
+       writel(val, clk_mgt[clock].reg);
+
+       /* Release the HW semaphore. */
+       writel(0, PRCM_SEM);
+
+       spin_unlock_irqrestore(&clk_mgt_lock, flags);
+}
+
+static int set_plldsi_rate(unsigned long rate)
+{
+       unsigned long src_rate;
+       unsigned long rem;
+       u32 pll_freq = 0;
+       u32 r;
+
+       src_rate = clock_rate(PRCMU_HDMICLK);
+       rem = rate;
+
+       for (r = 7; (rem > 0) && (r > 0); r--) {
+               u64 d;
+               u64 hwrate;
+
+               d = (r * rate);
+               (void)do_div(d, src_rate);
+               if (d < 6)
+                       d = 6;
+               else if (d > 255)
+                       d = 255;
+               hwrate = (d * src_rate);
+               if (((2 * hwrate) < (r * MIN_PLL_VCO_RATE)) ||
+                       ((r * MAX_PLL_VCO_RATE) < (2 * hwrate)))
+                       continue;
+               (void)do_div(hwrate, r);
+               if (rate < hwrate) {
+                       if (pll_freq == 0)
+                               pll_freq = (((u32)d << PRCM_PLL_FREQ_D_SHIFT) |
+                                       (r << PRCM_PLL_FREQ_R_SHIFT));
+                       break;
+               }
+               if ((rate - hwrate) < rem) {
+                       rem = (rate - hwrate);
+                       pll_freq = (((u32)d << PRCM_PLL_FREQ_D_SHIFT) |
+                               (r << PRCM_PLL_FREQ_R_SHIFT));
+               }
        }
+       if (pll_freq == 0)
+               return -EINVAL;
+
+       pll_freq |= (1 << PRCM_PLL_FREQ_N_SHIFT);
+       writel(pll_freq, PRCM_PLLDSI_FREQ);
+
+       return 0;
+}
+
+static void set_dsiclk_rate(u8 n, unsigned long rate)
+{
+       u32 val;
+       u32 div;
+
+       div = clock_divider(pll_rate(PRCM_PLLDSI_FREQ,
+                       clock_rate(PRCMU_HDMICLK), PLL_RAW), rate);
+
+       dsiclk[n].divsel = (div == 1) ? PRCM_DSI_PLLOUT_SEL_PHI :
+                          (div == 2) ? PRCM_DSI_PLLOUT_SEL_PHI_2 :
+                          /* else */   PRCM_DSI_PLLOUT_SEL_PHI_4;
+
+       val = readl(PRCM_DSI_PLLOUT_SEL);
+       val &= ~dsiclk[n].divsel_mask;
+       val |= (dsiclk[n].divsel << dsiclk[n].divsel_shift);
+       writel(val, PRCM_DSI_PLLOUT_SEL);
+}
+
+static void set_dsiescclk_rate(u8 n, unsigned long rate)
+{
+       u32 val;
+       u32 div;
+
+       div = clock_divider(clock_rate(PRCMU_TVCLK), rate);
+       val = readl(PRCM_DSITVCLK_DIV);
+       val &= ~dsiescclk[n].div_mask;
+       val |= (min(div, (u32)255) << dsiescclk[n].div_shift);
+       writel(val, PRCM_DSITVCLK_DIV);
+}
+
+int prcmu_set_clock_rate(u8 clock, unsigned long rate)
+{
        if (clock < PRCMU_NUM_REG_CLOCKS)
-               return request_reg_clock(clock, enable);
-       return -EINVAL;
+               set_clock_rate(clock, rate);
+       else if (clock == PRCMU_PLLDSI)
+               return set_plldsi_rate(rate);
+       else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+               set_dsiclk_rate((clock - PRCMU_DSI0CLK), rate);
+       else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+               set_dsiescclk_rate((clock - PRCMU_DSI0ESCCLK), rate);
+       return 0;
 }
 
 int db8500_prcmu_config_esram0_deep_sleep(u8 state)
@@ -1476,7 +2021,7 @@ int db8500_prcmu_config_esram0_deep_sleep(u8 state)
        return 0;
 }
 
-int prcmu_config_hotdog(u8 threshold)
+int db8500_prcmu_config_hotdog(u8 threshold)
 {
        mutex_lock(&mb4_transfer.lock);
 
@@ -1494,7 +2039,7 @@ int prcmu_config_hotdog(u8 threshold)
        return 0;
 }
 
-int prcmu_config_hotmon(u8 low, u8 high)
+int db8500_prcmu_config_hotmon(u8 low, u8 high)
 {
        mutex_lock(&mb4_transfer.lock);
 
@@ -1533,7 +2078,7 @@ static int config_hot_period(u16 val)
        return 0;
 }
 
-int prcmu_start_temp_sense(u16 cycles32k)
+int db8500_prcmu_start_temp_sense(u16 cycles32k)
 {
        if (cycles32k == 0xFFFF)
                return -EINVAL;
@@ -1541,7 +2086,7 @@ int prcmu_start_temp_sense(u16 cycles32k)
        return config_hot_period(cycles32k);
 }
 
-int prcmu_stop_temp_sense(void)
+int db8500_prcmu_stop_temp_sense(void)
 {
        return config_hot_period(0xFFFF);
 }
@@ -1570,7 +2115,7 @@ static int prcmu_a9wdog(u8 cmd, u8 d0, u8 d1, u8 d2, u8 d3)
 
 }
 
-int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
+int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
 {
        BUG_ON(num == 0 || num > 0xf);
        return prcmu_a9wdog(MB4H_A9WDOG_CONF, num, 0, 0,
@@ -1578,17 +2123,17 @@ int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
                            A9WDOG_AUTO_OFF_DIS);
 }
 
-int prcmu_enable_a9wdog(u8 id)
+int db8500_prcmu_enable_a9wdog(u8 id)
 {
        return prcmu_a9wdog(MB4H_A9WDOG_EN, id, 0, 0, 0);
 }
 
-int prcmu_disable_a9wdog(u8 id)
+int db8500_prcmu_disable_a9wdog(u8 id)
 {
        return prcmu_a9wdog(MB4H_A9WDOG_DIS, id, 0, 0, 0);
 }
 
-int prcmu_kick_a9wdog(u8 id)
+int db8500_prcmu_kick_a9wdog(u8 id)
 {
        return prcmu_a9wdog(MB4H_A9WDOG_KICK, id, 0, 0, 0);
 }
@@ -1596,16 +2141,8 @@ int prcmu_kick_a9wdog(u8 id)
 /*
  * timeout is 28 bit, in ms.
  */
-#define MAX_WATCHDOG_TIMEOUT 131000
-int prcmu_load_a9wdog(u8 id, u32 timeout)
+int db8500_prcmu_load_a9wdog(u8 id, u32 timeout)
 {
-       if (timeout > MAX_WATCHDOG_TIMEOUT)
-               /*
-                * Due to calculation bug in prcmu fw, timeouts
-                * can't be bigger than 131 seconds.
-                */
-               return -EINVAL;
-
        return prcmu_a9wdog(MB4H_A9WDOG_LOAD,
                            (id & A9WDOG_ID_MASK) |
                            /*
@@ -1618,41 +2155,6 @@ int prcmu_load_a9wdog(u8 id, u32 timeout)
                            (u8)((timeout >> 20) & 0xff));
 }
 
-/**
- * prcmu_set_clock_divider() - Configure the clock divider.
- * @clock:     The clock for which the request is made.
- * @divider:   The clock divider. (< 32)
- *
- * This function should only be used by the clock implementation.
- * Do not use it from any other place!
- */
-int prcmu_set_clock_divider(u8 clock, u8 divider)
-{
-       u32 val;
-       unsigned long flags;
-
-       if ((clock >= PRCMU_NUM_REG_CLOCKS) || (divider < 1) || (31 < divider))
-               return -EINVAL;
-
-       spin_lock_irqsave(&clk_mgt_lock, flags);
-
-       /* Grab the HW semaphore. */
-       while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
-               cpu_relax();
-
-       val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
-       val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK);
-       val |= (u32)divider;
-       writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
-
-       /* Release the HW semaphore. */
-       writel(0, PRCM_SEM);
-
-       spin_unlock_irqrestore(&clk_mgt_lock, flags);
-
-       return 0;
-}
-
 /**
  * prcmu_abb_read() - Read register value(s) from the ABB.
  * @slave:     The I2C slave address.
@@ -1675,6 +2177,7 @@ int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
        while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
                cpu_relax();
 
+       writeb(0, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB5));
        writeb(PRCMU_I2C_READ(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
        writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
        writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
@@ -1700,16 +2203,19 @@ int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
 }
 
 /**
- * prcmu_abb_write() - Write register value(s) to the ABB.
+ * prcmu_abb_write_masked() - Write masked register value(s) to the ABB.
  * @slave:     The I2C slave address.
  * @reg:       The (start) register address.
  * @value:     The value(s) to write.
+ * @mask:      The mask(s) to use.
  * @size:      The number of registers to write.
  *
- * Reads register value(s) from the ABB.
+ * Writes masked register value(s) to the ABB.
+ * For each @value, only the bits set to 1 in the corresponding @mask
+ * will be written. The other bits are not changed.
  * @size has to be 1 for the current firmware version.
  */
-int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask, u8 size)
 {
        int r;
 
@@ -1721,6 +2227,7 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
        while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
                cpu_relax();
 
+       writeb(~*mask, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB5));
        writeb(PRCMU_I2C_WRITE(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
        writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
        writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
@@ -1742,6 +2249,23 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
        return r;
 }
 
+/**
+ * prcmu_abb_write() - Write register value(s) to the ABB.
+ * @slave:     The I2C slave address.
+ * @reg:       The (start) register address.
+ * @value:     The value(s) to write.
+ * @size:      The number of registers to write.
+ *
+ * Writes register value(s) to the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       u8 mask = ~0;
+
+       return prcmu_abb_write_masked(slave, reg, value, &mask, size);
+}
+
 /**
  * prcmu_ac_wake_req - should be called whenever ARM wants to wakeup Modem
  */
@@ -1850,9 +2374,9 @@ u16 db8500_prcmu_get_reset_code(void)
 }
 
 /**
- * prcmu_reset_modem - ask the PRCMU to reset modem
+ * db8500_prcmu_reset_modem - ask the PRCMU to reset modem
  */
-void prcmu_modem_reset(void)
+void db8500_prcmu_modem_reset(void)
 {
        mutex_lock(&mb1_transfer.lock);
 
@@ -2099,6 +2623,26 @@ static struct irq_chip prcmu_irq_chip = {
        .irq_unmask     = prcmu_irq_unmask,
 };
 
+static char *fw_project_name(u8 project)
+{
+       switch (project) {
+       case PRCMU_FW_PROJECT_U8500:
+               return "U8500";
+       case PRCMU_FW_PROJECT_U8500_C2:
+               return "U8500 C2";
+       case PRCMU_FW_PROJECT_U9500:
+               return "U9500";
+       case PRCMU_FW_PROJECT_U9500_C2:
+               return "U9500 C2";
+       case PRCMU_FW_PROJECT_U8520:
+               return "U8520";
+       case PRCMU_FW_PROJECT_U8420:
+               return "U8420";
+       default:
+               return "Unknown";
+       }
+}
+
 void __init db8500_prcmu_early_init(void)
 {
        unsigned int i;
@@ -2108,11 +2652,13 @@ void __init db8500_prcmu_early_init(void)
                if (tcpm_base != NULL) {
                        u32 version;
                        version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET);
-                       prcmu_version.project_number = version & 0xFF;
-                       prcmu_version.api_version = (version >> 8) & 0xFF;
-                       prcmu_version.func_version = (version >> 16) & 0xFF;
-                       prcmu_version.errata = (version >> 24) & 0xFF;
-                       pr_info("PRCMU firmware version %d.%d.%d\n",
+                       fw_info.version.project = version & 0xFF;
+                       fw_info.version.api_version = (version >> 8) & 0xFF;
+                       fw_info.version.func_version = (version >> 16) & 0xFF;
+                       fw_info.version.errata = (version >> 24) & 0xFF;
+                       fw_info.valid = true;
+                       pr_info("PRCMU firmware: %s, version %d.%d.%d\n",
+                               fw_project_name(fw_info.version.project),
                                (version >> 8) & 0xFF, (version >> 16) & 0xFF,
                                (version >> 24) & 0xFF);
                        iounmap(tcpm_base);
@@ -2130,6 +2676,7 @@ void __init db8500_prcmu_early_init(void)
        init_completion(&mb0_transfer.ac_wake_work);
        mutex_init(&mb1_transfer.lock);
        init_completion(&mb1_transfer.work);
+       mb1_transfer.ape_opp = APE_NO_CHANGE;
        mutex_init(&mb2_transfer.lock);
        init_completion(&mb2_transfer.work);
        spin_lock_init(&mb2_transfer.auto_pm_lock);
@@ -2154,7 +2701,7 @@ void __init db8500_prcmu_early_init(void)
        }
 }
 
-static void __init db8500_prcmu_init_clkforce(void)
+static void __init init_prcm_registers(void)
 {
        u32 val;
 
@@ -2186,19 +2733,17 @@ static struct regulator_consumer_supply db8500_vape_consumers[] = {
        REGULATOR_SUPPLY("vcore", "uart1"),
        REGULATOR_SUPPLY("vcore", "uart2"),
        REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"),
+       REGULATOR_SUPPLY("v-hsi", "ste_hsi.0"),
 };
 
 static struct regulator_consumer_supply db8500_vsmps2_consumers[] = {
-       /* CG2900 and CW1200 power to off-chip peripherals */
-       REGULATOR_SUPPLY("gbf_1v8", "cg2900-uart.0"),
-       REGULATOR_SUPPLY("wlan_1v8", "cw1200.0"),
        REGULATOR_SUPPLY("musb_1v8", "ab8500-usb.0"),
        /* AV8100 regulator */
        REGULATOR_SUPPLY("hdmi_1v8", "0-0070"),
 };
 
 static struct regulator_consumer_supply db8500_b2r2_mcde_consumers[] = {
-       REGULATOR_SUPPLY("vsupply", "b2r2.0"),
+       REGULATOR_SUPPLY("vsupply", "b2r2_bus"),
        REGULATOR_SUPPLY("vsupply", "mcde"),
 };
 
@@ -2235,6 +2780,7 @@ static struct regulator_consumer_supply db8500_esram12_consumers[] = {
 static struct regulator_consumer_supply db8500_esram34_consumers[] = {
        REGULATOR_SUPPLY("v-esram34", "mcde"),
        REGULATOR_SUPPLY("esram34", "cm_control"),
+       REGULATOR_SUPPLY("lcla_esram", "dma40.0"),
 };
 
 static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
@@ -2291,7 +2837,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
                },
        },
        [DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
-               .supply_regulator = "db8500-vape",
+               /* dependency to u8500-vape is handled outside regulator framework */
                .constraints = {
                        .name = "db8500-sva-mmdsp",
                        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2307,7 +2853,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
                },
        },
        [DB8500_REGULATOR_SWITCH_SVAPIPE] = {
-               .supply_regulator = "db8500-vape",
+               /* dependency to u8500-vape is handled outside regulator framework */
                .constraints = {
                        .name = "db8500-sva-pipe",
                        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2316,7 +2862,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
                .num_consumer_supplies = ARRAY_SIZE(db8500_svapipe_consumers),
        },
        [DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
-               .supply_regulator = "db8500-vape",
+               /* dependency to u8500-vape is handled outside regulator framework */
                .constraints = {
                        .name = "db8500-sia-mmdsp",
                        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2331,7 +2877,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
                },
        },
        [DB8500_REGULATOR_SWITCH_SIAPIPE] = {
-               .supply_regulator = "db8500-vape",
+               /* dependency to u8500-vape is handled outside regulator framework */
                .constraints = {
                        .name = "db8500-sia-pipe",
                        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2359,7 +2905,10 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
                .num_consumer_supplies = ARRAY_SIZE(db8500_b2r2_mcde_consumers),
        },
        [DB8500_REGULATOR_SWITCH_ESRAM12] = {
-               .supply_regulator = "db8500-vape",
+               /*
+                * esram12 is set in retention and supplied by Vsafe when Vape is off,
+                * no need to hold Vape
+                */
                .constraints = {
                        .name = "db8500-esram12",
                        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2374,7 +2923,10 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
                },
        },
        [DB8500_REGULATOR_SWITCH_ESRAM34] = {
-               .supply_regulator = "db8500-vape",
+               /*
+                * esram34 is set in retention and supplied by Vsafe when Vape is off,
+                * no need to hold Vape
+                */
                .constraints = {
                        .name = "db8500-esram34",
                        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2412,7 +2964,7 @@ static int __init db8500_prcmu_probe(struct platform_device *pdev)
        if (ux500_is_svp())
                return -ENODEV;
 
-       db8500_prcmu_init_clkforce();
+       init_prcm_registers();
 
        /* Clean up the mailbox interrupts after pre-kernel code. */
        writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
index ec22e9f15d32eefad28f44e3dd7fa1c31b4277f6..3a0bf91d7780894a552f0f83d0cd9defb4637c63 100644 (file)
 
 #define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end))
 
-#define PRCM_SVACLK_MGT_OFF            0x008
-#define PRCM_SIACLK_MGT_OFF            0x00C
-#define PRCM_SGACLK_MGT_OFF            0x014
-#define PRCM_UARTCLK_MGT_OFF           0x018
-#define PRCM_MSP02CLK_MGT_OFF          0x01C
-#define PRCM_I2CCLK_MGT_OFF            0x020
-#define PRCM_SDMMCCLK_MGT_OFF          0x024
-#define PRCM_SLIMCLK_MGT_OFF           0x028
-#define PRCM_PER1CLK_MGT_OFF           0x02C
-#define PRCM_PER2CLK_MGT_OFF           0x030
-#define PRCM_PER3CLK_MGT_OFF           0x034
-#define PRCM_PER5CLK_MGT_OFF           0x038
-#define PRCM_PER6CLK_MGT_OFF           0x03C
-#define PRCM_PER7CLK_MGT_OFF           0x040
-#define PRCM_PWMCLK_MGT_OFF            0x044 /* for DB5500 */
-#define PRCM_IRDACLK_MGT_OFF           0x048 /* for DB5500 */
-#define PRCM_IRRCCLK_MGT_OFF           0x04C /* for DB5500 */
-#define PRCM_LCDCLK_MGT_OFF            0x044
-#define PRCM_BMLCLK_MGT_OFF            0x04C
-#define PRCM_HSITXCLK_MGT_OFF          0x050
-#define PRCM_HSIRXCLK_MGT_OFF          0x054
-#define PRCM_HDMICLK_MGT_OFF           0x058
-#define PRCM_APEATCLK_MGT_OFF          0x05C
-#define PRCM_APETRACECLK_MGT_OFF       0x060
-#define PRCM_MCDECLK_MGT_OFF           0x064
-#define PRCM_IPI2CCLK_MGT_OFF          0x068
-#define PRCM_DSIALTCLK_MGT_OFF         0x06C
-#define PRCM_DMACLK_MGT_OFF            0x074
-#define PRCM_B2R2CLK_MGT_OFF           0x078
-#define PRCM_TVCLK_MGT_OFF             0x07C
-#define PRCM_UNIPROCLK_MGT_OFF         0x278
-#define PRCM_SSPCLK_MGT_OFF            0x280
-#define PRCM_RNGCLK_MGT_OFF            0x284
-#define PRCM_UICCCLK_MGT_OFF           0x27C
-#define PRCM_MSP1CLK_MGT_OFF           0x288
+#define PRCM_CLK_MGT(_offset) (void __iomem *)(IO_ADDRESS(U8500_PRCMU_BASE) \
+       + _offset)
+#define PRCM_ACLK_MGT          PRCM_CLK_MGT(0x004)
+#define PRCM_SVACLK_MGT                PRCM_CLK_MGT(0x008)
+#define PRCM_SIACLK_MGT                PRCM_CLK_MGT(0x00C)
+#define PRCM_SGACLK_MGT                PRCM_CLK_MGT(0x014)
+#define PRCM_UARTCLK_MGT       PRCM_CLK_MGT(0x018)
+#define PRCM_MSP02CLK_MGT      PRCM_CLK_MGT(0x01C)
+#define PRCM_I2CCLK_MGT                PRCM_CLK_MGT(0x020)
+#define PRCM_SDMMCCLK_MGT      PRCM_CLK_MGT(0x024)
+#define PRCM_SLIMCLK_MGT       PRCM_CLK_MGT(0x028)
+#define PRCM_PER1CLK_MGT       PRCM_CLK_MGT(0x02C)
+#define PRCM_PER2CLK_MGT       PRCM_CLK_MGT(0x030)
+#define PRCM_PER3CLK_MGT       PRCM_CLK_MGT(0x034)
+#define PRCM_PER5CLK_MGT       PRCM_CLK_MGT(0x038)
+#define PRCM_PER6CLK_MGT       PRCM_CLK_MGT(0x03C)
+#define PRCM_PER7CLK_MGT       PRCM_CLK_MGT(0x040)
+#define PRCM_LCDCLK_MGT                PRCM_CLK_MGT(0x044)
+#define PRCM_BMLCLK_MGT                PRCM_CLK_MGT(0x04C)
+#define PRCM_HSITXCLK_MGT      PRCM_CLK_MGT(0x050)
+#define PRCM_HSIRXCLK_MGT      PRCM_CLK_MGT(0x054)
+#define PRCM_HDMICLK_MGT       PRCM_CLK_MGT(0x058)
+#define PRCM_APEATCLK_MGT      PRCM_CLK_MGT(0x05C)
+#define PRCM_APETRACECLK_MGT   PRCM_CLK_MGT(0x060)
+#define PRCM_MCDECLK_MGT       PRCM_CLK_MGT(0x064)
+#define PRCM_IPI2CCLK_MGT      PRCM_CLK_MGT(0x068)
+#define PRCM_DSIALTCLK_MGT     PRCM_CLK_MGT(0x06C)
+#define PRCM_DMACLK_MGT                PRCM_CLK_MGT(0x074)
+#define PRCM_B2R2CLK_MGT       PRCM_CLK_MGT(0x078)
+#define PRCM_TVCLK_MGT         PRCM_CLK_MGT(0x07C)
+#define PRCM_UNIPROCLK_MGT     PRCM_CLK_MGT(0x278)
+#define PRCM_SSPCLK_MGT                PRCM_CLK_MGT(0x280)
+#define PRCM_RNGCLK_MGT                PRCM_CLK_MGT(0x284)
+#define PRCM_UICCCLK_MGT       PRCM_CLK_MGT(0x27C)
+#define PRCM_MSP1CLK_MGT       PRCM_CLK_MGT(0x288)
 
 #define PRCM_ARM_PLLDIVPS      (_PRCMU_BASE + 0x118)
 #define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE         0x3f
@@ -79,6 +79,8 @@
 
 /* ARM WFI Standby signal register */
 #define PRCM_ARM_WFI_STANDBY    (_PRCMU_BASE + 0x130)
+#define PRCM_ARM_WFI_STANDBY_WFI0               0x08
+#define PRCM_ARM_WFI_STANDBY_WFI1               0x10
 #define PRCM_IOCR              (_PRCMU_BASE + 0x310)
 #define PRCM_IOCR_IOFORCE                      0x1
 
 #define PRCM_MMIP_LS_CLAMP_SET     (_PRCMU_BASE + 0x420)
 #define PRCM_MMIP_LS_CLAMP_CLR     (_PRCMU_BASE + 0x424)
 
+#define PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP                BIT(11)
+#define PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI       BIT(22)
+
 /* PRCMU clock/PLL/reset registers */
+#define PRCM_PLLSOC0_FREQ         (_PRCMU_BASE + 0x080)
+#define PRCM_PLLSOC1_FREQ         (_PRCMU_BASE + 0x084)
+#define PRCM_PLLDDR_FREQ          (_PRCMU_BASE + 0x08C)
+#define PRCM_PLL_FREQ_D_SHIFT  0
+#define PRCM_PLL_FREQ_D_MASK   BITS(0, 7)
+#define PRCM_PLL_FREQ_N_SHIFT  8
+#define PRCM_PLL_FREQ_N_MASK   BITS(8, 13)
+#define PRCM_PLL_FREQ_R_SHIFT  16
+#define PRCM_PLL_FREQ_R_MASK   BITS(16, 18)
+#define PRCM_PLL_FREQ_SELDIV2  BIT(24)
+#define PRCM_PLL_FREQ_DIV2EN   BIT(25)
+
 #define PRCM_PLLDSI_FREQ           (_PRCMU_BASE + 0x500)
 #define PRCM_PLLDSI_ENABLE         (_PRCMU_BASE + 0x504)
 #define PRCM_PLLDSI_LOCKP          (_PRCMU_BASE + 0x508)
-#define PRCM_LCDCLK_MGT            (_PRCMU_BASE + PRCM_LCDCLK_MGT_OFF)
-#define PRCM_MCDECLK_MGT           (_PRCMU_BASE + PRCM_MCDECLK_MGT_OFF)
-#define PRCM_HDMICLK_MGT           (_PRCMU_BASE + PRCM_HDMICLK_MGT_OFF)
-#define PRCM_TVCLK_MGT             (_PRCMU_BASE + PRCM_TVCLK_MGT_OFF)
 #define PRCM_DSI_PLLOUT_SEL        (_PRCMU_BASE + 0x530)
 #define PRCM_DSITVCLK_DIV          (_PRCMU_BASE + 0x52C)
 #define PRCM_PLLDSI_LOCKP          (_PRCMU_BASE + 0x508)
 #define PRCM_APE_RESETN_SET        (_PRCMU_BASE + 0x1E4)
 #define PRCM_APE_RESETN_CLR        (_PRCMU_BASE + 0x1E8)
 
+#define PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE BIT(0)
+
+#define PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10  BIT(0)
+#define PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3   BIT(1)
+
+#define PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_SHIFT   0
+#define PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_MASK    BITS(0, 2)
+#define PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_SHIFT   8
+#define PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_MASK    BITS(8, 10)
+
+#define PRCM_DSI_PLLOUT_SEL_OFF                0
+#define PRCM_DSI_PLLOUT_SEL_PHI                1
+#define PRCM_DSI_PLLOUT_SEL_PHI_2      2
+#define PRCM_DSI_PLLOUT_SEL_PHI_4      3
+
+#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_SHIFT       0
+#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_MASK                BITS(0, 7)
+#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_SHIFT       8
+#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_MASK                BITS(8, 15)
+#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_SHIFT       16
+#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_MASK                BITS(16, 23)
+#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_EN              BIT(24)
+#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_EN              BIT(25)
+#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_EN              BIT(26)
+
+#define PRCM_APE_RESETN_DSIPLL_RESETN BIT(14)
+
 #define PRCM_CLKOCR               (_PRCMU_BASE + 0x1CC)
 #define PRCM_CLKOCR_CLKOUT0_REF_CLK    (1 << 0)
 #define PRCM_CLKOCR_CLKOUT0_MASK       BITS(0, 13)
 #define PRCM_CLKOCR_CLKOSEL1_MASK      BITS(22, 24)
 #define PRCM_CLKOCR_CLK1TYPE           BIT(28)
 
-#define PRCM_CLK_MGT_CLKPLLDIV_MASK    BITS(0, 4)
-#define PRCM_CLK_MGT_CLKPLLSW_MASK     BITS(5, 7)
-#define PRCM_CLK_MGT_CLKEN             BIT(8)
+#define PRCM_CLK_MGT_CLKPLLDIV_MASK            BITS(0, 4)
+#define PRCM_CLK_MGT_CLKPLLSW_SOC0             BIT(5)
+#define PRCM_CLK_MGT_CLKPLLSW_SOC1             BIT(6)
+#define PRCM_CLK_MGT_CLKPLLSW_DDR              BIT(7)
+#define PRCM_CLK_MGT_CLKPLLSW_MASK             BITS(5, 7)
+#define PRCM_CLK_MGT_CLKEN                     BIT(8)
+#define PRCM_CLK_MGT_CLK38                     BIT(9)
+#define PRCM_CLK_MGT_CLK38DIV                  BIT(11)
+#define PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN    BIT(12)
 
 /* GPIOCR register */
 #define PRCM_GPIOCR_SPI2_SELECT BIT(23)
index 7122386b4e3cf1830dbb3cab2f552efefeb43834..9fd4f63c45cc18b2e60dc41085425ff3d35f04b8 100644 (file)
@@ -560,6 +560,8 @@ EXPORT_SYMBOL(mc13xxx_get_flags);
 
 #define MC13XXX_ADC1_CHAN0_SHIFT       5
 #define MC13XXX_ADC1_CHAN1_SHIFT       8
+#define MC13783_ADC1_ATO_SHIFT         11
+#define MC13783_ADC1_ATOX              (1 << 19)
 
 struct mc13xxx_adcdone_data {
        struct mc13xxx *mc13xxx;
@@ -580,7 +582,8 @@ static irqreturn_t mc13xxx_handler_adcdone(int irq, void *data)
 #define MC13XXX_ADC_WORKING (1 << 0)
 
 int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
-               unsigned int channel, unsigned int *sample)
+               unsigned int channel, u8 ato, bool atox,
+               unsigned int *sample)
 {
        u32 adc0, adc1, old_adc0;
        int i, ret;
@@ -631,6 +634,9 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
                return -EINVAL;
        }
 
+       adc1 |= ato << MC13783_ADC1_ATO_SHIFT;
+       if (atox)
+               adc1 |= MC13783_ADC1_ATOX;
        dev_dbg(&mc13xxx->spidev->dev, "%s: request irq\n", __func__);
        mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE,
                        mc13xxx_handler_adcdone, __func__, &adcdone_data);
@@ -813,7 +819,8 @@ err_revision:
                mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
 
        if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
-               mc13xxx_add_subdevice(mc13xxx, "%s-ts");
+               mc13xxx_add_subdevice_pdata(mc13xxx, "%s-ts",
+                               &pdata->touch, sizeof(pdata->touch));
 
        if (pdata) {
                mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
index 411f523d4878bd1cec6f8783ca6c99d6b57b669e..ffc3d48676ae67c5c838700d212310025ec8f2da 100644 (file)
@@ -162,7 +162,7 @@ int mfd_add_devices(struct device *parent, int id,
        atomic_t *cnts;
 
        /* initialize reference counting for all cells */
-       cnts = kcalloc(sizeof(*cnts), n_devs, GFP_KERNEL);
+       cnts = kcalloc(n_devs, sizeof(*cnts), GFP_KERNEL);
        if (!cnts)
                return -ENOMEM;
 
index 68ac2c55d5ae0bb1381c0681b641846079345f54..95a2e546a48962c18cfaa151aa7dc539e4c94035 100644 (file)
@@ -170,7 +170,7 @@ struct usbhs_hcd_omap {
 /*-------------------------------------------------------------------------*/
 
 const char usbhs_driver_name[] = USBHS_DRIVER_NAME;
-static u64 usbhs_dmamask = ~(u32)0;
+static u64 usbhs_dmamask = DMA_BIT_MASK(32);
 
 /*-------------------------------------------------------------------------*/
 
@@ -223,7 +223,7 @@ static struct platform_device *omap_usbhs_alloc_child(const char *name,
        }
 
        child->dev.dma_mask             = &usbhs_dmamask;
-       child->dev.coherent_dma_mask    = 0xffffffff;
+       dma_set_coherent_mask(&child->dev, DMA_BIT_MASK(32));
        child->dev.parent               = dev;
 
        ret = platform_device_add(child);
@@ -799,14 +799,13 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, omap);
 
+       omap_usbhs_init(dev);
        ret = omap_usbhs_alloc_children(pdev);
        if (ret) {
                dev_err(dev, "omap_usbhs_alloc_children failed\n");
                goto err_alloc;
        }
 
-       omap_usbhs_init(dev);
-
        goto end_probe;
 
 err_alloc:
index ff1a7e741ecdfc6d8eb3d27cacaa47a1b492768a..189c2f07b83f4331af92528886864e0f5c5fa1d7 100644 (file)
@@ -46,13 +46,7 @@ EXPORT_SYMBOL_GPL(pcf50633_read_block);
 int pcf50633_write_block(struct pcf50633 *pcf , u8 reg,
                                        int nr_regs, u8 *data)
 {
-       int ret;
-
-       ret = regmap_raw_write(pcf->regmap, reg, data, nr_regs);
-       if (ret != 0)
-               return ret;
-
-       return nr_regs;
+       return regmap_raw_write(pcf->regmap, reg, data, nr_regs);
 }
 EXPORT_SYMBOL_GPL(pcf50633_write_block);
 
index 9ab19a8f669dfa5a5b2fef8942aff5e90df3d073..d02ddf2ebd630ab7b2e77267c0290bc6742d4f58 100644 (file)
 
 #include <linux/mfd/pcf50633/core.h>
 #include <linux/mfd/pcf50633/gpio.h>
-
-enum pcf50633_regulator_id {
-       PCF50633_REGULATOR_AUTO,
-       PCF50633_REGULATOR_DOWN1,
-       PCF50633_REGULATOR_DOWN2,
-       PCF50633_REGULATOR_LDO1,
-       PCF50633_REGULATOR_LDO2,
-       PCF50633_REGULATOR_LDO3,
-       PCF50633_REGULATOR_LDO4,
-       PCF50633_REGULATOR_LDO5,
-       PCF50633_REGULATOR_LDO6,
-       PCF50633_REGULATOR_HCLDO,
-       PCF50633_REGULATOR_MEMLDO,
-};
-
-#define PCF50633_REG_AUTOOUT   0x1a
-#define PCF50633_REG_DOWN1OUT  0x1e
-#define PCF50633_REG_DOWN2OUT  0x22
-#define PCF50633_REG_MEMLDOOUT 0x26
-#define PCF50633_REG_LDO1OUT   0x2d
-#define PCF50633_REG_LDO2OUT   0x2f
-#define PCF50633_REG_LDO3OUT   0x31
-#define PCF50633_REG_LDO4OUT   0x33
-#define PCF50633_REG_LDO5OUT   0x35
-#define PCF50633_REG_LDO6OUT   0x37
-#define PCF50633_REG_HCLDOOUT  0x39
+#include <linux/mfd/pcf50633/pmic.h>
 
 static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = {
        [PCF50633_REGULATOR_AUTO]       = PCF50633_REG_AUTOOUT,
index 048a3b903b013bcb5a0efb62c303e76c02ab1056..498286cbb5300d31f160b693e0f1d85ec254041f 100644 (file)
 #include <linux/slab.h>
 
 #include <linux/mfd/pcf50633/core.h>
-
-/* Two MBCS registers used during cold start */
-#define PCF50633_REG_MBCS1             0x4b
-#define PCF50633_REG_MBCS2             0x4c
-#define PCF50633_MBCS1_USBPRES                 0x01
-#define PCF50633_MBCS1_ADAPTPRES       0x01
+#include <linux/mfd/pcf50633/mbc.h>
 
 int pcf50633_register_irq(struct pcf50633 *pcf, int irq,
                        void (*handler) (int, void *), void *data)
diff --git a/drivers/mfd/rc5t583-irq.c b/drivers/mfd/rc5t583-irq.c
new file mode 100644 (file)
index 0000000..fa6f80f
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * Interrupt driver for RICOH583 power management chip.
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * based on code
+ *      Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mfd/rc5t583.h>
+
+enum int_type {
+       SYS_INT  = 0x1,
+       DCDC_INT = 0x2,
+       RTC_INT  = 0x4,
+       ADC_INT  = 0x8,
+       GPIO_INT = 0x10,
+};
+
+static int gpedge_add[] = {
+       RC5T583_GPIO_GPEDGE2,
+       RC5T583_GPIO_GPEDGE2
+};
+
+static int irq_en_add[] = {
+       RC5T583_INT_EN_SYS1,
+       RC5T583_INT_EN_SYS2,
+       RC5T583_INT_EN_DCDC,
+       RC5T583_INT_EN_RTC,
+       RC5T583_INT_EN_ADC1,
+       RC5T583_INT_EN_ADC2,
+       RC5T583_INT_EN_ADC3,
+       RC5T583_GPIO_EN_INT
+};
+
+static int irq_mon_add[] = {
+       RC5T583_INT_MON_SYS1,
+       RC5T583_INT_MON_SYS2,
+       RC5T583_INT_MON_DCDC,
+       RC5T583_INT_MON_RTC,
+       RC5T583_INT_IR_ADCL,
+       RC5T583_INT_IR_ADCH,
+       RC5T583_INT_IR_ADCEND,
+       RC5T583_INT_IR_GPIOF,
+       RC5T583_INT_IR_GPIOR
+};
+
+static int irq_clr_add[] = {
+       RC5T583_INT_IR_SYS1,
+       RC5T583_INT_IR_SYS2,
+       RC5T583_INT_IR_DCDC,
+       RC5T583_INT_IR_RTC,
+       RC5T583_INT_IR_ADCL,
+       RC5T583_INT_IR_ADCH,
+       RC5T583_INT_IR_ADCEND,
+       RC5T583_INT_IR_GPIOF,
+       RC5T583_INT_IR_GPIOR
+};
+
+static int main_int_type[] = {
+       SYS_INT,
+       SYS_INT,
+       DCDC_INT,
+       RTC_INT,
+       ADC_INT,
+       ADC_INT,
+       ADC_INT,
+       GPIO_INT,
+       GPIO_INT,
+};
+
+struct rc5t583_irq_data {
+       u8      int_type;
+       u8      master_bit;
+       u8      int_en_bit;
+       u8      mask_reg_index;
+       int     grp_index;
+};
+
+#define RC5T583_IRQ(_int_type, _master_bit, _grp_index, \
+                       _int_bit, _mask_ind)            \
+       {                                               \
+               .int_type       = _int_type,            \
+               .master_bit     = _master_bit,          \
+               .grp_index      = _grp_index,           \
+               .int_en_bit     = _int_bit,             \
+               .mask_reg_index = _mask_ind,            \
+       }
+
+static const struct rc5t583_irq_data rc5t583_irqs[RC5T583_MAX_IRQS] = {
+       [RC5T583_IRQ_ONKEY]             = RC5T583_IRQ(SYS_INT,  0, 0, 0, 0),
+       [RC5T583_IRQ_ACOK]              = RC5T583_IRQ(SYS_INT,  0, 1, 1, 0),
+       [RC5T583_IRQ_LIDOPEN]           = RC5T583_IRQ(SYS_INT,  0, 2, 2, 0),
+       [RC5T583_IRQ_PREOT]             = RC5T583_IRQ(SYS_INT,  0, 3, 3, 0),
+       [RC5T583_IRQ_CLKSTP]            = RC5T583_IRQ(SYS_INT,  0, 4, 4, 0),
+       [RC5T583_IRQ_ONKEY_OFF]         = RC5T583_IRQ(SYS_INT,  0, 5, 5, 0),
+       [RC5T583_IRQ_WD]                = RC5T583_IRQ(SYS_INT,  0, 7, 7, 0),
+       [RC5T583_IRQ_EN_PWRREQ1]        = RC5T583_IRQ(SYS_INT,  0, 8, 0, 1),
+       [RC5T583_IRQ_EN_PWRREQ2]        = RC5T583_IRQ(SYS_INT,  0, 9, 1, 1),
+       [RC5T583_IRQ_PRE_VINDET]        = RC5T583_IRQ(SYS_INT,  0, 10, 2, 1),
+
+       [RC5T583_IRQ_DC0LIM]            = RC5T583_IRQ(DCDC_INT, 1, 0, 0, 2),
+       [RC5T583_IRQ_DC1LIM]            = RC5T583_IRQ(DCDC_INT, 1, 1, 1, 2),
+       [RC5T583_IRQ_DC2LIM]            = RC5T583_IRQ(DCDC_INT, 1, 2, 2, 2),
+       [RC5T583_IRQ_DC3LIM]            = RC5T583_IRQ(DCDC_INT, 1, 3, 3, 2),
+
+       [RC5T583_IRQ_CTC]               = RC5T583_IRQ(RTC_INT,  2, 0, 0, 3),
+       [RC5T583_IRQ_YALE]              = RC5T583_IRQ(RTC_INT,  2, 5, 5, 3),
+       [RC5T583_IRQ_DALE]              = RC5T583_IRQ(RTC_INT,  2, 6, 6, 3),
+       [RC5T583_IRQ_WALE]              = RC5T583_IRQ(RTC_INT,  2, 7, 7, 3),
+
+       [RC5T583_IRQ_AIN1L]             = RC5T583_IRQ(ADC_INT,  3, 0, 0, 4),
+       [RC5T583_IRQ_AIN2L]             = RC5T583_IRQ(ADC_INT,  3, 1, 1, 4),
+       [RC5T583_IRQ_AIN3L]             = RC5T583_IRQ(ADC_INT,  3, 2, 2, 4),
+       [RC5T583_IRQ_VBATL]             = RC5T583_IRQ(ADC_INT,  3, 3, 3, 4),
+       [RC5T583_IRQ_VIN3L]             = RC5T583_IRQ(ADC_INT,  3, 4, 4, 4),
+       [RC5T583_IRQ_VIN8L]             = RC5T583_IRQ(ADC_INT,  3, 5, 5, 4),
+       [RC5T583_IRQ_AIN1H]             = RC5T583_IRQ(ADC_INT,  3, 6, 0, 5),
+       [RC5T583_IRQ_AIN2H]             = RC5T583_IRQ(ADC_INT,  3, 7, 1, 5),
+       [RC5T583_IRQ_AIN3H]             = RC5T583_IRQ(ADC_INT,  3, 8, 2, 5),
+       [RC5T583_IRQ_VBATH]             = RC5T583_IRQ(ADC_INT,  3, 9, 3, 5),
+       [RC5T583_IRQ_VIN3H]             = RC5T583_IRQ(ADC_INT,  3, 10, 4, 5),
+       [RC5T583_IRQ_VIN8H]             = RC5T583_IRQ(ADC_INT,  3, 11, 5, 5),
+       [RC5T583_IRQ_ADCEND]            = RC5T583_IRQ(ADC_INT,  3, 12, 0, 6),
+
+       [RC5T583_IRQ_GPIO0]             = RC5T583_IRQ(GPIO_INT, 4, 0, 0, 7),
+       [RC5T583_IRQ_GPIO1]             = RC5T583_IRQ(GPIO_INT, 4, 1, 1, 7),
+       [RC5T583_IRQ_GPIO2]             = RC5T583_IRQ(GPIO_INT, 4, 2, 2, 7),
+       [RC5T583_IRQ_GPIO3]             = RC5T583_IRQ(GPIO_INT, 4, 3, 3, 7),
+       [RC5T583_IRQ_GPIO4]             = RC5T583_IRQ(GPIO_INT, 4, 4, 4, 7),
+       [RC5T583_IRQ_GPIO5]             = RC5T583_IRQ(GPIO_INT, 4, 5, 5, 7),
+       [RC5T583_IRQ_GPIO6]             = RC5T583_IRQ(GPIO_INT, 4, 6, 6, 7),
+       [RC5T583_IRQ_GPIO7]             = RC5T583_IRQ(GPIO_INT, 4, 7, 7, 7),
+};
+
+static void rc5t583_irq_lock(struct irq_data *irq_data)
+{
+       struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+       mutex_lock(&rc5t583->irq_lock);
+}
+
+static void rc5t583_irq_unmask(struct irq_data *irq_data)
+{
+       struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+       unsigned int __irq = irq_data->irq - rc5t583->irq_base;
+       const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
+
+       rc5t583->group_irq_en[data->grp_index] |= 1 << data->grp_index;
+       rc5t583->intc_inten_reg |= 1 << data->master_bit;
+       rc5t583->irq_en_reg[data->mask_reg_index] |= 1 << data->int_en_bit;
+}
+
+static void rc5t583_irq_mask(struct irq_data *irq_data)
+{
+       struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+       unsigned int __irq = irq_data->irq - rc5t583->irq_base;
+       const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
+
+       rc5t583->group_irq_en[data->grp_index] &= ~(1 << data->grp_index);
+       if (!rc5t583->group_irq_en[data->grp_index])
+               rc5t583->intc_inten_reg &= ~(1 << data->master_bit);
+
+       rc5t583->irq_en_reg[data->mask_reg_index] &= ~(1 << data->int_en_bit);
+}
+
+static int rc5t583_irq_set_type(struct irq_data *irq_data, unsigned int type)
+{
+       struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+       unsigned int __irq = irq_data->irq - rc5t583->irq_base;
+       const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
+       int val = 0;
+       int gpedge_index;
+       int gpedge_bit_pos;
+
+       /* Supporting only trigger level inetrrupt */
+       if ((data->int_type & GPIO_INT) && (type & IRQ_TYPE_EDGE_BOTH)) {
+               gpedge_index = data->int_en_bit / 4;
+               gpedge_bit_pos = data->int_en_bit % 4;
+
+               if (type & IRQ_TYPE_EDGE_FALLING)
+                       val |= 0x2;
+
+               if (type & IRQ_TYPE_EDGE_RISING)
+                       val |= 0x1;
+
+               rc5t583->gpedge_reg[gpedge_index] &= ~(3 << gpedge_bit_pos);
+               rc5t583->gpedge_reg[gpedge_index] |= (val << gpedge_bit_pos);
+               rc5t583_irq_unmask(irq_data);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static void rc5t583_irq_sync_unlock(struct irq_data *irq_data)
+{
+       struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+       int i;
+       int ret;
+
+       for (i = 0; i < ARRAY_SIZE(rc5t583->gpedge_reg); i++) {
+               ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
+                               rc5t583->gpedge_reg[i]);
+               if (ret < 0)
+                       dev_warn(rc5t583->dev,
+                               "Error in writing reg 0x%02x error: %d\n",
+                               gpedge_add[i], ret);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(rc5t583->irq_en_reg); i++) {
+               ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
+                                       rc5t583->irq_en_reg[i]);
+               if (ret < 0)
+                       dev_warn(rc5t583->dev,
+                               "Error in writing reg 0x%02x error: %d\n",
+                               irq_en_add[i], ret);
+       }
+
+       ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN,
+                               rc5t583->intc_inten_reg);
+       if (ret < 0)
+               dev_warn(rc5t583->dev,
+                       "Error in writing reg 0x%02x error: %d\n",
+                       RC5T583_INTC_INTEN, ret);
+
+       mutex_unlock(&rc5t583->irq_lock);
+}
+#ifdef CONFIG_PM_SLEEP
+static int rc5t583_irq_set_wake(struct irq_data *irq_data, unsigned int on)
+{
+       struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+       return irq_set_irq_wake(rc5t583->chip_irq, on);
+}
+#else
+#define rc5t583_irq_set_wake NULL
+#endif
+
+static irqreturn_t rc5t583_irq(int irq, void *data)
+{
+       struct rc5t583 *rc5t583 = data;
+       uint8_t int_sts[RC5T583_MAX_INTERRUPT_MASK_REGS];
+       uint8_t master_int;
+       int i;
+       int ret;
+       unsigned int rtc_int_sts = 0;
+
+       /* Clear the status */
+       for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)
+               int_sts[i] = 0;
+
+       ret  = rc5t583_read(rc5t583->dev, RC5T583_INTC_INTMON, &master_int);
+       if (ret < 0) {
+               dev_err(rc5t583->dev,
+                       "Error in reading reg 0x%02x error: %d\n",
+                       RC5T583_INTC_INTMON, ret);
+               return IRQ_HANDLED;
+       }
+
+       for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; ++i) {
+               if (!(master_int & main_int_type[i]))
+                       continue;
+
+               ret = rc5t583_read(rc5t583->dev, irq_mon_add[i], &int_sts[i]);
+               if (ret < 0) {
+                       dev_warn(rc5t583->dev,
+                               "Error in reading reg 0x%02x error: %d\n",
+                               irq_mon_add[i], ret);
+                       int_sts[i] = 0;
+                       continue;
+               }
+
+               if (main_int_type[i] & RTC_INT) {
+                       rtc_int_sts = 0;
+                       if (int_sts[i] & 0x1)
+                               rtc_int_sts |= BIT(6);
+                       if (int_sts[i] & 0x2)
+                               rtc_int_sts |= BIT(7);
+                       if (int_sts[i] & 0x4)
+                               rtc_int_sts |= BIT(0);
+                       if (int_sts[i] & 0x8)
+                               rtc_int_sts |= BIT(5);
+               }
+
+               ret = rc5t583_write(rc5t583->dev, irq_clr_add[i],
+                               ~int_sts[i]);
+               if (ret < 0)
+                       dev_warn(rc5t583->dev,
+                               "Error in reading reg 0x%02x error: %d\n",
+                               irq_clr_add[i], ret);
+
+               if (main_int_type[i] & RTC_INT)
+                       int_sts[i] = rtc_int_sts;
+       }
+
+       /* Merge gpio interrupts for rising and falling case*/
+       int_sts[7] |= int_sts[8];
+
+       /* Call interrupt handler if enabled */
+       for (i = 0; i < RC5T583_MAX_IRQS; ++i) {
+               const struct rc5t583_irq_data *data = &rc5t583_irqs[i];
+               if ((int_sts[data->mask_reg_index] & (1 << data->int_en_bit)) &&
+                       (rc5t583->group_irq_en[data->master_bit] &
+                                       (1 << data->grp_index)))
+                       handle_nested_irq(rc5t583->irq_base + i);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static struct irq_chip rc5t583_irq_chip = {
+       .name = "rc5t583-irq",
+       .irq_mask = rc5t583_irq_mask,
+       .irq_unmask = rc5t583_irq_unmask,
+       .irq_bus_lock = rc5t583_irq_lock,
+       .irq_bus_sync_unlock = rc5t583_irq_sync_unlock,
+       .irq_set_type = rc5t583_irq_set_type,
+       .irq_set_wake = rc5t583_irq_set_wake,
+};
+
+int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base)
+{
+       int i, ret;
+
+       if (!irq_base) {
+               dev_warn(rc5t583->dev, "No interrupt support on IRQ base\n");
+               return -EINVAL;
+       }
+
+       mutex_init(&rc5t583->irq_lock);
+
+       /* Initailize all int register to 0 */
+       for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)  {
+               ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
+                               rc5t583->irq_en_reg[i]);
+               if (ret < 0)
+                       dev_warn(rc5t583->dev,
+                               "Error in writing reg 0x%02x error: %d\n",
+                               irq_en_add[i], ret);
+       }
+
+       for (i = 0; i < RC5T583_MAX_GPEDGE_REG; i++)  {
+               ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
+                               rc5t583->gpedge_reg[i]);
+               if (ret < 0)
+                       dev_warn(rc5t583->dev,
+                               "Error in writing reg 0x%02x error: %d\n",
+                               gpedge_add[i], ret);
+       }
+
+       ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN, 0x0);
+       if (ret < 0)
+               dev_warn(rc5t583->dev,
+                       "Error in writing reg 0x%02x error: %d\n",
+                       RC5T583_INTC_INTEN, ret);
+
+       /* Clear all interrupts in case they woke up active. */
+       for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)  {
+               ret = rc5t583_write(rc5t583->dev, irq_clr_add[i], 0);
+               if (ret < 0)
+                       dev_warn(rc5t583->dev,
+                               "Error in writing reg 0x%02x error: %d\n",
+                               irq_clr_add[i], ret);
+       }
+
+       rc5t583->irq_base = irq_base;
+       rc5t583->chip_irq = irq;
+
+       for (i = 0; i < RC5T583_MAX_IRQS; i++) {
+               int __irq = i + rc5t583->irq_base;
+               irq_set_chip_data(__irq, rc5t583);
+               irq_set_chip_and_handler(__irq, &rc5t583_irq_chip,
+                                        handle_simple_irq);
+               irq_set_nested_thread(__irq, 1);
+#ifdef CONFIG_ARM
+               set_irq_flags(__irq, IRQF_VALID);
+#endif
+       }
+
+       ret = request_threaded_irq(irq, NULL, rc5t583_irq, IRQF_ONESHOT,
+                               "rc5t583", rc5t583);
+       if (ret < 0)
+               dev_err(rc5t583->dev,
+                       "Error in registering interrupt error: %d\n", ret);
+       return ret;
+}
+
+int rc5t583_irq_exit(struct rc5t583 *rc5t583)
+{
+       if (rc5t583->chip_irq)
+               free_irq(rc5t583->chip_irq, rc5t583);
+       return 0;
+}
diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c
new file mode 100644 (file)
index 0000000..99ef944
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Core driver access RC5T583 power management chip.
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * Based on code
+ *     Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/rc5t583.h>
+#include <linux/regmap.h>
+
+#define RICOH_ONOFFSEL_REG     0x10
+#define RICOH_SWCTL_REG                0x5E
+
+struct deepsleep_control_data {
+       u8 reg_add;
+       u8 ds_pos_bit;
+};
+
+#define DEEPSLEEP_INIT(_id, _reg, _pos)                \
+       {                                       \
+               .reg_add = RC5T583_##_reg,      \
+               .ds_pos_bit = _pos,             \
+       }
+
+static struct deepsleep_control_data deepsleep_data[] = {
+       DEEPSLEEP_INIT(DC0, SLPSEQ1, 0),
+       DEEPSLEEP_INIT(DC1, SLPSEQ1, 4),
+       DEEPSLEEP_INIT(DC2, SLPSEQ2, 0),
+       DEEPSLEEP_INIT(DC3, SLPSEQ2, 4),
+       DEEPSLEEP_INIT(LDO0, SLPSEQ3, 0),
+       DEEPSLEEP_INIT(LDO1, SLPSEQ3, 4),
+       DEEPSLEEP_INIT(LDO2, SLPSEQ4, 0),
+       DEEPSLEEP_INIT(LDO3, SLPSEQ4, 4),
+       DEEPSLEEP_INIT(LDO4, SLPSEQ5, 0),
+       DEEPSLEEP_INIT(LDO5, SLPSEQ5, 4),
+       DEEPSLEEP_INIT(LDO6, SLPSEQ6, 0),
+       DEEPSLEEP_INIT(LDO7, SLPSEQ6, 4),
+       DEEPSLEEP_INIT(LDO8, SLPSEQ7, 0),
+       DEEPSLEEP_INIT(LDO9, SLPSEQ7, 4),
+       DEEPSLEEP_INIT(PSO0, SLPSEQ8, 0),
+       DEEPSLEEP_INIT(PSO1, SLPSEQ8, 4),
+       DEEPSLEEP_INIT(PSO2, SLPSEQ9, 0),
+       DEEPSLEEP_INIT(PSO3, SLPSEQ9, 4),
+       DEEPSLEEP_INIT(PSO4, SLPSEQ10, 0),
+       DEEPSLEEP_INIT(PSO5, SLPSEQ10, 4),
+       DEEPSLEEP_INIT(PSO6, SLPSEQ11, 0),
+       DEEPSLEEP_INIT(PSO7, SLPSEQ11, 4),
+};
+
+#define EXT_PWR_REQ            \
+       (RC5T583_EXT_PWRREQ1_CONTROL | RC5T583_EXT_PWRREQ2_CONTROL)
+
+static struct mfd_cell rc5t583_subdevs[] = {
+       {.name = "rc5t583-regulator",},
+       {.name = "rc5t583-rtc",      },
+       {.name = "rc5t583-key",      }
+};
+
+int rc5t583_write(struct device *dev, uint8_t reg, uint8_t val)
+{
+       struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+       return regmap_write(rc5t583->regmap, reg, val);
+}
+
+int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val)
+{
+       struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+       unsigned int ival;
+       int ret;
+       ret = regmap_read(rc5t583->regmap, reg, &ival);
+       if (!ret)
+               *val = (uint8_t)ival;
+       return ret;
+}
+
+int rc5t583_set_bits(struct device *dev, unsigned int reg,
+                       unsigned int bit_mask)
+{
+       struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+       return regmap_update_bits(rc5t583->regmap, reg, bit_mask, bit_mask);
+}
+
+int rc5t583_clear_bits(struct device *dev, unsigned int reg,
+                       unsigned int bit_mask)
+{
+       struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+       return regmap_update_bits(rc5t583->regmap, reg, bit_mask, 0);
+}
+
+int rc5t583_update(struct device *dev, unsigned int reg,
+               unsigned int val, unsigned int mask)
+{
+       struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+       return regmap_update_bits(rc5t583->regmap, reg, mask, val);
+}
+
+static int __rc5t583_set_ext_pwrreq1_control(struct device *dev,
+       int id, int ext_pwr, int slots)
+{
+       int ret;
+       uint8_t sleepseq_val;
+       unsigned int en_bit;
+       unsigned int slot_bit;
+
+       if (id == RC5T583_DS_DC0) {
+               dev_err(dev, "PWRREQ1 is invalid control for rail %d\n", id);
+               return -EINVAL;
+       }
+
+       en_bit = deepsleep_data[id].ds_pos_bit;
+       slot_bit = en_bit + 1;
+       ret = rc5t583_read(dev, deepsleep_data[id].reg_add, &sleepseq_val);
+       if (ret < 0) {
+               dev_err(dev, "Error in reading reg 0x%x\n",
+                               deepsleep_data[id].reg_add);
+               return ret;
+       }
+
+       sleepseq_val &= ~(0xF << en_bit);
+       sleepseq_val |= BIT(en_bit);
+       sleepseq_val |= ((slots & 0x7) << slot_bit);
+       ret = rc5t583_set_bits(dev, RICOH_ONOFFSEL_REG, BIT(1));
+       if (ret < 0) {
+               dev_err(dev, "Error in updating the 0x%02x register\n",
+                               RICOH_ONOFFSEL_REG);
+               return ret;
+       }
+
+       ret = rc5t583_write(dev, deepsleep_data[id].reg_add, sleepseq_val);
+       if (ret < 0) {
+               dev_err(dev, "Error in writing reg 0x%x\n",
+                               deepsleep_data[id].reg_add);
+               return ret;
+       }
+
+       if (id == RC5T583_DS_LDO4) {
+               ret = rc5t583_write(dev, RICOH_SWCTL_REG, 0x1);
+               if (ret < 0)
+                       dev_err(dev, "Error in writing reg 0x%x\n",
+                               RICOH_SWCTL_REG);
+       }
+       return ret;
+}
+
+static int __rc5t583_set_ext_pwrreq2_control(struct device *dev,
+       int id, int ext_pwr)
+{
+       int ret;
+
+       if (id != RC5T583_DS_DC0) {
+               dev_err(dev, "PWRREQ2 is invalid control for rail %d\n", id);
+               return -EINVAL;
+       }
+
+       ret = rc5t583_set_bits(dev, RICOH_ONOFFSEL_REG, BIT(2));
+       if (ret < 0)
+               dev_err(dev, "Error in updating the ONOFFSEL 0x10 register\n");
+       return ret;
+}
+
+int rc5t583_ext_power_req_config(struct device *dev, int ds_id,
+       int ext_pwr_req, int deepsleep_slot_nr)
+{
+       if ((ext_pwr_req & EXT_PWR_REQ) == EXT_PWR_REQ)
+               return -EINVAL;
+
+       if (ext_pwr_req & RC5T583_EXT_PWRREQ1_CONTROL)
+               return __rc5t583_set_ext_pwrreq1_control(dev, ds_id,
+                               ext_pwr_req, deepsleep_slot_nr);
+
+       if (ext_pwr_req & RC5T583_EXT_PWRREQ2_CONTROL)
+               return __rc5t583_set_ext_pwrreq2_control(dev,
+                       ds_id, ext_pwr_req);
+       return 0;
+}
+
+static int rc5t583_clear_ext_power_req(struct rc5t583 *rc5t583,
+       struct rc5t583_platform_data *pdata)
+{
+       int ret;
+       int i;
+       uint8_t on_off_val = 0;
+
+       /*  Clear ONOFFSEL register */
+       if (pdata->enable_shutdown)
+               on_off_val = 0x1;
+
+       ret = rc5t583_write(rc5t583->dev, RICOH_ONOFFSEL_REG, on_off_val);
+       if (ret < 0)
+               dev_warn(rc5t583->dev, "Error in writing reg %d error: %d\n",
+                                       RICOH_ONOFFSEL_REG, ret);
+
+       ret = rc5t583_write(rc5t583->dev, RICOH_SWCTL_REG, 0x0);
+       if (ret < 0)
+               dev_warn(rc5t583->dev, "Error in writing reg %d error: %d\n",
+                                       RICOH_SWCTL_REG, ret);
+
+       /* Clear sleep sequence register */
+       for (i = RC5T583_SLPSEQ1; i <= RC5T583_SLPSEQ11; ++i) {
+               ret = rc5t583_write(rc5t583->dev, i, 0x0);
+               if (ret < 0)
+                       dev_warn(rc5t583->dev,
+                               "Error in writing reg 0x%02x error: %d\n",
+                               i, ret);
+       }
+       return 0;
+}
+
+static bool volatile_reg(struct device *dev, unsigned int reg)
+{
+       /* Enable caching in interrupt registers */
+       switch (reg) {
+       case RC5T583_INT_EN_SYS1:
+       case RC5T583_INT_EN_SYS2:
+       case RC5T583_INT_EN_DCDC:
+       case RC5T583_INT_EN_RTC:
+       case RC5T583_INT_EN_ADC1:
+       case RC5T583_INT_EN_ADC2:
+       case RC5T583_INT_EN_ADC3:
+       case RC5T583_GPIO_GPEDGE1:
+       case RC5T583_GPIO_GPEDGE2:
+       case RC5T583_GPIO_EN_INT:
+               return false;
+
+       case RC5T583_GPIO_MON_IOIN:
+               /* This is gpio input register */
+               return true;
+
+       default:
+               /* Enable caching in gpio registers */
+               if ((reg >= RC5T583_GPIO_IOSEL) &&
+                               (reg <= RC5T583_GPIO_GPOFUNC))
+                       return false;
+
+               /* Enable caching in sleep seq registers */
+               if ((reg >= RC5T583_SLPSEQ1) && (reg <= RC5T583_SLPSEQ11))
+                       return false;
+
+               /* Enable caching of regulator registers */
+               if ((reg >= RC5T583_REG_DC0CTL) && (reg <= RC5T583_REG_SR3CTL))
+                       return false;
+               if ((reg >= RC5T583_REG_LDOEN1) &&
+                                       (reg <= RC5T583_REG_LDO9DAC_DS))
+                       return false;
+
+               break;
+       }
+
+       return true;
+}
+
+static const struct regmap_config rc5t583_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .volatile_reg = volatile_reg,
+       .max_register = RC5T583_MAX_REGS,
+       .num_reg_defaults_raw = RC5T583_MAX_REGS,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c,
+                             const struct i2c_device_id *id)
+{
+       struct rc5t583 *rc5t583;
+       struct rc5t583_platform_data *pdata = i2c->dev.platform_data;
+       int ret;
+       bool irq_init_success = false;
+
+       if (!pdata) {
+               dev_err(&i2c->dev, "Err: Platform data not found\n");
+               return -EINVAL;
+       }
+
+       rc5t583 = devm_kzalloc(&i2c->dev, sizeof(struct rc5t583), GFP_KERNEL);
+       if (!rc5t583) {
+               dev_err(&i2c->dev, "Memory allocation failed\n");
+               return -ENOMEM;
+       }
+
+       rc5t583->dev = &i2c->dev;
+       i2c_set_clientdata(i2c, rc5t583);
+
+       rc5t583->regmap = regmap_init_i2c(i2c, &rc5t583_regmap_config);
+       if (IS_ERR(rc5t583->regmap)) {
+               ret = PTR_ERR(rc5t583->regmap);
+               dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = rc5t583_clear_ext_power_req(rc5t583, pdata);
+       if (ret < 0)
+               goto err_irq_init;
+
+       if (i2c->irq) {
+               ret = rc5t583_irq_init(rc5t583, i2c->irq, pdata->irq_base);
+               /* Still continue with waring if irq init fails */
+               if (ret)
+                       dev_warn(&i2c->dev, "IRQ init failed: %d\n", ret);
+               else
+                       irq_init_success = true;
+       }
+
+       ret = mfd_add_devices(rc5t583->dev, -1, rc5t583_subdevs,
+                       ARRAY_SIZE(rc5t583_subdevs), NULL, 0);
+       if (ret) {
+               dev_err(&i2c->dev, "add mfd devices failed: %d\n", ret);
+               goto err_add_devs;
+       }
+
+       return 0;
+
+err_add_devs:
+       if (irq_init_success)
+               rc5t583_irq_exit(rc5t583);
+err_irq_init:
+       regmap_exit(rc5t583->regmap);
+       return ret;
+}
+
+static int  __devexit rc5t583_i2c_remove(struct i2c_client *i2c)
+{
+       struct rc5t583 *rc5t583 = i2c_get_clientdata(i2c);
+
+       mfd_remove_devices(rc5t583->dev);
+       rc5t583_irq_exit(rc5t583);
+       regmap_exit(rc5t583->regmap);
+       return 0;
+}
+
+static const struct i2c_device_id rc5t583_i2c_id[] = {
+       {.name = "rc5t583", .driver_data = 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, rc5t583_i2c_id);
+
+static struct i2c_driver rc5t583_i2c_driver = {
+       .driver = {
+                  .name = "rc5t583",
+                  .owner = THIS_MODULE,
+                  },
+       .probe = rc5t583_i2c_probe,
+       .remove = __devexit_p(rc5t583_i2c_remove),
+       .id_table = rc5t583_i2c_id,
+};
+
+static int __init rc5t583_i2c_init(void)
+{
+       return i2c_add_driver(&rc5t583_i2c_driver);
+}
+subsys_initcall(rc5t583_i2c_init);
+
+static void __exit rc5t583_i2c_exit(void)
+{
+       i2c_del_driver(&rc5t583_i2c_driver);
+}
+
+module_exit(rc5t583_i2c_exit);
+
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("RICOH RC5T583 power management system device driver");
+MODULE_LICENSE("GPL v2");
index caadabeed8e94d59ae55fd8dbde84b37014769bb..48949d998d105f62172dae5697d3e4e3dd99819a 100644 (file)
 #include <linux/mfd/s5m87xx/s5m-rtc.h>
 #include <linux/regmap.h>
 
-static struct mfd_cell s5m87xx_devs[] = {
+static struct mfd_cell s5m8751_devs[] = {
+       {
+               .name = "s5m8751-pmic",
+       }, {
+               .name = "s5m-charger",
+       }, {
+               .name = "s5m8751-codec",
+       },
+};
+
+static struct mfd_cell s5m8763_devs[] = {
+       {
+               .name = "s5m8763-pmic",
+       }, {
+               .name = "s5m-rtc",
+       }, {
+               .name = "s5m-charger",
+       },
+};
+
+static struct mfd_cell s5m8767_devs[] = {
        {
                .name = "s5m8767-pmic",
        }, {
@@ -42,7 +62,7 @@ EXPORT_SYMBOL_GPL(s5m_reg_read);
 
 int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
 {
-       return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);;
+       return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);
 }
 EXPORT_SYMBOL_GPL(s5m_bulk_read);
 
@@ -54,7 +74,7 @@ EXPORT_SYMBOL_GPL(s5m_reg_write);
 
 int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
 {
-       return regmap_raw_write(s5m87xx->regmap, reg, buf, count * sizeof(u16));
+       return regmap_raw_write(s5m87xx->regmap, reg, buf, count);
 }
 EXPORT_SYMBOL_GPL(s5m_bulk_write);
 
@@ -74,10 +94,10 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
 {
        struct s5m_platform_data *pdata = i2c->dev.platform_data;
        struct s5m87xx_dev *s5m87xx;
-       int ret = 0;
-       int error;
+       int ret;
 
-       s5m87xx = kzalloc(sizeof(struct s5m87xx_dev), GFP_KERNEL);
+       s5m87xx = devm_kzalloc(&i2c->dev, sizeof(struct s5m87xx_dev),
+                               GFP_KERNEL);
        if (s5m87xx == NULL)
                return -ENOMEM;
 
@@ -96,9 +116,9 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
 
        s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config);
        if (IS_ERR(s5m87xx->regmap)) {
-               error = PTR_ERR(s5m87xx->regmap);
+               ret = PTR_ERR(s5m87xx->regmap);
                dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
-                       error);
+                       ret);
                goto err;
        }
 
@@ -112,9 +132,23 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
 
        pm_runtime_set_active(s5m87xx->dev);
 
-       ret = mfd_add_devices(s5m87xx->dev, -1,
-                               s5m87xx_devs, ARRAY_SIZE(s5m87xx_devs),
-                               NULL, 0);
+       switch (s5m87xx->device_type) {
+       case S5M8751X:
+               ret = mfd_add_devices(s5m87xx->dev, -1, s5m8751_devs,
+                                       ARRAY_SIZE(s5m8751_devs), NULL, 0);
+               break;
+       case S5M8763X:
+               ret = mfd_add_devices(s5m87xx->dev, -1, s5m8763_devs,
+                                       ARRAY_SIZE(s5m8763_devs), NULL, 0);
+               break;
+       case S5M8767X:
+               ret = mfd_add_devices(s5m87xx->dev, -1, s5m8767_devs,
+                                       ARRAY_SIZE(s5m8767_devs), NULL, 0);
+               break;
+       default:
+               /* If this happens the probe function is problem */
+               BUG();
+       }
 
        if (ret < 0)
                goto err;
@@ -126,7 +160,6 @@ err:
        s5m_irq_exit(s5m87xx);
        i2c_unregister_device(s5m87xx->rtc);
        regmap_exit(s5m87xx->regmap);
-       kfree(s5m87xx);
        return ret;
 }
 
@@ -138,7 +171,6 @@ static int s5m87xx_i2c_remove(struct i2c_client *i2c)
        s5m_irq_exit(s5m87xx);
        i2c_unregister_device(s5m87xx->rtc);
        regmap_exit(s5m87xx->regmap);
-       kfree(s5m87xx);
        return 0;
 }
 
index de76dfb6f0ad2af82796c74d4d16a9abe3701bb9..0236676085cf096f6c4e0091ac3803d4f8fc1f3f 100644 (file)
@@ -342,7 +342,10 @@ int s5m_irq_resume(struct s5m87xx_dev *s5m87xx)
                        s5m8767_irq_thread(s5m87xx->irq_base, s5m87xx);
                        break;
                default:
-                       break;
+                       dev_err(s5m87xx->dev,
+                               "Unknown device type %d\n",
+                               s5m87xx->device_type);
+                       return -EINVAL;
 
                }
        }
@@ -444,7 +447,9 @@ int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
                }
                break;
        default:
-               break;
+               dev_err(s5m87xx->dev,
+                       "Unknown device type %d\n", s5m87xx->device_type);
+               return -EINVAL;
        }
 
        if (!s5m87xx->ono)
@@ -467,12 +472,15 @@ int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
                                        IRQF_ONESHOT, "s5m87xx-ono", s5m87xx);
                break;
        default:
+               ret = -EINVAL;
                break;
        }
 
-       if (ret)
+       if (ret) {
                dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
                        s5m87xx->ono, ret);
+               return ret;
+       }
 
        return 0;
 }
index f4d86117f44a21bcc140e93b8fd116798d6d5054..d927dd49acb340f303cf7e705e941863be8b312e 100644 (file)
@@ -387,14 +387,6 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
 
 EXPORT_SYMBOL_GPL(sm501_unit_power);
 
-
-/* Perform a rounded division. */
-static long sm501fb_round_div(long num, long denom)
-{
-        /* n / d + 1 / 2 = (2n + d) / 2d */
-        return (2 * num + denom) / (2 * denom);
-}
-
 /* clock value structure. */
 struct sm501_clock {
        unsigned long mclk;
@@ -428,7 +420,7 @@ static int sm501_calc_clock(unsigned long freq,
                /* try all 8 shift values.*/
                for (shift = 0; shift < 8; shift++) {
                        /* Calculate difference to requested clock */
-                       diff = sm501fb_round_div(mclk, divider << shift) - freq;
+                       diff = DIV_ROUND_CLOSEST(mclk, divider << shift) - freq;
                        if (diff < 0)
                                diff = -diff;
 
index e07947e56b2a0e2bd68d5aa7da434ae6aa5ed878..2dd8d49cb30bc7d63d14250e673b2c12eb4cef3f 100644 (file)
@@ -298,6 +298,11 @@ static struct mfd_cell stmpe_gpio_cell = {
        .num_resources  = ARRAY_SIZE(stmpe_gpio_resources),
 };
 
+static struct mfd_cell stmpe_gpio_cell_noirq = {
+       .name           = "stmpe-gpio",
+       /* gpio cell resources consist of an irq only so no resources here */
+};
+
 /*
  * Keypad (1601, 2401, 2403)
  */
@@ -346,6 +351,13 @@ static struct stmpe_variant_block stmpe801_blocks[] = {
        },
 };
 
+static struct stmpe_variant_block stmpe801_blocks_noirq[] = {
+       {
+               .cell   = &stmpe_gpio_cell_noirq,
+               .block  = STMPE_BLOCK_GPIO,
+       },
+};
+
 static int stmpe801_enable(struct stmpe *stmpe, unsigned int blocks,
                           bool enable)
 {
@@ -367,6 +379,17 @@ static struct stmpe_variant_info stmpe801 = {
        .enable         = stmpe801_enable,
 };
 
+static struct stmpe_variant_info stmpe801_noirq = {
+       .name           = "stmpe801",
+       .id_val         = STMPE801_ID,
+       .id_mask        = 0xffff,
+       .num_gpios      = 8,
+       .regs           = stmpe801_regs,
+       .blocks         = stmpe801_blocks_noirq,
+       .num_blocks     = ARRAY_SIZE(stmpe801_blocks_noirq),
+       .enable         = stmpe801_enable,
+};
+
 /*
  * Touchscreen (STMPE811 or STMPE610)
  */
@@ -712,7 +735,7 @@ static struct stmpe_variant_info stmpe2403 = {
        .enable_autosleep       = stmpe1601_autosleep, /* same as stmpe1601 */
 };
 
-static struct stmpe_variant_info *stmpe_variant_info[] = {
+static struct stmpe_variant_info *stmpe_variant_info[STMPE_NBR_PARTS] = {
        [STMPE610]      = &stmpe610,
        [STMPE801]      = &stmpe801,
        [STMPE811]      = &stmpe811,
@@ -721,6 +744,16 @@ static struct stmpe_variant_info *stmpe_variant_info[] = {
        [STMPE2403]     = &stmpe2403,
 };
 
+/*
+ * These devices can be connected in a 'no-irq' configuration - the irq pin
+ * is not used and the device cannot interrupt the CPU. Here we only list
+ * devices which support this configuration - the driver will fail probing
+ * for any devices not listed here which are configured in this way.
+ */
+static struct stmpe_variant_info *stmpe_noirq_variant_info[STMPE_NBR_PARTS] = {
+       [STMPE801]      = &stmpe801_noirq,
+};
+
 static irqreturn_t stmpe_irq(int irq, void *data)
 {
        struct stmpe *stmpe = data;
@@ -864,7 +897,7 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
        unsigned int irq_trigger = stmpe->pdata->irq_trigger;
        int autosleep_timeout = stmpe->pdata->autosleep_timeout;
        struct stmpe_variant_info *variant = stmpe->variant;
-       u8 icr;
+       u8 icr = 0;
        unsigned int id;
        u8 data[2];
        int ret;
@@ -887,31 +920,33 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
        if (ret)
                return ret;
 
-       if (id == STMPE801_ID)
-               icr = STMPE801_REG_SYS_CTRL_INT_EN;
-       else
-               icr = STMPE_ICR_LSB_GIM;
-
-       /* STMPE801 doesn't support Edge interrupts */
-       if (id != STMPE801_ID) {
-               if (irq_trigger == IRQF_TRIGGER_FALLING ||
-                               irq_trigger == IRQF_TRIGGER_RISING)
-                       icr |= STMPE_ICR_LSB_EDGE;
-       }
-
-       if (irq_trigger == IRQF_TRIGGER_RISING ||
-                       irq_trigger == IRQF_TRIGGER_HIGH) {
+       if (stmpe->irq >= 0) {
                if (id == STMPE801_ID)
-                       icr |= STMPE801_REG_SYS_CTRL_INT_HI;
+                       icr = STMPE801_REG_SYS_CTRL_INT_EN;
                else
-                       icr |= STMPE_ICR_LSB_HIGH;
-       }
+                       icr = STMPE_ICR_LSB_GIM;
 
-       if (stmpe->pdata->irq_invert_polarity) {
-               if (id == STMPE801_ID)
-                       icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
-               else
-                       icr ^= STMPE_ICR_LSB_HIGH;
+               /* STMPE801 doesn't support Edge interrupts */
+               if (id != STMPE801_ID) {
+                       if (irq_trigger == IRQF_TRIGGER_FALLING ||
+                                       irq_trigger == IRQF_TRIGGER_RISING)
+                               icr |= STMPE_ICR_LSB_EDGE;
+               }
+
+               if (irq_trigger == IRQF_TRIGGER_RISING ||
+                               irq_trigger == IRQF_TRIGGER_HIGH) {
+                       if (id == STMPE801_ID)
+                               icr |= STMPE801_REG_SYS_CTRL_INT_HI;
+                       else
+                               icr |= STMPE_ICR_LSB_HIGH;
+               }
+
+               if (stmpe->pdata->irq_invert_polarity) {
+                       if (id == STMPE801_ID)
+                               icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
+                       else
+                               icr ^= STMPE_ICR_LSB_HIGH;
+               }
        }
 
        if (stmpe->pdata->autosleep) {
@@ -1001,19 +1036,38 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
                stmpe->irq = ci->irq;
        }
 
+       if (stmpe->irq < 0) {
+               /* use alternate variant info for no-irq mode, if supported */
+               dev_info(stmpe->dev,
+                       "%s configured in no-irq mode by platform data\n",
+                       stmpe->variant->name);
+               if (!stmpe_noirq_variant_info[stmpe->partnum]) {
+                       dev_err(stmpe->dev,
+                               "%s does not support no-irq mode!\n",
+                               stmpe->variant->name);
+                       ret = -ENODEV;
+                       goto free_gpio;
+               }
+               stmpe->variant = stmpe_noirq_variant_info[stmpe->partnum];
+       }
+
        ret = stmpe_chip_init(stmpe);
        if (ret)
                goto free_gpio;
 
-       ret = stmpe_irq_init(stmpe);
-       if (ret)
-               goto free_gpio;
+       if (stmpe->irq >= 0) {
+               ret = stmpe_irq_init(stmpe);
+               if (ret)
+                       goto free_gpio;
 
-       ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
-                       pdata->irq_trigger | IRQF_ONESHOT, "stmpe", stmpe);
-       if (ret) {
-               dev_err(stmpe->dev, "failed to request IRQ: %d\n", ret);
-               goto out_removeirq;
+               ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
+                               pdata->irq_trigger | IRQF_ONESHOT,
+                               "stmpe", stmpe);
+               if (ret) {
+                       dev_err(stmpe->dev, "failed to request IRQ: %d\n",
+                                       ret);
+                       goto out_removeirq;
+               }
        }
 
        ret = stmpe_devices_init(stmpe);
@@ -1026,9 +1080,11 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
 
 out_removedevs:
        mfd_remove_devices(stmpe->dev);
-       free_irq(stmpe->irq, stmpe);
+       if (stmpe->irq >= 0)
+               free_irq(stmpe->irq, stmpe);
 out_removeirq:
-       stmpe_irq_remove(stmpe);
+       if (stmpe->irq >= 0)
+               stmpe_irq_remove(stmpe);
 free_gpio:
        if (pdata->irq_over_gpio)
                gpio_free(pdata->irq_gpio);
@@ -1041,8 +1097,10 @@ int stmpe_remove(struct stmpe *stmpe)
 {
        mfd_remove_devices(stmpe->dev);
 
-       free_irq(stmpe->irq, stmpe);
-       stmpe_irq_remove(stmpe);
+       if (stmpe->irq >= 0) {
+               free_irq(stmpe->irq, stmpe);
+               stmpe_irq_remove(stmpe);
+       }
 
        if (stmpe->pdata->irq_over_gpio)
                gpio_free(stmpe->pdata->irq_gpio);
@@ -1057,7 +1115,7 @@ static int stmpe_suspend(struct device *dev)
 {
        struct stmpe *stmpe = dev_get_drvdata(dev);
 
-       if (device_may_wakeup(dev))
+       if (stmpe->irq >= 0 && device_may_wakeup(dev))
                enable_irq_wake(stmpe->irq);
 
        return 0;
@@ -1067,7 +1125,7 @@ static int stmpe_resume(struct device *dev)
 {
        struct stmpe *stmpe = dev_get_drvdata(dev);
 
-       if (device_may_wakeup(dev))
+       if (stmpe->irq >= 0 && device_may_wakeup(dev))
                disable_irq_wake(stmpe->irq);
 
        return 0;
diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c
new file mode 100644 (file)
index 0000000..a66d4df
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * Core driver for TI TPS65090 PMIC family
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65090.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+
+#define NUM_INT_REG 2
+#define TOTAL_NUM_REG 0x18
+
+/* interrupt status registers */
+#define TPS65090_INT_STS       0x0
+#define TPS65090_INT_STS2      0x1
+
+/* interrupt mask registers */
+#define TPS65090_INT_MSK       0x2
+#define TPS65090_INT_MSK2      0x3
+
+struct tps65090_irq_data {
+       u8              mask_reg;
+       u8              mask_pos;
+};
+
+#define TPS65090_IRQ(_reg, _mask_pos)          \
+       {                                       \
+               .mask_reg       = (_reg),       \
+               .mask_pos       = (_mask_pos),  \
+       }
+
+static const struct tps65090_irq_data tps65090_irqs[] = {
+       [0]             = TPS65090_IRQ(0, 0),
+       [1]             = TPS65090_IRQ(0, 1),
+       [2]             = TPS65090_IRQ(0, 2),
+       [3]             = TPS65090_IRQ(0, 3),
+       [4]             = TPS65090_IRQ(0, 4),
+       [5]             = TPS65090_IRQ(0, 5),
+       [6]             = TPS65090_IRQ(0, 6),
+       [7]             = TPS65090_IRQ(0, 7),
+       [8]             = TPS65090_IRQ(1, 0),
+       [9]             = TPS65090_IRQ(1, 1),
+       [10]            = TPS65090_IRQ(1, 2),
+       [11]            = TPS65090_IRQ(1, 3),
+       [12]            = TPS65090_IRQ(1, 4),
+       [13]            = TPS65090_IRQ(1, 5),
+       [14]            = TPS65090_IRQ(1, 6),
+       [15]            = TPS65090_IRQ(1, 7),
+};
+
+static struct mfd_cell tps65090s[] = {
+       {
+               .name = "tps65910-pmic",
+       },
+       {
+               .name = "tps65910-regulator",
+       },
+};
+
+struct tps65090 {
+       struct mutex            lock;
+       struct device           *dev;
+       struct i2c_client       *client;
+       struct regmap           *rmap;
+       struct irq_chip         irq_chip;
+       struct mutex            irq_lock;
+       int                     irq_base;
+       unsigned int            id;
+};
+
+int tps65090_write(struct device *dev, int reg, uint8_t val)
+{
+       struct tps65090 *tps = dev_get_drvdata(dev);
+       return regmap_write(tps->rmap, reg, val);
+}
+EXPORT_SYMBOL_GPL(tps65090_write);
+
+int tps65090_read(struct device *dev, int reg, uint8_t *val)
+{
+       struct tps65090 *tps = dev_get_drvdata(dev);
+       unsigned int temp_val;
+       int ret;
+       ret = regmap_read(tps->rmap, reg, &temp_val);
+       if (!ret)
+               *val = temp_val;
+       return ret;
+}
+EXPORT_SYMBOL_GPL(tps65090_read);
+
+int tps65090_set_bits(struct device *dev, int reg, uint8_t bit_num)
+{
+       struct tps65090 *tps = dev_get_drvdata(dev);
+       return regmap_update_bits(tps->rmap, reg, BIT(bit_num), ~0u);
+}
+EXPORT_SYMBOL_GPL(tps65090_set_bits);
+
+int tps65090_clr_bits(struct device *dev, int reg, uint8_t bit_num)
+{
+       struct tps65090 *tps = dev_get_drvdata(dev);
+       return regmap_update_bits(tps->rmap, reg, BIT(bit_num), 0u);
+}
+EXPORT_SYMBOL_GPL(tps65090_clr_bits);
+
+static void tps65090_irq_lock(struct irq_data *data)
+{
+       struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data);
+
+       mutex_lock(&tps65090->irq_lock);
+}
+
+static void tps65090_irq_mask(struct irq_data *irq_data)
+{
+       struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data);
+       unsigned int __irq = irq_data->hwirq;
+       const struct tps65090_irq_data *data = &tps65090_irqs[__irq];
+
+       tps65090_set_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg),
+               data->mask_pos);
+}
+
+static void tps65090_irq_unmask(struct irq_data *irq_data)
+{
+       struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data);
+       unsigned int __irq = irq_data->irq - tps65090->irq_base;
+       const struct tps65090_irq_data *data = &tps65090_irqs[__irq];
+
+       tps65090_clr_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg),
+               data->mask_pos);
+}
+
+static void tps65090_irq_sync_unlock(struct irq_data *data)
+{
+       struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data);
+
+       mutex_unlock(&tps65090->irq_lock);
+}
+
+static irqreturn_t tps65090_irq(int irq, void *data)
+{
+       struct tps65090 *tps65090 = data;
+       int ret = 0;
+       u8 status, mask;
+       unsigned long int acks = 0;
+       int i;
+
+       for (i = 0; i < NUM_INT_REG; i++) {
+               ret = tps65090_read(tps65090->dev, TPS65090_INT_MSK + i, &mask);
+               if (ret < 0) {
+                       dev_err(tps65090->dev,
+                               "failed to read mask reg [addr:%d]\n",
+                               TPS65090_INT_MSK + i);
+                       return IRQ_NONE;
+               }
+               ret = tps65090_read(tps65090->dev, TPS65090_INT_STS + i,
+                       &status);
+               if (ret < 0) {
+                       dev_err(tps65090->dev,
+                               "failed to read status reg [addr:%d]\n",
+                                TPS65090_INT_STS + i);
+                       return IRQ_NONE;
+               }
+               if (status) {
+                       /* Ack only those interrupts which are not masked */
+                       status &= (~mask);
+                       ret = tps65090_write(tps65090->dev,
+                                       TPS65090_INT_STS + i, status);
+                       if (ret < 0) {
+                               dev_err(tps65090->dev,
+                                       "failed to write interrupt status\n");
+                               return IRQ_NONE;
+                       }
+                       acks |= (status << (i * 8));
+               }
+       }
+
+       for_each_set_bit(i, &acks, ARRAY_SIZE(tps65090_irqs))
+               handle_nested_irq(tps65090->irq_base + i);
+       return acks ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int __devinit tps65090_irq_init(struct tps65090 *tps65090, int irq,
+       int irq_base)
+{
+       int i, ret;
+
+       if (!irq_base) {
+               dev_err(tps65090->dev, "IRQ base not set\n");
+               return -EINVAL;
+       }
+
+       mutex_init(&tps65090->irq_lock);
+
+       for (i = 0; i < NUM_INT_REG; i++)
+               tps65090_write(tps65090->dev, TPS65090_INT_MSK + i, 0xFF);
+
+       for (i = 0; i < NUM_INT_REG; i++)
+               tps65090_write(tps65090->dev, TPS65090_INT_STS + i, 0xff);
+
+       tps65090->irq_base = irq_base;
+       tps65090->irq_chip.name = "tps65090";
+       tps65090->irq_chip.irq_mask = tps65090_irq_mask;
+       tps65090->irq_chip.irq_unmask = tps65090_irq_unmask;
+       tps65090->irq_chip.irq_bus_lock = tps65090_irq_lock;
+       tps65090->irq_chip.irq_bus_sync_unlock = tps65090_irq_sync_unlock;
+
+       for (i = 0; i < ARRAY_SIZE(tps65090_irqs); i++) {
+               int __irq = i + tps65090->irq_base;
+               irq_set_chip_data(__irq, tps65090);
+               irq_set_chip_and_handler(__irq, &tps65090->irq_chip,
+                                        handle_simple_irq);
+               irq_set_nested_thread(__irq, 1);
+#ifdef CONFIG_ARM
+               set_irq_flags(__irq, IRQF_VALID);
+#endif
+       }
+
+       ret = request_threaded_irq(irq, NULL, tps65090_irq, IRQF_ONESHOT,
+                               "tps65090", tps65090);
+       if (!ret) {
+               device_init_wakeup(tps65090->dev, 1);
+               enable_irq_wake(irq);
+       }
+
+       return ret;
+}
+
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+       if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS))
+               return true;
+       else
+               return false;
+}
+
+static const struct regmap_config tps65090_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = TOTAL_NUM_REG,
+       .num_reg_defaults_raw = TOTAL_NUM_REG,
+       .cache_type = REGCACHE_RBTREE,
+       .volatile_reg = is_volatile_reg,
+};
+
+static int __devinit tps65090_i2c_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       struct tps65090_platform_data *pdata = client->dev.platform_data;
+       struct tps65090 *tps65090;
+       int ret;
+
+       if (!pdata) {
+               dev_err(&client->dev, "tps65090 requires platform data\n");
+               return -EINVAL;
+       }
+
+       tps65090 = devm_kzalloc(&client->dev, sizeof(struct tps65090),
+               GFP_KERNEL);
+       if (tps65090 == NULL)
+               return -ENOMEM;
+
+       tps65090->client = client;
+       tps65090->dev = &client->dev;
+       i2c_set_clientdata(client, tps65090);
+
+       mutex_init(&tps65090->lock);
+
+       if (client->irq) {
+               ret = tps65090_irq_init(tps65090, client->irq, pdata->irq_base);
+               if (ret) {
+                       dev_err(&client->dev, "IRQ init failed with err: %d\n",
+                               ret);
+                       goto err_exit;
+               }
+       }
+
+       tps65090->rmap = regmap_init_i2c(tps65090->client,
+               &tps65090_regmap_config);
+       if (IS_ERR(tps65090->rmap)) {
+               dev_err(&client->dev, "regmap_init failed with err: %ld\n",
+                       PTR_ERR(tps65090->rmap));
+               goto err_irq_exit;
+       };
+
+       ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
+               ARRAY_SIZE(tps65090s), NULL, 0);
+       if (ret) {
+               dev_err(&client->dev, "add mfd devices failed with err: %d\n",
+                       ret);
+               goto err_regmap_exit;
+       }
+
+       return 0;
+
+err_regmap_exit:
+       regmap_exit(tps65090->rmap);
+
+err_irq_exit:
+       if (client->irq)
+               free_irq(client->irq, tps65090);
+err_exit:
+       return ret;
+}
+
+static int __devexit tps65090_i2c_remove(struct i2c_client *client)
+{
+       struct tps65090 *tps65090 = i2c_get_clientdata(client);
+
+       mfd_remove_devices(tps65090->dev);
+       regmap_exit(tps65090->rmap);
+       if (client->irq)
+               free_irq(client->irq, tps65090);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int tps65090_i2c_suspend(struct i2c_client *client, pm_message_t state)
+{
+       if (client->irq)
+               disable_irq(client->irq);
+       return 0;
+}
+
+static int tps65090_i2c_resume(struct i2c_client *client)
+{
+       if (client->irq)
+               enable_irq(client->irq);
+       return 0;
+}
+#endif
+
+static const struct i2c_device_id tps65090_id_table[] = {
+       { "tps65090", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, tps65090_id_table);
+
+static struct i2c_driver tps65090_driver = {
+       .driver = {
+               .name   = "tps65090",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = tps65090_i2c_probe,
+       .remove         = __devexit_p(tps65090_i2c_remove),
+#ifdef CONFIG_PM
+       .suspend        = tps65090_i2c_suspend,
+       .resume         = tps65090_i2c_resume,
+#endif
+       .id_table       = tps65090_id_table,
+};
+
+static int __init tps65090_init(void)
+{
+       return i2c_add_driver(&tps65090_driver);
+}
+subsys_initcall(tps65090_init);
+
+static void __exit tps65090_exit(void)
+{
+       i2c_del_driver(&tps65090_driver);
+}
+module_exit(tps65090_exit);
+
+MODULE_DESCRIPTION("TPS65090 core driver");
+MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c
new file mode 100644 (file)
index 0000000..f7d854e
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * tps65217.c
+ *
+ * TPS65217 chip family multi-function driver
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65217.h>
+
+/**
+ * tps65217_reg_read: Read a single tps65217 register.
+ *
+ * @tps: Device to read from.
+ * @reg: Register to read.
+ * @val: Contians the value
+ */
+int tps65217_reg_read(struct tps65217 *tps, unsigned int reg,
+                       unsigned int *val)
+{
+       return regmap_read(tps->regmap, reg, val);
+}
+EXPORT_SYMBOL_GPL(tps65217_reg_read);
+
+/**
+ * tps65217_reg_write: Write a single tps65217 register.
+ *
+ * @tps65217: Device to write to.
+ * @reg: Register to write to.
+ * @val: Value to write.
+ * @level: Password protected level
+ */
+int tps65217_reg_write(struct tps65217 *tps, unsigned int reg,
+                       unsigned int val, unsigned int level)
+{
+       int ret;
+       unsigned int xor_reg_val;
+
+       switch (level) {
+       case TPS65217_PROTECT_NONE:
+               return regmap_write(tps->regmap, reg, val);
+       case TPS65217_PROTECT_L1:
+               xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
+               ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
+                                                       xor_reg_val);
+               if (ret < 0)
+                       return ret;
+
+               return regmap_write(tps->regmap, reg, val);
+       case TPS65217_PROTECT_L2:
+               xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
+               ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
+                                                       xor_reg_val);
+               if (ret < 0)
+                       return ret;
+               ret = regmap_write(tps->regmap, reg, val);
+               if (ret < 0)
+                       return ret;
+               ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
+                                                       xor_reg_val);
+               if (ret < 0)
+                       return ret;
+               return regmap_write(tps->regmap, reg, val);
+       default:
+               return -EINVAL;
+       }
+}
+EXPORT_SYMBOL_GPL(tps65217_reg_write);
+
+/**
+ * tps65217_update_bits: Modify bits w.r.t mask, val and level.
+ *
+ * @tps65217: Device to write to.
+ * @reg: Register to read-write to.
+ * @mask: Mask.
+ * @val: Value to write.
+ * @level: Password protected level
+ */
+int tps65217_update_bits(struct tps65217 *tps, unsigned int reg,
+               unsigned int mask, unsigned int val, unsigned int level)
+{
+       int ret;
+       unsigned int data;
+
+       ret = tps65217_reg_read(tps, reg, &data);
+       if (ret) {
+               dev_err(tps->dev, "Read from reg 0x%x failed\n", reg);
+               return ret;
+       }
+
+       data &= ~mask;
+       data |= val & mask;
+
+       ret = tps65217_reg_write(tps, reg, data, level);
+       if (ret)
+               dev_err(tps->dev, "Write for reg 0x%x failed\n", reg);
+
+       return ret;
+}
+
+int tps65217_set_bits(struct tps65217 *tps, unsigned int reg,
+               unsigned int mask, unsigned int val, unsigned int level)
+{
+       return tps65217_update_bits(tps, reg, mask, val, level);
+}
+EXPORT_SYMBOL_GPL(tps65217_set_bits);
+
+int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
+               unsigned int mask, unsigned int level)
+{
+       return tps65217_update_bits(tps, reg, mask, 0, level);
+}
+EXPORT_SYMBOL_GPL(tps65217_clear_bits);
+
+static struct regmap_config tps65217_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+static int __devinit tps65217_probe(struct i2c_client *client,
+                               const struct i2c_device_id *ids)
+{
+       struct tps65217 *tps;
+       struct tps65217_board *pdata = client->dev.platform_data;
+       int i, ret;
+       unsigned int version;
+
+       tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
+       if (!tps)
+               return -ENOMEM;
+
+       tps->pdata = pdata;
+       tps->regmap = regmap_init_i2c(client, &tps65217_regmap_config);
+       if (IS_ERR(tps->regmap)) {
+               ret = PTR_ERR(tps->regmap);
+               dev_err(tps->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       i2c_set_clientdata(client, tps);
+       tps->dev = &client->dev;
+
+       ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version);
+       if (ret < 0) {
+               dev_err(tps->dev, "Failed to read revision"
+                                       " register: %d\n", ret);
+               goto err_regmap;
+       }
+
+       dev_info(tps->dev, "TPS65217 ID %#x version 1.%d\n",
+                       (version & TPS65217_CHIPID_CHIP_MASK) >> 4,
+                       version & TPS65217_CHIPID_REV_MASK);
+
+       for (i = 0; i < TPS65217_NUM_REGULATOR; i++) {
+               struct platform_device *pdev;
+
+               pdev = platform_device_alloc("tps65217-pmic", i);
+               if (!pdev) {
+                       dev_err(tps->dev, "Cannot create regulator %d\n", i);
+                       continue;
+               }
+
+               pdev->dev.parent = tps->dev;
+               platform_device_add_data(pdev, &pdata->tps65217_init_data[i],
+                                       sizeof(pdata->tps65217_init_data[i]));
+               tps->regulator_pdev[i] = pdev;
+
+               platform_device_add(pdev);
+       }
+
+       return 0;
+
+err_regmap:
+       regmap_exit(tps->regmap);
+
+       return ret;
+}
+
+static int __devexit tps65217_remove(struct i2c_client *client)
+{
+       struct tps65217 *tps = i2c_get_clientdata(client);
+       int i;
+
+       for (i = 0; i < TPS65217_NUM_REGULATOR; i++)
+               platform_device_unregister(tps->regulator_pdev[i]);
+
+       regmap_exit(tps->regmap);
+
+       return 0;
+}
+
+static const struct i2c_device_id tps65217_id_table[] = {
+       {"tps65217", 0xF0},
+       {/* end of list */}
+};
+MODULE_DEVICE_TABLE(i2c, tps65217_id_table);
+
+static struct i2c_driver tps65217_driver = {
+       .driver         = {
+               .name   = "tps65217",
+       },
+       .id_table       = tps65217_id_table,
+       .probe          = tps65217_probe,
+       .remove         = __devexit_p(tps65217_remove),
+};
+
+static int __init tps65217_init(void)
+{
+       return i2c_add_driver(&tps65217_driver);
+}
+subsys_initcall(tps65217_init);
+
+static void __exit tps65217_exit(void)
+{
+       i2c_del_driver(&tps65217_driver);
+}
+module_exit(tps65217_exit);
+
+MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>");
+MODULE_DESCRIPTION("TPS65217 chip family multi-function driver");
+MODULE_LICENSE("GPL v2");
index 95c0d7978bec4a67cfaa74d8c93b430dc715974b..c9ed5c00a6211bb2349858ef76161eb880e45396 100644 (file)
@@ -145,12 +145,23 @@ static void tps65910_irq_disable(struct irq_data *data)
        tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq));
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tps65910_irq_set_wake(struct irq_data *data, unsigned int enable)
+{
+       struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
+       return irq_set_irq_wake(tps65910->chip_irq, enable);
+}
+#else
+#define tps65910_irq_set_wake NULL
+#endif
+
 static struct irq_chip tps65910_irq_chip = {
        .name = "tps65910",
        .irq_bus_lock = tps65910_irq_lock,
        .irq_bus_sync_unlock = tps65910_irq_sync_unlock,
        .irq_disable = tps65910_irq_disable,
        .irq_enable = tps65910_irq_enable,
+       .irq_set_wake = tps65910_irq_set_wake,
 };
 
 int tps65910_irq_init(struct tps65910 *tps65910, int irq,
index 4392f6bca156e20a71d7acb8cce0b9316db42753..bf2b25ebf2ca7d4c9c2777158518bd2a3185a39c 100644 (file)
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
+#include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 #include <linux/mfd/core.h>
+#include <linux/regmap.h>
 #include <linux/mfd/tps65910.h>
 
 static struct mfd_cell tps65910s[] = {
@@ -38,99 +40,56 @@ static struct mfd_cell tps65910s[] = {
 static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
                                  int bytes, void *dest)
 {
-       struct i2c_client *i2c = tps65910->i2c_client;
-       struct i2c_msg xfer[2];
-       int ret;
-
-       /* Write register */
-       xfer[0].addr = i2c->addr;
-       xfer[0].flags = 0;
-       xfer[0].len = 1;
-       xfer[0].buf = &reg;
-
-       /* Read data */
-       xfer[1].addr = i2c->addr;
-       xfer[1].flags = I2C_M_RD;
-       xfer[1].len = bytes;
-       xfer[1].buf = dest;
-
-       ret = i2c_transfer(i2c->adapter, xfer, 2);
-       if (ret == 2)
-               ret = 0;
-       else if (ret >= 0)
-               ret = -EIO;
-
-       return ret;
+       return regmap_bulk_read(tps65910->regmap, reg, dest, bytes);
 }
 
 static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg,
-                                  int bytes, void *src)
+                                 int bytes, void *src)
 {
-       struct i2c_client *i2c = tps65910->i2c_client;
-       /* we add 1 byte for device register */
-       u8 msg[TPS65910_MAX_REGISTER + 1];
-       int ret;
-
-       if (bytes > TPS65910_MAX_REGISTER)
-               return -EINVAL;
-
-       msg[0] = reg;
-       memcpy(&msg[1], src, bytes);
-
-       ret = i2c_master_send(i2c, msg, bytes + 1);
-       if (ret < 0)
-               return ret;
-       if (ret != bytes + 1)
-               return -EIO;
-       return 0;
+       return regmap_bulk_write(tps65910->regmap, reg, src, bytes);
 }
 
 int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
 {
-       u8 data;
-       int err;
-
-       mutex_lock(&tps65910->io_mutex);
-       err = tps65910_i2c_read(tps65910, reg, 1, &data);
-       if (err) {
-               dev_err(tps65910->dev, "read from reg %x failed\n", reg);
-               goto out;
-       }
-
-       data |= mask;
-       err = tps65910_i2c_write(tps65910, reg, 1, &data);
-       if (err)
-               dev_err(tps65910->dev, "write to reg %x failed\n", reg);
-
-out:
-       mutex_unlock(&tps65910->io_mutex);
-       return err;
+       return regmap_update_bits(tps65910->regmap, reg, mask, mask);
 }
 EXPORT_SYMBOL_GPL(tps65910_set_bits);
 
 int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
 {
-       u8 data;
-       int err;
-
-       mutex_lock(&tps65910->io_mutex);
-       err = tps65910_i2c_read(tps65910, reg, 1, &data);
-       if (err) {
-               dev_err(tps65910->dev, "read from reg %x failed\n", reg);
-               goto out;
-       }
-
-       data &= ~mask;
-       err = tps65910_i2c_write(tps65910, reg, 1, &data);
-       if (err)
-               dev_err(tps65910->dev, "write to reg %x failed\n", reg);
-
-out:
-       mutex_unlock(&tps65910->io_mutex);
-       return err;
+       return regmap_update_bits(tps65910->regmap, reg, mask, 0);
 }
 EXPORT_SYMBOL_GPL(tps65910_clear_bits);
 
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+       struct tps65910 *tps65910 = dev_get_drvdata(dev);
+
+       /*
+        * Caching all regulator registers.
+        * All regualator register address range is same for
+        * TPS65910 and TPS65911
+        */
+       if ((reg >= TPS65910_VIO) && (reg <= TPS65910_VDAC)) {
+               /* Check for non-existing register */
+               if (tps65910_chip_id(tps65910) == TPS65910)
+                       if ((reg == TPS65911_VDDCTRL_OP) ||
+                               (reg == TPS65911_VDDCTRL_SR))
+                               return true;
+               return false;
+       }
+       return true;
+}
+
+static const struct regmap_config tps65910_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .volatile_reg = is_volatile_reg,
+       .max_register = TPS65910_MAX_REGISTER,
+       .num_reg_defaults_raw = TPS65910_MAX_REGISTER,
+       .cache_type = REGCACHE_RBTREE,
+};
+
 static int tps65910_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
@@ -161,6 +120,13 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
        tps65910->write = tps65910_i2c_write;
        mutex_init(&tps65910->io_mutex);
 
+       tps65910->regmap = regmap_init_i2c(i2c, &tps65910_regmap_config);
+       if (IS_ERR(tps65910->regmap)) {
+               ret = PTR_ERR(tps65910->regmap);
+               dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
+               goto regmap_err;
+       }
+
        ret = mfd_add_devices(tps65910->dev, -1,
                              tps65910s, ARRAY_SIZE(tps65910s),
                              NULL, 0);
@@ -178,6 +144,8 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
        return ret;
 
 err:
+       regmap_exit(tps65910->regmap);
+regmap_err:
        kfree(tps65910);
        kfree(init_data);
        return ret;
@@ -189,6 +157,7 @@ static int tps65910_i2c_remove(struct i2c_client *i2c)
 
        tps65910_irq_exit(tps65910);
        mfd_remove_devices(tps65910->dev);
+       regmap_exit(tps65910->regmap);
        kfree(tps65910);
 
        return 0;
index 806680d1bbb4ec84237eaea15dbe645122dd91ea..7c2267e71f8b7f0e75fd2efeef472b85711f967c 100644 (file)
@@ -46,9 +46,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c/twl.h>
 
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-#include <plat/cpu.h>
-#endif
+#include "twl-core.h"
 
 /*
  * The TWL4030 "Triton 2" is one of a family of a multi-function "Power
 #define twl_has_watchdog()        false
 #endif
 
-#if defined(CONFIG_MFD_TWL4030_AUDIO) || defined(CONFIG_MFD_TWL4030_AUDIO_MODULE) ||\
-       defined(CONFIG_TWL6040_CORE) || defined(CONFIG_TWL6040_CORE_MODULE)
+#if defined(CONFIG_MFD_TWL4030_AUDIO) || \
+       defined(CONFIG_MFD_TWL4030_AUDIO_MODULE)
 #define twl_has_codec()        true
 #else
 #define twl_has_codec()        false
 #define SUB_CHIP_ID1 1
 #define SUB_CHIP_ID2 2
 #define SUB_CHIP_ID3 3
+#define SUB_CHIP_ID_INVAL 0xff
 
 #define TWL_MODULE_LAST TWL4030_MODULE_LAST
 
-#define TWL4030_NR_IRQS    34 /* core:8, power:8, gpio: 18 */
-#define TWL6030_NR_IRQS    20
-
 /* Base Address defns for twl4030_map[] */
 
 /* subchip/slave 0 - USB ID */
@@ -314,7 +310,7 @@ static struct twl_mapping twl6030_map[] = {
         * so they continue to match the order in this table.
         */
        { SUB_CHIP_ID1, TWL6030_BASEADD_USB },
-       { SUB_CHIP_ID3, TWL6030_BASEADD_AUDIO },
+       { SUB_CHIP_ID_INVAL, TWL6030_BASEADD_AUDIO },
        { SUB_CHIP_ID2, TWL6030_BASEADD_DIEID },
        { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
        { SUB_CHIP_ID1, TWL6030_BASEADD_PIH },
@@ -376,6 +372,11 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
                return -EPERM;
        }
        sid = twl_map[mod_no].sid;
+       if (unlikely(sid == SUB_CHIP_ID_INVAL)) {
+               pr_err("%s: module %d is not part of the pmic\n",
+                      DRIVER_NAME, mod_no);
+               return -EINVAL;
+       }
        twl = &twl_modules[sid];
 
        mutex_lock(&twl->xfer_lock);
@@ -433,6 +434,11 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
                return -EPERM;
        }
        sid = twl_map[mod_no].sid;
+       if (unlikely(sid == SUB_CHIP_ID_INVAL)) {
+               pr_err("%s: module %d is not part of the pmic\n",
+                      DRIVER_NAME, mod_no);
+               return -EINVAL;
+       }
        twl = &twl_modules[sid];
 
        mutex_lock(&twl->xfer_lock);
@@ -663,7 +669,8 @@ add_regulator(int num, struct regulator_init_data *pdata,
  */
 
 static int
-add_children(struct twl4030_platform_data *pdata, unsigned long features)
+add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
+               unsigned long features)
 {
        struct device   *child;
        unsigned sub_chip_id;
@@ -671,7 +678,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
        if (twl_has_gpio() && pdata->gpio) {
                child = add_child(SUB_CHIP_ID1, "twl4030_gpio",
                                pdata->gpio, sizeof(*pdata->gpio),
-                               false, pdata->irq_base + GPIO_INTR_OFFSET, 0);
+                               false, irq_base + GPIO_INTR_OFFSET, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
@@ -679,7 +686,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
        if (twl_has_keypad() && pdata->keypad) {
                child = add_child(SUB_CHIP_ID2, "twl4030_keypad",
                                pdata->keypad, sizeof(*pdata->keypad),
-                               true, pdata->irq_base + KEYPAD_INTR_OFFSET, 0);
+                               true, irq_base + KEYPAD_INTR_OFFSET, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
@@ -687,7 +694,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
        if (twl_has_madc() && pdata->madc) {
                child = add_child(2, "twl4030_madc",
                                pdata->madc, sizeof(*pdata->madc),
-                               true, pdata->irq_base + MADC_INTR_OFFSET, 0);
+                               true, irq_base + MADC_INTR_OFFSET, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
@@ -703,7 +710,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                sub_chip_id = twl_map[TWL_MODULE_RTC].sid;
                child = add_child(sub_chip_id, "twl_rtc",
                                NULL, 0,
-                               true, pdata->irq_base + RTC_INTR_OFFSET, 0);
+                               true, irq_base + RTC_INTR_OFFSET, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
@@ -756,8 +763,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                                pdata->usb, sizeof(*pdata->usb),
                                true,
                                /* irq0 = USB_PRES, irq1 = USB */
-                               pdata->irq_base + USB_PRES_INTR_OFFSET,
-                               pdata->irq_base + USB_INTR_OFFSET);
+                               irq_base + USB_PRES_INTR_OFFSET,
+                               irq_base + USB_INTR_OFFSET);
 
                if (IS_ERR(child))
                        return PTR_ERR(child);
@@ -805,8 +812,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                        pdata->usb, sizeof(*pdata->usb),
                        true,
                        /* irq1 = VBUS_PRES, irq0 = USB ID */
-                       pdata->irq_base + USBOTG_INTR_OFFSET,
-                       pdata->irq_base + USB_PRES_INTR_OFFSET);
+                       irq_base + USBOTG_INTR_OFFSET,
+                       irq_base + USB_PRES_INTR_OFFSET);
 
                if (IS_ERR(child))
                        return PTR_ERR(child);
@@ -833,7 +840,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 
        if (twl_has_pwrbutton() && twl_class_is_4030()) {
                child = add_child(1, "twl4030_pwrbutton",
-                               NULL, 0, true, pdata->irq_base + 8 + 0, 0);
+                               NULL, 0, true, irq_base + 8 + 0, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
@@ -847,15 +854,6 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                        return PTR_ERR(child);
        }
 
-       if (twl_has_codec() && pdata->audio && twl_class_is_6030()) {
-               sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
-               child = add_child(sub_chip_id, "twl6040",
-                               pdata->audio, sizeof(*pdata->audio),
-                               false, 0, 0);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-       }
-
        /* twl4030 regulators */
        if (twl_has_regulator() && twl_class_is_4030()) {
                child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1,
@@ -1092,8 +1090,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                child = add_child(3, "twl4030_bci",
                                pdata->bci, sizeof(*pdata->bci), false,
                                /* irq0 = CHG_PRES, irq1 = BCI */
-                               pdata->irq_base + BCI_PRES_INTR_OFFSET,
-                               pdata->irq_base + BCI_INTR_OFFSET);
+                               irq_base + BCI_PRES_INTR_OFFSET,
+                               irq_base + BCI_INTR_OFFSET);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
@@ -1193,26 +1191,24 @@ static void clocks_init(struct device *dev,
 
 /*----------------------------------------------------------------------*/
 
-int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
-int twl4030_exit_irq(void);
-int twl4030_init_chip_irq(const char *chip);
-int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
-int twl6030_exit_irq(void);
 
 static int twl_remove(struct i2c_client *client)
 {
-       unsigned i;
+       unsigned i, num_slaves;
        int status;
 
-       if (twl_class_is_4030())
+       if (twl_class_is_4030()) {
                status = twl4030_exit_irq();
-       else
+               num_slaves = TWL_NUM_SLAVES;
+       } else {
                status = twl6030_exit_irq();
+               num_slaves = TWL_NUM_SLAVES - 1;
+       }
 
        if (status < 0)
                return status;
 
-       for (i = 0; i < TWL_NUM_SLAVES; i++) {
+       for (i = 0; i < num_slaves; i++) {
                struct twl_client       *twl = &twl_modules[i];
 
                if (twl->client && twl->client != client)
@@ -1223,20 +1219,15 @@ static int twl_remove(struct i2c_client *client)
        return 0;
 }
 
-/* NOTE:  this driver only handles a single twl4030/tps659x0 chip */
+/* NOTE: This driver only handles a single twl4030/tps659x0 chip */
 static int __devinit
 twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
-       int                             status;
-       unsigned                        i;
        struct twl4030_platform_data    *pdata = client->dev.platform_data;
        struct device_node              *node = client->dev.of_node;
-       u8 temp;
-       int ret = 0;
-       int nr_irqs = TWL4030_NR_IRQS;
-
-       if ((id->driver_data) & TWL6030_CLASS)
-               nr_irqs = TWL6030_NR_IRQS;
+       int                             irq_base = 0;
+       int                             status;
+       unsigned                        i, num_slaves;
 
        if (node && !pdata) {
                /*
@@ -1255,17 +1246,6 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
                return -EINVAL;
        }
 
-       status = irq_alloc_descs(-1, pdata->irq_base, nr_irqs, 0);
-       if (IS_ERR_VALUE(status)) {
-               dev_err(&client->dev, "Fail to allocate IRQ descs\n");
-               return status;
-       }
-
-       pdata->irq_base = status;
-       pdata->irq_end = pdata->irq_base + nr_irqs;
-       irq_domain_add_legacy(node, nr_irqs, pdata->irq_base, 0,
-                             &irq_domain_simple_ops, NULL);
-
        if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
                dev_dbg(&client->dev, "can't talk I2C?\n");
                return -EIO;
@@ -1276,13 +1256,23 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
                return -EBUSY;
        }
 
-       for (i = 0; i < TWL_NUM_SLAVES; i++) {
-               struct twl_client       *twl = &twl_modules[i];
+       if ((id->driver_data) & TWL6030_CLASS) {
+               twl_id = TWL6030_CLASS_ID;
+               twl_map = &twl6030_map[0];
+               num_slaves = TWL_NUM_SLAVES - 1;
+       } else {
+               twl_id = TWL4030_CLASS_ID;
+               twl_map = &twl4030_map[0];
+               num_slaves = TWL_NUM_SLAVES;
+       }
+
+       for (i = 0; i < num_slaves; i++) {
+               struct twl_client *twl = &twl_modules[i];
 
                twl->address = client->addr + i;
-               if (i == 0)
+               if (i == 0) {
                        twl->client = client;
-               else {
+               else {
                        twl->client = i2c_new_dummy(client->adapter,
                                        twl->address);
                        if (!twl->client) {
@@ -1294,22 +1284,16 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
                }
                mutex_init(&twl->xfer_lock);
        }
+
        inuse = true;
-       if ((id->driver_data) & TWL6030_CLASS) {
-               twl_id = TWL6030_CLASS_ID;
-               twl_map = &twl6030_map[0];
-       } else {
-               twl_id = TWL4030_CLASS_ID;
-               twl_map = &twl4030_map[0];
-       }
 
        /* setup clock framework */
        clocks_init(&client->dev, pdata->clock);
 
        /* read TWL IDCODE Register */
        if (twl_id == TWL4030_CLASS_ID) {
-               ret = twl_read_idcode_register();
-               WARN(ret < 0, "Error: reading twl_idcode register value\n");
+               status = twl_read_idcode_register();
+               WARN(status < 0, "Error: reading twl_idcode register value\n");
        }
 
        /* load power event scripts */
@@ -1317,31 +1301,31 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
                twl4030_power_init(pdata->power);
 
        /* Maybe init the T2 Interrupt subsystem */
-       if (client->irq
-                       && pdata->irq_base
-                       && pdata->irq_end > pdata->irq_base) {
+       if (client->irq) {
                if (twl_class_is_4030()) {
                        twl4030_init_chip_irq(id->name);
-                       status = twl4030_init_irq(client->irq, pdata->irq_base,
-                       pdata->irq_end);
+                       irq_base = twl4030_init_irq(&client->dev, client->irq);
                } else {
-                       status = twl6030_init_irq(client->irq, pdata->irq_base,
-                       pdata->irq_end);
+                       irq_base = twl6030_init_irq(&client->dev, client->irq);
                }
 
-               if (status < 0)
+               if (irq_base < 0) {
+                       status = irq_base;
                        goto fail;
+               }
        }
 
-       /* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
+       /*
+        * Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
         * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
         * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
         */
-
        if (twl_class_is_4030()) {
+               u8 temp;
+
                twl_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1);
                temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
-               I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
+                       I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
                twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
        }
 
@@ -1349,11 +1333,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
        if (node)
                status = of_platform_populate(node, NULL, NULL, &client->dev);
        if (status)
-               status = add_children(pdata, id->driver_data);
+               status = add_children(pdata, irq_base, id->driver_data);
 
 fail:
        if (status < 0)
                twl_remove(client);
+
        return status;
 }
 
index 8c50a556e9866067eab7ec15c60d5e8736258fe6..6ff99dce714f1665e7021b5c266e68cb8e857851 100644 (file)
@@ -1,9 +1,9 @@
 #ifndef __TWL_CORE_H__
 #define __TWL_CORE_H__
 
-extern int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
+extern int twl6030_init_irq(struct device *dev, int irq_num);
 extern int twl6030_exit_irq(void);
-extern int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
+extern int twl4030_init_irq(struct device *dev, int irq_num);
 extern int twl4030_exit_irq(void);
 extern int twl4030_init_chip_irq(const char *chip);
 
index b69bb517b102a4595b76342afeb58e0c9b3270c2..5d656e8143583634196061e709dcd1944d0b1121 100644 (file)
  */
 
 #include <linux/init.h>
+#include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
-
+#include <linux/of.h>
+#include <linux/irqdomain.h>
 #include <linux/i2c/twl.h>
 
 #include "twl-core.h"
  *     base + 8  .. base + 15  SIH for PWR_INT
  *     base + 16 .. base + 33  SIH for GPIO
  */
+#define TWL4030_CORE_NR_IRQS   8
+#define TWL4030_PWR_NR_IRQS    8
 
 /* PIH register offsets */
 #define REG_PIH_ISR_P1                 0x01
 #define REG_PIH_ISR_P2                 0x02
 #define REG_PIH_SIR                    0x03    /* for testing */
 
-
 /* Linux could (eventually) use either IRQ line */
 static int irq_line;
 
@@ -111,7 +114,8 @@ static int nr_sih_modules;
 #define TWL4030_MODULE_INT_PWR         TWL4030_MODULE_INT
 
 
-/* Order in this table matches order in PIH_ISR.  That is,
+/*
+ * Order in this table matches order in PIH_ISR.  That is,
  * BIT(n) in PIH_ISR is sih_modules[n].
  */
 /* sih_modules_twl4030 is used both in twl4030 and twl5030 */
@@ -288,7 +292,6 @@ static unsigned twl4030_irq_base;
  */
 static irqreturn_t handle_twl4030_pih(int irq, void *devid)
 {
-       int             module_irq;
        irqreturn_t     ret;
        u8              pih_isr;
 
@@ -299,16 +302,18 @@ static irqreturn_t handle_twl4030_pih(int irq, void *devid)
                return IRQ_NONE;
        }
 
-       /* these handlers deal with the relevant SIH irq status */
-       for (module_irq = twl4030_irq_base;
-                       pih_isr;
-                       pih_isr >>= 1, module_irq++) {
-               if (pih_isr & 0x1)
-                       handle_nested_irq(module_irq);
+       while (pih_isr) {
+               unsigned long   pending = __ffs(pih_isr);
+               unsigned int    irq;
+
+               pih_isr &= ~BIT(pending);
+               irq = pending + twl4030_irq_base;
+               handle_nested_irq(irq);
        }
 
        return IRQ_HANDLED;
 }
+
 /*----------------------------------------------------------------------*/
 
 /*
@@ -337,7 +342,6 @@ static int twl4030_init_sih_modules(unsigned line)
        memset(buf, 0xff, sizeof buf);
        sih = sih_modules;
        for (i = 0; i < nr_sih_modules; i++, sih++) {
-
                /* skip USB -- it's funky */
                if (!sih->bytes_ixr)
                        continue;
@@ -352,7 +356,8 @@ static int twl4030_init_sih_modules(unsigned line)
                        pr_err("twl4030: err %d initializing %s %s\n",
                                        status, sih->name, "IMR");
 
-               /* Maybe disable "exclusive" mode; buffer second pending irq;
+               /*
+                * Maybe disable "exclusive" mode; buffer second pending irq;
                 * set Clear-On-Read (COR) bit.
                 *
                 * NOTE that sometimes COR polarity is documented as being
@@ -382,7 +387,8 @@ static int twl4030_init_sih_modules(unsigned line)
                if (sih->irq_lines <= line)
                        continue;
 
-               /* Clear pending interrupt status.  Either the read was
+               /*
+                * Clear pending interrupt status.  Either the read was
                 * enough, or we need to write those bits.  Repeat, in
                 * case an IRQ is pending (PENDDIS=0) ... that's not
                 * uncommon with PWR_INT.PWRON.
@@ -398,7 +404,8 @@ static int twl4030_init_sih_modules(unsigned line)
                                status = twl_i2c_write(sih->module, buf,
                                        sih->mask[line].isr_offset,
                                        sih->bytes_ixr);
-                       /* else COR=1 means read sufficed.
+                       /*
+                        * else COR=1 means read sufficed.
                         * (for most SIH modules...)
                         */
                }
@@ -410,7 +417,8 @@ static int twl4030_init_sih_modules(unsigned line)
 static inline void activate_irq(int irq)
 {
 #ifdef CONFIG_ARM
-       /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
+       /*
+        * 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);
@@ -620,33 +628,24 @@ static irqreturn_t handle_twl4030_sih(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static unsigned twl4030_irq_next;
-
-/* returns the first IRQ used by this SIH bank,
- * or negative errno
- */
-int twl4030_sih_setup(int module)
+/* returns the first IRQ used by this SIH bank, or negative errno */
+int twl4030_sih_setup(struct device *dev, int module, int irq_base)
 {
        int                     sih_mod;
        const struct sih        *sih = NULL;
        struct sih_agent        *agent;
        int                     i, irq;
        int                     status = -EINVAL;
-       unsigned                irq_base = twl4030_irq_next;
 
        /* only support modules with standard clear-on-read for now */
-       for (sih_mod = 0, sih = sih_modules;
-                       sih_mod < nr_sih_modules;
+       for (sih_mod = 0, sih = sih_modules; sih_mod < nr_sih_modules;
                        sih_mod++, sih++) {
                if (sih->module == module && sih->set_cor) {
-                       if (!WARN((irq_base + sih->bits) > NR_IRQS,
-                                       "irq %d for %s too big\n",
-                                       irq_base + sih->bits,
-                                       sih->name))
-                               status = 0;
+                       status = 0;
                        break;
                }
        }
+
        if (status < 0)
                return status;
 
@@ -654,8 +653,6 @@ int twl4030_sih_setup(int module)
        if (!agent)
                return -ENOMEM;
 
-       status = 0;
-
        agent->irq_base = irq_base;
        agent->sih = sih;
        agent->imr = ~0;
@@ -671,8 +668,6 @@ int twl4030_sih_setup(int module)
                activate_irq(irq);
        }
 
-       twl4030_irq_next += i;
-
        /* replace generic PIH handler (handle_simple_irq) */
        irq = sih_mod + twl4030_irq_base;
        irq_set_handler_data(irq, agent);
@@ -680,26 +675,43 @@ int twl4030_sih_setup(int module)
        status = request_threaded_irq(irq, NULL, handle_twl4030_sih, 0,
                                      agent->irq_name ?: sih->name, NULL);
 
-       pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name,
-                       irq, irq_base, twl4030_irq_next - 1);
+       dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", sih->name,
+                       irq, irq_base, irq_base + i - 1);
 
        return status < 0 ? status : irq_base;
 }
 
 /* FIXME need a call to reverse twl4030_sih_setup() ... */
 
-
 /*----------------------------------------------------------------------*/
 
 /* FIXME pass in which interrupt line we'll use ... */
 #define twl_irq_line   0
 
-int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
+int twl4030_init_irq(struct device *dev, int irq_num)
 {
        static struct irq_chip  twl4030_irq_chip;
+       int                     status, i;
+       int                     irq_base, irq_end, nr_irqs;
+       struct                  device_node *node = dev->of_node;
 
-       int                     status;
-       int                     i;
+       /*
+        * TWL core and pwr interrupts must be contiguous because
+        * the hwirqs numbers are defined contiguously from 1 to 15.
+        * Create only one domain for both.
+        */
+       nr_irqs = TWL4030_PWR_NR_IRQS + TWL4030_CORE_NR_IRQS;
+
+       irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+       if (IS_ERR_VALUE(irq_base)) {
+               dev_err(dev, "Fail to allocate IRQ descs\n");
+               return irq_base;
+       }
+
+       irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
+                             &irq_domain_simple_ops, NULL);
+
+       irq_end = irq_base + TWL4030_CORE_NR_IRQS;
 
        /*
         * Mask and clear all TWL4030 interrupts since initially we do
@@ -711,7 +723,8 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
 
        twl4030_irq_base = irq_base;
 
-       /* install an irq handler for each of the SIH modules;
+       /*
+        * Install an irq handler for each of the SIH modules;
         * clone dummy irq_chip since PIH can't *do* anything
         */
        twl4030_irq_chip = dummy_irq_chip;
@@ -725,14 +738,14 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
                irq_set_nested_thread(i, 1);
                activate_irq(i);
        }
-       twl4030_irq_next = i;
-       pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
-                       irq_num, irq_base, twl4030_irq_next - 1);
+
+       dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", "PIH",
+                       irq_num, irq_base, irq_end);
 
        /* ... and the PWR_INT module ... */
-       status = twl4030_sih_setup(TWL4030_MODULE_INT);
+       status = twl4030_sih_setup(dev, TWL4030_MODULE_INT, irq_end);
        if (status < 0) {
-               pr_err("twl4030: sih_setup PWR INT --> %d\n", status);
+               dev_err(dev, "sih_setup PWR INT --> %d\n", status);
                goto fail;
        }
 
@@ -741,11 +754,11 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
                                      IRQF_ONESHOT,
                                      "TWL4030-PIH", NULL);
        if (status < 0) {
-               pr_err("twl4030: could not claim irq%d: %d\n", irq_num, status);
+               dev_err(dev, "could not claim irq%d: %d\n", irq_num, status);
                goto fail_rqirq;
        }
 
-       return status;
+       return irq_base;
 fail_rqirq:
        /* clean up twl4030_sih_setup */
 fail:
index c6b456ad7342755c83e4f31d1106dd9d74cf5ca6..b76902f1e44ae545af5e562765259834f3eed7db 100644 (file)
@@ -39,6 +39,8 @@
 #include <linux/i2c/twl.h>
 #include <linux/platform_device.h>
 #include <linux/suspend.h>
+#include <linux/of.h>
+#include <linux/irqdomain.h>
 
 #include "twl-core.h"
 
@@ -51,8 +53,8 @@
  *
  * We set up IRQs starting at a platform-specified base. An interrupt map table,
  * specifies mapping between interrupt number and the associated module.
- *
  */
+#define TWL6030_NR_IRQS    20
 
 static int twl6030_interrupt_mapping[24] = {
        PWR_INTR_OFFSET,        /* Bit 0        PWRON                   */
@@ -185,8 +187,17 @@ static int twl6030_irq_thread(void *data)
                        }
                local_irq_enable();
                }
-               ret = twl_i2c_write(TWL_MODULE_PIH, sts.bytes,
-                               REG_INT_STS_A, 3); /* clear INT_STS_A */
+
+               /*
+                * NOTE:
+                * Simulation confirms that documentation is wrong w.r.t the
+                * interrupt status clear operation. A single *byte* write to
+                * any one of STS_A to STS_C register results in all three
+                * STS registers being reset. Since it does not matter which
+                * value is written, all three registers are cleared on a
+                * single byte write, so we just use 0x0 to clear.
+                */
+               ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A);
                if (ret)
                        pr_warning("twl6030: I2C error in clearing PIH ISR\n");
 
@@ -227,7 +238,7 @@ static inline void activate_irq(int irq)
 #endif
 }
 
-int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
+static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
 {
        if (on)
                atomic_inc(&twl6030_wakeirqs);
@@ -237,11 +248,6 @@ int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
        return 0;
 }
 
-/*----------------------------------------------------------------------*/
-
-static unsigned twl6030_irq_next;
-
-/*----------------------------------------------------------------------*/
 int twl6030_interrupt_unmask(u8 bit_mask, u8 offset)
 {
        int ret;
@@ -311,7 +317,8 @@ int twl6030_mmc_card_detect_config(void)
                                                                        ret);
                return ret;
        }
-       return 0;
+
+       return twl6030_irq_base + MMCDETECT_INTR_OFFSET;
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
 
@@ -340,29 +347,44 @@ int twl6030_mmc_card_detect(struct device *dev, int slot)
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect);
 
-int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
+int twl6030_init_irq(struct device *dev, int irq_num)
 {
-
-       int     status = 0;
-       int     i;
+       struct                  device_node *node = dev->of_node;
+       int                     nr_irqs, irq_base, irq_end;
        struct task_struct      *task;
-       int ret;
-       u8 mask[4];
+       static struct irq_chip  twl6030_irq_chip;
+       int                     status = 0;
+       int                     i;
+       u8                      mask[4];
+
+       nr_irqs = TWL6030_NR_IRQS;
+
+       irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+       if (IS_ERR_VALUE(irq_base)) {
+               dev_err(dev, "Fail to allocate IRQ descs\n");
+               return irq_base;
+       }
+
+       irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
+                             &irq_domain_simple_ops, NULL);
+
+       irq_end = irq_base + nr_irqs;
 
-       static struct irq_chip  twl6030_irq_chip;
        mask[1] = 0xFF;
        mask[2] = 0xFF;
        mask[3] = 0xFF;
-       ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
-                       REG_INT_MSK_LINE_A, 3); /* MASK ALL INT LINES */
-       ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
-                       REG_INT_MSK_STS_A, 3); /* MASK ALL INT STS */
-       ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
-                       REG_INT_STS_A, 3); /* clear INT_STS_A,B,C */
+
+       /* mask all int lines */
+       twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3);
+       /* mask all int sts */
+       twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3);
+       /* clear INT_STS_A,B,C */
+       twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3);
 
        twl6030_irq_base = irq_base;
 
-       /* install an irq handler for each of the modules;
+       /*
+        * install an irq handler for each of the modules;
         * clone dummy irq_chip since PIH can't *do* anything
         */
        twl6030_irq_chip = dummy_irq_chip;
@@ -377,30 +399,29 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
                activate_irq(i);
        }
 
-       twl6030_irq_next = i;
-       pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
-                       irq_num, irq_base, twl6030_irq_next - 1);
+       dev_info(dev, "PIH (irq %d) chaining IRQs %d..%d\n",
+                       irq_num, irq_base, irq_end);
 
        /* install an irq handler to demultiplex the TWL6030 interrupt */
        init_completion(&irq_event);
 
-       status = request_irq(irq_num, handle_twl6030_pih, 0,
-                               "TWL6030-PIH", &irq_event);
+       status = request_irq(irq_num, handle_twl6030_pih, 0, "TWL6030-PIH",
+                            &irq_event);
        if (status < 0) {
-               pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status);
+               dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
                goto fail_irq;
        }
 
        task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");
        if (IS_ERR(task)) {
-               pr_err("twl6030: could not create irq %d thread!\n", irq_num);
+               dev_err(dev, "could not create irq %d thread!\n", irq_num);
                status = PTR_ERR(task);
                goto fail_kthread;
        }
 
        twl_irq = irq_num;
        register_pm_notifier(&twl6030_irq_pm_notifier_block);
-       return status;
+       return irq_base;
 
 fail_kthread:
        free_irq(irq_num, &irq_event);
@@ -408,6 +429,7 @@ fail_kthread:
 fail_irq:
        for (i = irq_base; i < irq_end; i++)
                irq_set_chip_and_handler(i, NULL, NULL);
+
        return status;
 }
 
index 745c8794566426ad6de06b465c38744d5851ec66..4bceee98f0a4f848a417217f87dbb31bc8d7594f 100644 (file)
@@ -89,7 +89,7 @@ static const struct spi_device_id wm831x_spi_ids[] = {
        { "wm8326", WM8326 },
        { },
 };
-MODULE_DEVICE_TABLE(spi, wm831x_spi_id);
+MODULE_DEVICE_TABLE(spi, wm831x_spi_ids);
 
 static struct spi_driver wm831x_spi_driver = {
        .driver = {
index 237764ae5f9bdb8deaa5a276e4cd902dcfa065a5..1189a17f0f25f6362b5d97c2ff65e8d7cd685c5f 100644 (file)
@@ -271,8 +271,7 @@ static int wm8400_init(struct wm8400 *wm8400,
                return -EIO;
        }
        if (i != reg_data[WM8400_RESET_ID].default_val) {
-               dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n",
-                       reg);
+               dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n", i);
                return -ENODEV;
        }
 
index 98733d408feec58f719da3842a7b13387fc42db8..9d7ca1e978fad30775d1de8b6913333a137118c6 100644 (file)
@@ -639,7 +639,7 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq)
        }
 
        pm_runtime_enable(wm8994->dev);
-       pm_runtime_resume(wm8994->dev);
+       pm_runtime_idle(wm8994->dev);
 
        return 0;
 
index 7605b60954539fa14b9203e5f6b3343475676390..bfd25af6ecb106e75eddb4cdc0afad561238506f 100644 (file)
@@ -20,7 +20,6 @@
 #include "wm8994.h"
 
 static struct reg_default wm1811_defaults[] = {
-       { 0x0000, 0x1811 },    /* R0    - Software Reset */
        { 0x0001, 0x0000 },    /* R1    - Power Management (1) */
        { 0x0002, 0x6000 },    /* R2    - Power Management (2) */
        { 0x0003, 0x0000 },    /* R3    - Power Management (3) */
@@ -61,7 +60,7 @@ static struct reg_default wm1811_defaults[] = {
        { 0x0036, 0x0000 },    /* R54   - Speaker Mixer */
        { 0x0037, 0x0000 },    /* R55   - Additional Control */
        { 0x0038, 0x0000 },    /* R56   - AntiPOP (1) */
-       { 0x0039, 0x0180 },    /* R57   - AntiPOP (2) */
+       { 0x0039, 0x0000 },    /* R57   - AntiPOP (2) */
        { 0x003B, 0x000D },    /* R59   - LDO 1 */
        { 0x003C, 0x0003 },    /* R60   - LDO 2 */
        { 0x003D, 0x0039 },    /* R61   - MICBIAS1 */
@@ -69,16 +68,12 @@ static struct reg_default wm1811_defaults[] = {
        { 0x004C, 0x1F25 },    /* R76   - Charge Pump (1) */
        { 0x004D, 0xAB19 },    /* R77   - Charge Pump (2) */
        { 0x0051, 0x0004 },    /* R81   - Class W (1) */
-       { 0x0054, 0x0000 },    /* R84   - DC Servo (1) */
        { 0x0055, 0x054A },    /* R85   - DC Servo (2) */
-       { 0x0058, 0x0000 },    /* R88   - DC Servo Readback */
        { 0x0059, 0x0000 },    /* R89   - DC Servo (4) */
        { 0x0060, 0x0000 },    /* R96   - Analogue HP (1) */
        { 0x00C5, 0x0000 },    /* R197  - Class D Test (5) */
        { 0x00D0, 0x7600 },    /* R208  - Mic Detect 1 */
        { 0x00D1, 0x007F },    /* R209  - Mic Detect 2 */
-       { 0x00D2, 0x0000 },    /* R210  - Mic Detect 3 */
-       { 0x0100, 0x0100 },    /* R256  - Chip Revision */
        { 0x0101, 0x8004 },    /* R257  - Control Interface */
        { 0x0200, 0x0000 },    /* R512  - AIF1 Clocking (1) */
        { 0x0201, 0x0000 },    /* R513  - AIF1 Clocking (2) */
@@ -88,7 +83,6 @@ static struct reg_default wm1811_defaults[] = {
        { 0x0209, 0x0000 },    /* R521  - Clocking (2) */
        { 0x0210, 0x0083 },    /* R528  - AIF1 Rate */
        { 0x0211, 0x0083 },    /* R529  - AIF2 Rate */
-       { 0x0212, 0x0000 },    /* R530  - Rate Status */
        { 0x0220, 0x0000 },    /* R544  - FLL1 Control (1) */
        { 0x0221, 0x0000 },    /* R545  - FLL1 Control (2) */
        { 0x0222, 0x0000 },    /* R546  - FLL1 Control (3) */
@@ -218,8 +212,6 @@ static struct reg_default wm1811_defaults[] = {
        { 0x070A, 0xA101 },    /* R1802 - GPIO 11 */
        { 0x0720, 0x0000 },    /* R1824 - Pull Control (1) */
        { 0x0721, 0x0156 },    /* R1825 - Pull Control (2) */
-       { 0x0730, 0x0000 },    /* R1840 - Interrupt Status 1 */
-       { 0x0731, 0x0000 },    /* R1841 - Interrupt Status 2 */
        { 0x0732, 0x0000 },    /* R1842 - Interrupt Raw Status 2 */
        { 0x0738, 0x07FF },    /* R1848 - Interrupt Status 1 Mask */
        { 0x0739, 0xDFEF },    /* R1849 - Interrupt Status 2 Mask */
@@ -228,7 +220,6 @@ static struct reg_default wm1811_defaults[] = {
 };
 
 static struct reg_default wm8994_defaults[] = {
-       { 0x0000, 0x8994 },    /* R0     - Software Reset */ 
        { 0x0001, 0x0000 },    /* R1     - Power Management (1) */ 
        { 0x0002, 0x6000 },    /* R2     - Power Management (2) */ 
        { 0x0003, 0x0000 },    /* R3     - Power Management (3) */ 
@@ -275,12 +266,9 @@ static struct reg_default wm8994_defaults[] = {
        { 0x003C, 0x0003 },    /* R60    - LDO 2 */ 
        { 0x004C, 0x1F25 },    /* R76    - Charge Pump (1) */ 
        { 0x0051, 0x0004 },    /* R81    - Class W (1) */ 
-       { 0x0054, 0x0000 },    /* R84    - DC Servo (1) */ 
        { 0x0055, 0x054A },    /* R85    - DC Servo (2) */ 
        { 0x0057, 0x0000 },    /* R87    - DC Servo (4) */ 
-       { 0x0058, 0x0000 },    /* R88    - DC Servo Readback */ 
        { 0x0060, 0x0000 },    /* R96    - Analogue HP (1) */ 
-       { 0x0100, 0x0003 },    /* R256   - Chip Revision */ 
        { 0x0101, 0x8004 },    /* R257   - Control Interface */ 
        { 0x0110, 0x0000 },    /* R272   - Write Sequencer Ctrl (1) */ 
        { 0x0111, 0x0000 },    /* R273   - Write Sequencer Ctrl (2) */ 
@@ -292,7 +280,6 @@ static struct reg_default wm8994_defaults[] = {
        { 0x0209, 0x0000 },    /* R521   - Clocking (2) */ 
        { 0x0210, 0x0083 },    /* R528   - AIF1 Rate */ 
        { 0x0211, 0x0083 },    /* R529   - AIF2 Rate */ 
-       { 0x0212, 0x0000 },    /* R530   - Rate Status */ 
        { 0x0220, 0x0000 },    /* R544   - FLL1 Control (1) */ 
        { 0x0221, 0x0000 },    /* R545   - FLL1 Control (2) */ 
        { 0x0222, 0x0000 },    /* R546   - FLL1 Control (3) */ 
@@ -445,9 +432,6 @@ static struct reg_default wm8994_defaults[] = {
        { 0x070A, 0xA101 },    /* R1802  - GPIO 11 */ 
        { 0x0720, 0x0000 },    /* R1824  - Pull Control (1) */ 
        { 0x0721, 0x0156 },    /* R1825  - Pull Control (2) */ 
-       { 0x0730, 0x0000 },    /* R1840  - Interrupt Status 1 */ 
-       { 0x0731, 0x0000 },    /* R1841  - Interrupt Status 2 */ 
-       { 0x0732, 0x0000 },    /* R1842  - Interrupt Raw Status 2 */ 
        { 0x0738, 0x07FF },    /* R1848  - Interrupt Status 1 Mask */ 
        { 0x0739, 0xFFFF },    /* R1849  - Interrupt Status 2 Mask */ 
        { 0x0740, 0x0000 },    /* R1856  - Interrupt Control */ 
@@ -455,7 +439,6 @@ static struct reg_default wm8994_defaults[] = {
 };
 
 static struct reg_default wm8958_defaults[] = {
-       { 0x0000, 0x8958 },    /* R0     - Software Reset */ 
        { 0x0001, 0x0000 },    /* R1     - Power Management (1) */
        { 0x0002, 0x6000 },    /* R2     - Power Management (2) */
        { 0x0003, 0x0000 },    /* R3     - Power Management (3) */
@@ -970,6 +953,7 @@ static bool wm8994_readable_register(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case WM8994_DC_SERVO_READBACK:
+       case WM8994_MICBIAS:
        case WM8994_WRITE_SEQUENCER_CTRL_1:
        case WM8994_WRITE_SEQUENCER_CTRL_2:
        case WM8994_AIF1_ADC2_LEFT_VOLUME:
index f04761e6622dddcc34a3e860b7559ea410a9d113..afee0e8ae714426ad787fbe1be7d372c888e87f0 100644 (file)
@@ -376,6 +376,9 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
        INIT_DELAYED_WORK(&info->calib_work, calibrate_vrtc_work);
        schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
 #endif /* VRTC_CALIBRATION */
+
+       device_init_wakeup(&pdev->dev, 1);
+
        return 0;
 out_rtc:
        free_irq(info->irq, info);
@@ -401,10 +404,34 @@ static int __devexit pm860x_rtc_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_rtc_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+       if (device_may_wakeup(dev))
+               chip->wakeup_flag |= 1 << PM8607_IRQ_RTC;
+       return 0;
+}
+static int pm860x_rtc_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+       if (device_may_wakeup(dev))
+               chip->wakeup_flag &= ~(1 << PM8607_IRQ_RTC);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_rtc_pm_ops, pm860x_rtc_suspend, pm860x_rtc_resume);
+
 static struct platform_driver pm860x_rtc_driver = {
        .driver         = {
                .name   = "88pm860x-rtc",
                .owner  = THIS_MODULE,
+               .pm     = &pm860x_rtc_pm_ops,
        },
        .probe          = pm860x_rtc_probe,
        .remove         = __devexit_p(pm860x_rtc_remove),
index 915943af3f21eed5f78d5fada3c3d42d20e74b6b..f49181c7311390c471b0abc6caa6d8ca6ae4de91 100644 (file)
@@ -67,6 +67,28 @@ static inline int wled_idc(int port)
        return ret;
 }
 
+static int backlight_power_set(struct pm860x_chip *chip, int port,
+               int on)
+{
+       int ret = -EINVAL;
+
+       switch (port) {
+       case PM8606_BACKLIGHT1:
+               ret = on ? pm8606_osc_enable(chip, WLED1_DUTY) :
+                       pm8606_osc_disable(chip, WLED1_DUTY);
+               break;
+       case PM8606_BACKLIGHT2:
+               ret = on ? pm8606_osc_enable(chip, WLED2_DUTY) :
+                       pm8606_osc_disable(chip, WLED2_DUTY);
+               break;
+       case PM8606_BACKLIGHT3:
+               ret = on ? pm8606_osc_enable(chip, WLED3_DUTY) :
+                       pm8606_osc_disable(chip, WLED3_DUTY);
+               break;
+       }
+       return ret;
+}
+
 static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
 {
        struct pm860x_backlight_data *data = bl_get_data(bl);
@@ -79,6 +101,9 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
        else
                value = brightness;
 
+       if (brightness)
+               backlight_power_set(chip, data->port, 1);
+
        ret = pm860x_reg_write(data->i2c, wled_a(data->port), value);
        if (ret < 0)
                goto out;
@@ -115,6 +140,9 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
        if (ret < 0)
                goto out;
 
+       if (brightness == 0)
+               backlight_power_set(chip, data->port, 0);
+
        dev_dbg(chip->dev, "set brightness %d\n", value);
        data->current_brightness = value;
        return 0;
@@ -170,7 +198,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
        struct backlight_device *bl;
        struct resource *res;
        struct backlight_properties props;
-       unsigned char value;
        char name[MFD_NAME_SIZE];
        int ret;
 
@@ -217,26 +244,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, bl);
 
-       /* Enable reference VSYS */
-       ret = pm860x_reg_read(data->i2c, PM8606_VSYS);
-       if (ret < 0)
-               goto out;
-       if ((ret & PM8606_VSYS_EN) == 0) {
-               value = ret | PM8606_VSYS_EN;
-               ret = pm860x_reg_write(data->i2c, PM8606_VSYS, value);
-               if (ret < 0)
-                       goto out;
-       }
-       /* Enable reference OSC */
-       ret = pm860x_reg_read(data->i2c, PM8606_MISC);
-       if (ret < 0)
-               goto out;
-       if ((ret & PM8606_MISC_OSC_EN) == 0) {
-               value = ret | PM8606_MISC_OSC_EN;
-               ret = pm860x_reg_write(data->i2c, PM8606_MISC, value);
-               if (ret < 0)
-                       goto out;
-       }
        /* read current backlight */
        ret = pm860x_backlight_get_brightness(bl);
        if (ret < 0)
index 7fcab23c59cee7a7fe2fe3a2fdbadff49cb0571b..2463b61003336b0f176b5ed851aa8776a5202697 100644 (file)
@@ -761,7 +761,7 @@ struct twl_regulator_driver_data {
 
 /*----------------------------------------------------------------------*/
 
-int twl4030_sih_setup(int module);
+int twl4030_sih_setup(struct device *dev, int module, int irq_base);
 
 /* Offsets to Power Registers */
 #define TWL4030_VDAC_DEV_GRP           0x3B
index 92be3476c9f5560d8623ac5cae738e1471525f22..84d071ade1d89df5dd9faf6e6de1c7f3a0f88bcf 100644 (file)
@@ -263,6 +263,22 @@ enum {
 #define PM8607_PD_PREBIAS_MASK         (0x1F << 0)
 #define PM8607_PD_PRECHG_MASK          (7 << 5)
 
+#define PM8606_REF_GP_OSC_OFF         0
+#define PM8606_REF_GP_OSC_ON          1
+#define PM8606_REF_GP_OSC_UNKNOWN     2
+
+/* Clients of reference group and 8MHz oscillator in 88PM8606 */
+enum pm8606_ref_gp_and_osc_clients {
+       REF_GP_NO_CLIENTS       = 0,
+       WLED1_DUTY              = (1<<0), /*PF 0x02.7:0*/
+       WLED2_DUTY              = (1<<1), /*PF 0x04.7:0*/
+       WLED3_DUTY              = (1<<2), /*PF 0x06.7:0*/
+       RGB1_ENABLE             = (1<<3), /*PF 0x07.1*/
+       RGB2_ENABLE             = (1<<4), /*PF 0x07.2*/
+       LDO_VBR_EN              = (1<<5), /*PF 0x12.0*/
+       REF_GP_MAX_CLIENT       = 0xFFFF
+};
+
 /* Interrupt Number in 88PM8607 */
 enum {
        PM8607_IRQ_ONKEY,
@@ -298,6 +314,7 @@ enum {
 struct pm860x_chip {
        struct device           *dev;
        struct mutex            irq_lock;
+       struct mutex            osc_lock;
        struct i2c_client       *client;
        struct i2c_client       *companion;     /* companion chip client */
        struct regmap           *regmap;
@@ -305,12 +322,15 @@ struct pm860x_chip {
 
        int                     buck3_double;   /* DVC ramp slope double */
        unsigned short          companion_addr;
+       unsigned short          osc_vote;
        int                     id;
        int                     irq_mode;
        int                     irq_base;
        int                     core_irq;
        unsigned char           chip_version;
+       unsigned char           osc_status;
 
+       unsigned int            wakeup_flag;
 };
 
 enum {
@@ -369,6 +389,9 @@ struct pm860x_platform_data {
        int             num_regulators;
 };
 
+extern int pm8606_osc_enable(struct pm860x_chip *, unsigned short);
+extern int pm8606_osc_disable(struct pm860x_chip *, unsigned short);
+
 extern int pm860x_reg_read(struct i2c_client *, int);
 extern int pm860x_reg_write(struct i2c_client *, int, unsigned char);
 extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *);
index e20dd6ead1d09f2dee7d35af32397f40ad92d8f4..5fa697477b71fa6d6fe14fecf3f679bb22851b9a 100644 (file)
@@ -34,13 +34,6 @@ struct device;
 #define AB5500_1_1     0x21
 #define AB5500_2_0     0x24
 
-/* AB8500 CIDs*/
-#define AB8500_CUT1P0  0x10
-#define AB8500_CUT1P1  0x11
-#define AB8500_CUT2P0  0x20
-#define AB8500_CUT3P0  0x30
-#define AB8500_CUT3P3  0x33
-
 /*
  * AB3100, EVENTA1, A2 and A3 event register flags
  * these are catenated into a single 32-bit flag in the code
index 488a8c920a29c30e23ba51134eedf94207205b39..2387c207ea86d5cc2cf5df7e8aa20e90c3ae2301 100644 (file)
@@