Merge tag 'mfd-3.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 25 Feb 2013 04:00:58 +0000 (20:00 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 25 Feb 2013 04:00:58 +0000 (20:00 -0800)
Pull MFS updates from Samuel Ortiz:
 "This is the MFD pull request for the 3.9 merge window.

  No new drivers this time, but a bunch of fairly big cleanups:

   - Roger Quadros worked on a OMAP USBHS and TLL platform data
     consolidation, OMAP5 support and clock management code cleanup.

   - The first step of a major sync for the ab8500 driver from Lee
     Jones.  In particular, the debugfs and the sysct interfaces got
     extended and improved.

   - Peter Ujfalusi sent a nice patchset for cleaning and fixing the
     twl-core driver, with a much needed module id lookup code
     improvement.

   - The regular wm5102 and arizona cleanups and fixes from Mark Brown.

   - Laxman Dewangan extended the palmas APIs in order to implement the
     palmas GPIO and rt drivers.

   - Laxman also added DT support for the tps65090 driver.

   - The Intel SCH and ICH drivers got a couple fixes from Aaron Sierra
     and Darren Hart.

   - Linus Walleij patchset for the ab8500 driver allowed ab8500 and
     ab9540 based devices to switch to the new abx500 pin-ctrl driver.

   - The max8925 now has device tree and irqdomain support thanks to
     Qing Xu.

   - The recently added rtsx driver got a few cleanups and fixes for a
     better card detection code path and now also supports the RTS5227
     chipset, thanks to Wei Wang and Roger Tseng."

* tag 'mfd-3.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (109 commits)
  mfd: lpc_ich: Use devres API to allocate private data
  mfd: lpc_ich: Add Device IDs for Intel Wellsburg PCH
  mfd: lpc_sch: Accomodate partial population of the MFD devices
  mfd: da9052-i2c: Staticize da9052_i2c_fix()
  mfd: syscon: Fix sparse warning
  mfd: twl-core: Fix kernel panic on boot
  mfd: rtsx: Fix issue that booting OS with SD card inserted
  mfd: ab8500: Fix compile error
  mfd: Add missing GENERIC_HARDIRQS dependecies
  Documentation: Add docs for max8925 dt
  mfd: max8925: Add dts
  mfd: max8925: Support dt for backlight
  mfd: max8925: Fix onkey driver irq base
  mfd: max8925: Fix mfd device register failure
  mfd: max8925: Add irqdomain for dt
  mfd: vexpress: Allow vexpress-sysreg to self-initialise
  mfd: rtsx: Support RTS5227
  mfd: rtsx: Implement driving adjustment to device-dependent callbacks
  mfd: vexpress: Add pseudo-GPIO based LEDs
  mfd: ab8500: Rename ab8500 to abx500 for hwmon driver
  ...

68 files changed:
Documentation/devicetree/bindings/mfd/max8925.txt [new file with mode: 0644]
Documentation/devicetree/bindings/power_supply/max8925_batter.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/tps65090.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/backlight/max8925-backlight.txt [new file with mode: 0644]
arch/arm/boot/dts/mmp2-brownstone.dts
arch/arm/boot/dts/mmp2.dtsi
arch/arm/mach-omap2/board-zoom-display.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-palmas.c [new file with mode: 0644]
drivers/input/misc/max8925_onkey.c
drivers/memstick/host/rtsx_pci_ms.c
drivers/mfd/88pm800.c
drivers/mfd/88pm805.c
drivers/mfd/88pm80x.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/ab8500-core.c
drivers/mfd/ab8500-debugfs.c
drivers/mfd/ab8500-gpadc.c
drivers/mfd/ab8500-sysctrl.c
drivers/mfd/abx500-core.c
drivers/mfd/arizona-core.c
drivers/mfd/da9052-i2c.c
drivers/mfd/db8500-prcmu.c
drivers/mfd/lpc_ich.c
drivers/mfd/lpc_sch.c
drivers/mfd/max8925-core.c
drivers/mfd/max8925-i2c.c
drivers/mfd/omap-usb-host.c
drivers/mfd/omap-usb-tll.c
drivers/mfd/palmas.c
drivers/mfd/rtl8411.c
drivers/mfd/rts5209.c
drivers/mfd/rts5227.c [new file with mode: 0644]
drivers/mfd/rts5229.c
drivers/mfd/rtsx_pcr.c
drivers/mfd/rtsx_pcr.h
drivers/mfd/syscon.c
drivers/mfd/tps6507x.c
drivers/mfd/tps65090.c
drivers/mfd/twl-core.c
drivers/mfd/vexpress-sysreg.c
drivers/mfd/wm5102-tables.c
drivers/mfd/wm8994-core.c
drivers/mmc/host/rtsx_pci_sdmmc.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-palmas.c [new file with mode: 0644]
drivers/usb/host/ehci-omap.c
drivers/video/backlight/max8925_bl.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/ux500_wdt.c [new file with mode: 0644]
include/linux/i2c/twl.h
include/linux/mfd/88pm80x.h
include/linux/mfd/abx500.h
include/linux/mfd/abx500/ab8500-sysctrl.h
include/linux/mfd/abx500/ab8500.h
include/linux/mfd/arizona/pdata.h
include/linux/mfd/arizona/registers.h
include/linux/mfd/dbx500-prcmu.h
include/linux/mfd/max8925.h
include/linux/mfd/palmas.h
include/linux/mfd/rtsx_pci.h
include/linux/platform_data/usb-omap.h
include/linux/platform_data/ux500_wdt.h [new file with mode: 0644]
include/linux/vexpress.h

diff --git a/Documentation/devicetree/bindings/mfd/max8925.txt b/Documentation/devicetree/bindings/mfd/max8925.txt
new file mode 100644 (file)
index 0000000..4f0dc66
--- /dev/null
@@ -0,0 +1,64 @@
+* Maxim max8925 Power Management IC
+
+Required parent device properties:
+- compatible : "maxim,max8925"
+- reg : the I2C slave address for the max8925 chip
+- interrupts : IRQ line for the max8925 chip
+- interrupt-controller: describes the max8925 as an interrupt
+  controller (has its own domain)
+- #interrupt-cells : should be 1.
+       - The cell is the max8925 local IRQ number
+
+Optional parent device properties:
+- maxim,tsc-irq: there are 2 IRQ lines for max8925, one is indicated in
+  interrupts property, the other is indicated here.
+
+max8925 consists of a large and varied group of sub-devices:
+
+Device                  Supply Names    Description
+------                  ------------    -----------
+max8925-onkey          :               : On key
+max8925-rtc            :               : RTC
+max8925-regulator      :               : Regulators
+max8925-backlight      :               : Backlight
+max8925-touch          :               : Touchscreen
+max8925-power          :               : Charger
+
+Example:
+
+       pmic: max8925@3c {
+               compatible = "maxim,max8925";
+               reg = <0x3c>;
+               interrupts = <1>;
+               interrupt-parent = <&intcmux4>;
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               maxim,tsc-irq = <0>;
+
+               regulators {
+                       SDV1 {
+                               regulator-min-microvolt = <637500>;
+                               regulator-max-microvolt = <1425000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       LDO1 {
+                               regulator-min-microvolt = <750000>;
+                               regulator-max-microvolt = <3900000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+               };
+               backlight {
+                       maxim,max8925-dual-string = <0>;
+               };
+               charger {
+                       batt-detect = <0>;
+                       topoff-threshold = <1>;
+                       fast-charge = <7>;
+                       no-temp-support = <0>;
+                       no-insert-detect = <0>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/power_supply/max8925_batter.txt b/Documentation/devicetree/bindings/power_supply/max8925_batter.txt
new file mode 100644 (file)
index 0000000..d7e3e0c
--- /dev/null
@@ -0,0 +1,18 @@
+max8925-battery bindings
+~~~~~~~~~~~~~~~~
+
+Optional properties :
+ - batt-detect: whether support battery detect
+ - topoff-threshold: set charging current in topoff mode
+ - fast-charge: set charging current in fast mode
+ - no-temp-support: whether support temperature protection detect
+ - no-insert-detect: whether support insert detect
+
+Example:
+       charger {
+               batt-detect = <0>;
+               topoff-threshold = <1>;
+               fast-charge = <7>;
+               no-temp-support = <0>;
+               no-insert-detect = <0>;
+       };
diff --git a/Documentation/devicetree/bindings/regulator/tps65090.txt b/Documentation/devicetree/bindings/regulator/tps65090.txt
new file mode 100644 (file)
index 0000000..313a60b
--- /dev/null
@@ -0,0 +1,122 @@
+TPS65090 regulators
+
+Required properties:
+- compatible: "ti,tps65090"
+- reg: I2C slave address
+- interrupts: the interrupt outputs of the controller
+- regulators: A node that houses a sub-node for each regulator within the
+  device. Each sub-node is identified using the node's name, with valid
+  values listed below. The content of each sub-node is defined by the
+  standard binding for regulators; see regulator.txt.
+  dcdc[1-3], fet[1-7] and ldo[1-2] respectively.
+- vsys[1-3]-supply: The input supply for DCDC[1-3] respectively.
+- infet[1-7]-supply: The input supply for FET[1-7] respectively.
+- vsys-l[1-2]-supply: The input supply for LDO[1-2] respectively.
+
+Optional properties:
+- ti,enable-ext-control: This is applicable for DCDC1, DCDC2 and DCDC3.
+  If DCDCs are externally controlled then this property should be there.
+- "dcdc-ext-control-gpios: This is applicable for DCDC1, DCDC2 and DCDC3.
+  If DCDCs are externally controlled and if it is from GPIO then GPIO
+  number should be provided. If it is externally controlled and no GPIO
+  entry then driver will just configure this rails as external control
+  and will not provide any enable/disable APIs.
+
+Each regulator is defined using the standard binding for regulators.
+
+Example:
+
+       tps65090@48 {
+               compatible = "ti,tps65090";
+               reg = <0x48>;
+               interrupts = <0 88 0x4>;
+
+               vsys1-supply = <&some_reg>;
+               vsys2-supply = <&some_reg>;
+               vsys3-supply = <&some_reg>;
+               infet1-supply = <&some_reg>;
+               infet2-supply = <&some_reg>;
+               infet3-supply = <&some_reg>;
+               infet4-supply = <&some_reg>;
+               infet5-supply = <&some_reg>;
+               infet6-supply = <&some_reg>;
+               infet7-supply = <&some_reg>;
+               vsys_l1-supply = <&some_reg>;
+               vsys_l2-supply = <&some_reg>;
+
+               regulators {
+                       dcdc1 {
+                               regulator-name = "dcdc1";
+                               regulator-boot-on;
+                               regulator-always-on;
+                               ti,enable-ext-control;
+                               dcdc-ext-control-gpios = <&gpio 10 0>;
+                       };
+
+                       dcdc2 {
+                               regulator-name = "dcdc2";
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       dcdc3 {
+                               regulator-name = "dcdc3";
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       fet1 {
+                               regulator-name = "fet1";
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       fet2 {
+                               regulator-name = "fet2";
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       fet3 {
+                               regulator-name = "fet3";
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       fet4 {
+                               regulator-name = "fet4";
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       fet5 {
+                               regulator-name = "fet5";
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       fet6 {
+                               regulator-name = "fet6";
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       fet7 {
+                               regulator-name = "fet7";
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       ldo1 {
+                               regulator-name = "ldo1";
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       ldo2 {
+                               regulator-name = "ldo2";
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/video/backlight/max8925-backlight.txt b/Documentation/devicetree/bindings/video/backlight/max8925-backlight.txt
new file mode 100644 (file)
index 0000000..b4cffda
--- /dev/null
@@ -0,0 +1,10 @@
+88pm860x-backlight bindings
+
+Optional properties:
+  - maxim,max8925-dual-string: whether support dual string
+
+Example:
+
+       backlights {
+               maxim,max8925-dual-string = <0>;
+       };
index c9b4f27d191e1c61c7099da10910b69d24c34b8d..7f70a39459f649d7051b5423c754e356686762db 100644 (file)
                        };
                        twsi1: i2c@d4011000 {
                                status = "okay";
+                               pmic: max8925@3c {
+                                       compatible = "maxium,max8925";
+                                       reg = <0x3c>;
+                                       interrupts = <1>;
+                                       interrupt-parent = <&intcmux4>;
+                                       interrupt-controller;
+                                       #interrupt-cells = <1>;
+                                       maxim,tsc-irq = <0>;
+
+                                       regulators {
+                                               SDV1 {
+                                                       regulator-min-microvolt = <637500>;
+                                                       regulator-max-microvolt = <1425000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               SDV2 {
+                                                       regulator-min-microvolt = <650000>;
+                                                       regulator-max-microvolt = <2225000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               SDV3 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO1 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO2 {
+                                                       regulator-min-microvolt = <650000>;
+                                                       regulator-max-microvolt = <2250000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO3 {
+                                                       regulator-min-microvolt = <650000>;
+                                                       regulator-max-microvolt = <2250000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO4 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO5 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO6 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO7 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO8 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO9 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO10 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                               };
+                                               LDO11 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO12 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO13 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO14 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO15 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO16 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO17 {
+                                                       regulator-min-microvolt = <650000>;
+                                                       regulator-max-microvolt = <2250000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO18 {
+                                                       regulator-min-microvolt = <650000>;
+                                                       regulator-max-microvolt = <2250000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO19 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                               LDO20 {
+                                                       regulator-min-microvolt = <750000>;
+                                                       regulator-max-microvolt = <3900000>;
+                                                       regulator-boot-on;
+                                                       regulator-always-on;
+                                               };
+                                       };
+                                       backlight {
+                                               maxim,max8925-dual-string = <0>;
+                                       };
+                                       charger {
+                                               batt-detect = <0>;
+                                               topoff-threshold = <1>;
+                                               fast-charge = <7>;
+                                               no-temp-support = <0>;
+                                               no-insert-detect = <0>;
+                                       };
+                               };
                        };
                        rtc: rtc@d4010000 {
                                status = "okay";
index 0514fb41627e1130a52d3c4ed56ff81ea23d68d0..1429ac05b36d45cff8aff69e745e98444c547f88 100644 (file)
@@ -46,7 +46,7 @@
                                mrvl,intc-nr-irqs = <64>;
                        };
 
-                       intcmux4@d4282150 {
+                       intcmux4: interrupt-controller@d4282150 {
                                compatible = "mrvl,mmp2-mux-intc";
                                interrupts = <4>;
                                interrupt-controller;
                                compatible = "mrvl,mmp-twsi";
                                reg = <0xd4011000 0x1000>;
                                interrupts = <7>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
                                mrvl,i2c-fast-mode;
                                status = "disabled";
                        };
index 1c7c834a5b5f5fb819dc56b6c8bc01edfc62f4d8..8cef477d6b006ac81e890e68c9965abecb2d8a97 100644 (file)
@@ -49,13 +49,13 @@ static void zoom_panel_disable_lcd(struct omap_dss_device *dssdev)
 {
 }
 
-/*
- * PWMA/B register offsets (TWL4030_MODULE_PWMA)
- */
+/* Register offsets in TWL4030_MODULE_INTBR */
 #define TWL_INTBR_PMBR1        0xD
 #define TWL_INTBR_GPBR1        0xC
-#define TWL_LED_PWMON  0x0
-#define TWL_LED_PWMOFF 0x1
+
+/* Register offsets in TWL_MODULE_PWM */
+#define TWL_LED_PWMON  0x3
+#define TWL_LED_PWMOFF 0x4
 
 static int zoom_set_bl_intensity(struct omap_dss_device *dssdev, int level)
 {
@@ -93,8 +93,8 @@ static int zoom_set_bl_intensity(struct omap_dss_device *dssdev, int level)
        }
 
        c = ((50 * (100 - level)) / 100) + 1;
-       twl_i2c_write_u8(TWL4030_MODULE_PWM1, 0x7F, TWL_LED_PWMOFF);
-       twl_i2c_write_u8(TWL4030_MODULE_PWM1, c, TWL_LED_PWMON);
+       twl_i2c_write_u8(TWL_MODULE_PWM, 0x7F, TWL_LED_PWMOFF);
+       twl_i2c_write_u8(TWL_MODULE_PWM, c, TWL_LED_PWMON);
 #else
        pr_warn("Backlight not enabled\n");
 #endif
index b89d250f56e747744bfa98cbd92383bf3d63f203..74e17f19cc3386f6a43d857231c0fc2fca351903 100644 (file)
@@ -657,6 +657,13 @@ config GPIO_JANZ_TTL
          This driver provides support for driving the pins in output
          mode only. Input mode is not supported.
 
+config GPIO_PALMAS
+       bool "TI PALMAS series PMICs GPIO"
+       depends on MFD_PALMAS
+       help
+         Select this option to enable GPIO driver for the TI PALMAS
+         series chip family.
+
 config GPIO_TPS6586X
        bool "TPS6586X GPIO"
        depends on MFD_TPS6586X
index 45a388c21d0468f54782492dc014dcdbb0a5df14..6dbcba2e5cacc43c61b7a3a429a939248fc4df22 100644 (file)
@@ -68,6 +68,7 @@ obj-$(CONFIG_GPIO_TC3589X)    += gpio-tc3589x.o
 obj-$(CONFIG_ARCH_TEGRA)       += gpio-tegra.o
 obj-$(CONFIG_GPIO_TIMBERDALE)  += gpio-timberdale.o
 obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o
+obj-$(CONFIG_GPIO_PALMAS)      += gpio-palmas.o
 obj-$(CONFIG_GPIO_TPS6586X)    += gpio-tps6586x.o
 obj-$(CONFIG_GPIO_TPS65910)    += gpio-tps65910.o
 obj-$(CONFIG_GPIO_TPS65912)    += gpio-tps65912.o
diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c
new file mode 100644 (file)
index 0000000..e3a4e56
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * TI Palma series PMIC's GPIO driver.
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * 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/gpio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/palmas.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+struct palmas_gpio {
+       struct gpio_chip gpio_chip;
+       struct palmas *palmas;
+};
+
+static inline struct palmas_gpio *to_palmas_gpio(struct gpio_chip *chip)
+{
+       return container_of(chip, struct palmas_gpio, gpio_chip);
+}
+
+static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+       struct palmas_gpio *pg = to_palmas_gpio(gc);
+       struct palmas *palmas = pg->palmas;
+       unsigned int val;
+       int ret;
+
+       ret = palmas_read(palmas, PALMAS_GPIO_BASE, PALMAS_GPIO_DATA_IN, &val);
+       if (ret < 0) {
+               dev_err(gc->dev, "GPIO_DATA_IN read failed, err = %d\n", ret);
+               return ret;
+       }
+       return !!(val & BIT(offset));
+}
+
+static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset,
+                       int value)
+{
+       struct palmas_gpio *pg = to_palmas_gpio(gc);
+       struct palmas *palmas = pg->palmas;
+       int ret;
+
+       if (value)
+               ret = palmas_write(palmas, PALMAS_GPIO_BASE,
+                               PALMAS_GPIO_SET_DATA_OUT, BIT(offset));
+       else
+               ret = palmas_write(palmas, PALMAS_GPIO_BASE,
+                               PALMAS_GPIO_CLEAR_DATA_OUT, BIT(offset));
+       if (ret < 0)
+               dev_err(gc->dev, "%s write failed, err = %d\n",
+                       (value) ? "GPIO_SET_DATA_OUT" : "GPIO_CLEAR_DATA_OUT",
+                       ret);
+}
+
+static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset,
+                               int value)
+{
+       struct palmas_gpio *pg = to_palmas_gpio(gc);
+       struct palmas *palmas = pg->palmas;
+       int ret;
+
+       /* Set the initial value */
+       palmas_gpio_set(gc, offset, value);
+
+       ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE,
+               PALMAS_GPIO_DATA_DIR, BIT(offset), BIT(offset));
+       if (ret < 0)
+               dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret);
+       return ret;
+}
+
+static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset)
+{
+       struct palmas_gpio *pg = to_palmas_gpio(gc);
+       struct palmas *palmas = pg->palmas;
+       int ret;
+
+       ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE,
+               PALMAS_GPIO_DATA_DIR, BIT(offset), 0);
+       if (ret < 0)
+               dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret);
+       return ret;
+}
+
+static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+       struct palmas_gpio *pg = to_palmas_gpio(gc);
+       struct palmas *palmas = pg->palmas;
+
+       return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset);
+}
+
+static int palmas_gpio_probe(struct platform_device *pdev)
+{
+       struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
+       struct palmas_platform_data *palmas_pdata;
+       struct palmas_gpio *palmas_gpio;
+       int ret;
+
+       palmas_gpio = devm_kzalloc(&pdev->dev,
+                               sizeof(*palmas_gpio), GFP_KERNEL);
+       if (!palmas_gpio) {
+               dev_err(&pdev->dev, "Could not allocate palmas_gpio\n");
+               return -ENOMEM;
+       }
+
+       palmas_gpio->palmas = palmas;
+       palmas_gpio->gpio_chip.owner = THIS_MODULE;
+       palmas_gpio->gpio_chip.label = dev_name(&pdev->dev);
+       palmas_gpio->gpio_chip.ngpio = 8;
+       palmas_gpio->gpio_chip.can_sleep = 1;
+       palmas_gpio->gpio_chip.direction_input = palmas_gpio_input;
+       palmas_gpio->gpio_chip.direction_output = palmas_gpio_output;
+       palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq;
+       palmas_gpio->gpio_chip.set      = palmas_gpio_set;
+       palmas_gpio->gpio_chip.get      = palmas_gpio_get;
+       palmas_gpio->gpio_chip.dev = &pdev->dev;
+#ifdef CONFIG_OF_GPIO
+       palmas_gpio->gpio_chip.of_node = palmas->dev->of_node;
+#endif
+       palmas_pdata = dev_get_platdata(palmas->dev);
+       if (palmas_pdata && palmas_pdata->gpio_base)
+               palmas_gpio->gpio_chip.base = palmas_pdata->gpio_base;
+       else
+               palmas_gpio->gpio_chip.base = -1;
+
+       ret = gpiochip_add(&palmas_gpio->gpio_chip);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, palmas_gpio);
+       return ret;
+}
+
+static int palmas_gpio_remove(struct platform_device *pdev)
+{
+       struct palmas_gpio *palmas_gpio = platform_get_drvdata(pdev);
+
+       return gpiochip_remove(&palmas_gpio->gpio_chip);
+}
+
+static struct platform_driver palmas_gpio_driver = {
+       .driver.name    = "palmas-gpio",
+       .driver.owner   = THIS_MODULE,
+       .probe          = palmas_gpio_probe,
+       .remove         = palmas_gpio_remove,
+};
+
+static int __init palmas_gpio_init(void)
+{
+       return platform_driver_register(&palmas_gpio_driver);
+}
+subsys_initcall(palmas_gpio_init);
+
+static void __exit palmas_gpio_exit(void)
+{
+       platform_driver_unregister(&palmas_gpio_driver);
+}
+module_exit(palmas_gpio_exit);
+
+MODULE_ALIAS("platform:palmas-gpio");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("GPIO driver for TI Palmas series PMICs");
+MODULE_LICENSE("GPL v2");
index 369a39de4ff32100ea8dd9847ceb22e37191caf3..f9179b2585a90e5b80f0715da13dbfefdec1cece 100644 (file)
@@ -100,9 +100,6 @@ static int max8925_onkey_probe(struct platform_device *pdev)
        input->dev.parent = &pdev->dev;
        input_set_capability(input, EV_KEY, KEY_POWER);
 
-       irq[0] += chip->irq_base;
-       irq[1] += chip->irq_base;
-
        error = request_threaded_irq(irq[0], NULL, max8925_onkey_handler,
                                     IRQF_ONESHOT, "onkey-down", info);
        if (error < 0) {
index f5ddb82dadb71cb6d726f48f15782bedfa21016c..64a779c58a74fd9346444c62663817010f5331d3 100644 (file)
@@ -426,6 +426,9 @@ static void rtsx_pci_ms_request(struct memstick_host *msh)
 
        dev_dbg(ms_dev(host), "--> %s\n", __func__);
 
+       if (rtsx_pci_card_exclusive_check(host->pcr, RTSX_MS_CARD))
+               return;
+
        schedule_work(&host->handle_req);
 }
 
@@ -441,6 +444,10 @@ static int rtsx_pci_ms_set_param(struct memstick_host *msh,
        dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n",
                        __func__, param, value);
 
+       err = rtsx_pci_card_exclusive_check(host->pcr, RTSX_MS_CARD);
+       if (err)
+               return err;
+
        switch (param) {
        case MEMSTICK_POWER:
                if (value == MEMSTICK_POWER_ON)
index 391e23e6a6470e26ea68d47bce622280f00bce70..582bda543520dcbde0f6baaae86d5f9b626787f0 100644 (file)
@@ -531,7 +531,7 @@ static int pm800_probe(struct i2c_client *client,
        ret = device_800_init(chip, pdata);
        if (ret) {
                dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
-               goto err_800_init;
+               goto err_subchip_alloc;
        }
 
        ret = pm800_pages_init(chip);
@@ -546,10 +546,8 @@ static int pm800_probe(struct i2c_client *client,
 err_page_init:
        mfd_remove_devices(chip->dev);
        device_irq_exit_800(chip);
-err_800_init:
-       devm_kfree(&client->dev, subchip);
 err_subchip_alloc:
-       pm80x_deinit(client);
+       pm80x_deinit();
 out_init:
        return ret;
 }
@@ -562,9 +560,7 @@ static int pm800_remove(struct i2c_client *client)
        device_irq_exit_800(chip);
 
        pm800_pages_exit(chip);
-       devm_kfree(&client->dev, chip->subchip);
-
-       pm80x_deinit(client);
+       pm80x_deinit();
 
        return 0;
 }
index e671230be2b150fb104c9a30a5f19131020e8239..65d7ac099b2065d1945b936d634d2416a78f26cd 100644 (file)
@@ -257,7 +257,7 @@ static int pm805_probe(struct i2c_client *client,
                pdata->plat_config(chip, pdata);
 
 err_805_init:
-       pm80x_deinit(client);
+       pm80x_deinit();
 out_init:
        return ret;
 }
@@ -269,7 +269,7 @@ static int pm805_remove(struct i2c_client *client)
        mfd_remove_devices(chip->dev);
        device_irq_exit_805(chip);
 
-       pm80x_deinit(client);
+       pm80x_deinit();
 
        return 0;
 }
index 1adb355d86d1a5782c8c3d8bf1513a176c2e8519..f736a46eb8c0e41e3785e76dc0e89d17d1306068 100644 (file)
@@ -48,14 +48,12 @@ int pm80x_init(struct i2c_client *client,
                ret = PTR_ERR(map);
                dev_err(&client->dev, "Failed to allocate register map: %d\n",
                        ret);
-               goto err_regmap_init;
+               return ret;
        }
 
        chip->id = id->driver_data;
-       if (chip->id < CHIP_PM800 || chip->id > CHIP_PM805) {
-               ret = -EINVAL;
-               goto err_chip_id;
-       }
+       if (chip->id < CHIP_PM800 || chip->id > CHIP_PM805)
+               return -EINVAL;
 
        chip->client = client;
        chip->regmap = map;
@@ -82,19 +80,11 @@ int pm80x_init(struct i2c_client *client,
        }
 
        return 0;
-
-err_chip_id:
-       regmap_exit(map);
-err_regmap_init:
-       devm_kfree(&client->dev, chip);
-       return ret;
 }
 EXPORT_SYMBOL_GPL(pm80x_init);
 
-int pm80x_deinit(struct i2c_client *client)
+int pm80x_deinit(void)
 {
-       struct pm80x_chip *chip = i2c_get_clientdata(client);
-
        /*
         * workaround: clear the dependency between pm800 and pm805.
         * would remove it after HW chip fixes the issue.
@@ -103,10 +93,6 @@ int pm80x_deinit(struct i2c_client *client)
                g_pm80x_chip->companion = NULL;
        else
                g_pm80x_chip = NULL;
-
-       regmap_exit(chip->regmap);
-       devm_kfree(&client->dev, chip);
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(pm80x_deinit);
index ff553babf455025c2a5ce303297a15f404d2d5e3..671f5b171c737d78c9659d2afe3a68e02fd3981f 100644 (file)
@@ -65,7 +65,7 @@ config MFD_SM501_GPIO
 
 config MFD_RTSX_PCI
        tristate "Support for Realtek PCI-E card reader"
-       depends on PCI
+       depends on PCI && GENERIC_HARDIRQS
        select MFD_CORE
        help
          This supports for Realtek PCI-Express card reader including rts5209,
@@ -95,7 +95,7 @@ config MFD_DM355EVM_MSP
 
 config MFD_TI_SSP
        tristate "TI Sequencer Serial Port support"
-       depends on ARCH_DAVINCI_TNETV107X
+       depends on ARCH_DAVINCI_TNETV107X && GENERIC_HARDIRQS
        select MFD_CORE
        ---help---
          Say Y here if you want support for the Sequencer Serial Port
@@ -109,6 +109,7 @@ config MFD_TI_AM335X_TSCADC
        select MFD_CORE
        select REGMAP
        select REGMAP_MMIO
+       depends on GENERIC_HARDIRQS
        help
          If you say yes here you get support for Texas Instruments series
          of Touch Screen /ADC chips.
@@ -126,6 +127,7 @@ config HTC_EGPIO
 config HTC_PASIC3
        tristate "HTC PASIC3 LED/DS1WM chip support"
        select MFD_CORE
+       depends on GENERIC_HARDIRQS
        help
          This core driver provides register access for the LED/DS1WM
          chips labeled "AIC2" and "AIC3", found on HTC Blueangel and
@@ -157,6 +159,7 @@ config MFD_LM3533
        depends on I2C
        select MFD_CORE
        select REGMAP_I2C
+       depends on GENERIC_HARDIRQS
        help
          Say yes here to enable support for National Semiconductor / TI
          LM3533 Lighting Power chips.
@@ -171,6 +174,7 @@ config TPS6105X
        select REGULATOR
        select MFD_CORE
        select REGULATOR_FIXED_VOLTAGE
+       depends on GENERIC_HARDIRQS
        help
          This option enables a driver for the TP61050/TPS61052
          high-power "white LED driver". This boost converter is
@@ -193,7 +197,7 @@ config TPS65010
 config TPS6507X
        tristate "TPS6507x Power Management / Touch Screen chips"
        select MFD_CORE
-       depends on I2C
+       depends on I2C && GENERIC_HARDIRQS
        help
          If you say yes here you get support for the TPS6507x series of
          Power Management / Touch Screen chips.  These include voltage
@@ -204,7 +208,7 @@ config TPS6507X
 
 config MFD_TPS65217
        tristate "TPS65217 Power Management / White LED chips"
-       depends on I2C
+       depends on I2C && GENERIC_HARDIRQS
        select MFD_CORE
        select REGMAP_I2C
        help
@@ -234,7 +238,7 @@ config MFD_TPS6586X
 
 config MFD_TPS65910
        bool "TPS65910 Power Management chip"
-       depends on I2C=y && GPIOLIB
+       depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
@@ -251,7 +255,7 @@ config MFD_TPS65912_I2C
        bool "TPS65912 Power Management chip with I2C"
        select MFD_CORE
        select MFD_TPS65912
-       depends on I2C=y && GPIOLIB
+       depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
        help
          If you say yes here you get support for the TPS65912 series of
          PM chips with I2C interface.
@@ -260,7 +264,7 @@ config MFD_TPS65912_SPI
        bool "TPS65912 Power Management chip with SPI"
        select MFD_CORE
        select MFD_TPS65912
-       depends on SPI_MASTER && GPIOLIB
+       depends on SPI_MASTER && GPIOLIB && GENERIC_HARDIRQS
        help
          If you say yes here you get support for the TPS65912 series of
          PM chips with SPI interface.
@@ -330,13 +334,13 @@ config TWL4030_POWER
 
 config MFD_TWL4030_AUDIO
        bool
-       depends on TWL4030_CORE
+       depends on TWL4030_CORE && GENERIC_HARDIRQS
        select MFD_CORE
        default n
 
 config TWL6040_CORE
        bool "Support for TWL6040 audio codec"
-       depends on I2C=y
+       depends on I2C=y && GENERIC_HARDIRQS
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
@@ -405,7 +409,7 @@ config MFD_TMIO
 
 config MFD_T7L66XB
        bool "Support Toshiba T7L66XB"
-       depends on ARM && HAVE_CLK
+       depends on ARM && HAVE_CLK && GENERIC_HARDIRQS
        select MFD_CORE
        select MFD_TMIO
        help
@@ -413,7 +417,7 @@ config MFD_T7L66XB
 
 config MFD_SMSC
        bool "Support for the SMSC ECE1099 series chips"
-       depends on I2C=y
+       depends on I2C=y && GENERIC_HARDIRQS
        select MFD_CORE
        select REGMAP_I2C
        help
@@ -460,7 +464,7 @@ config MFD_DA9052_SPI
        select REGMAP_SPI
        select REGMAP_IRQ
        select PMIC_DA9052
-       depends on SPI_MASTER=y
+       depends on SPI_MASTER=y && GENERIC_HARDIRQS
        help
          Support for the Dialog Semiconductor DA9052 PMIC
          when controlled using SPI. This driver provides common support
@@ -472,7 +476,7 @@ config MFD_DA9052_I2C
        select REGMAP_I2C
        select REGMAP_IRQ
        select PMIC_DA9052
-       depends on I2C=y
+       depends on I2C=y && GENERIC_HARDIRQS
        help
          Support for the Dialog Semiconductor DA9052 PMIC
          when controlled using I2C. This driver provides common support
@@ -485,7 +489,7 @@ config MFD_DA9055
        select REGMAP_IRQ
        select PMIC_DA9055
        select MFD_CORE
-       depends on I2C=y
+       depends on I2C=y && GENERIC_HARDIRQS
        help
          Say yes here for support of Dialog Semiconductor DA9055. This is
          a Power Management IC. This driver provides common support for
@@ -508,7 +512,7 @@ config PMIC_ADP5520
 
 config MFD_LP8788
        bool "Texas Instruments LP8788 Power Management Unit Driver"
-       depends on I2C=y
+       depends on I2C=y && GENERIC_HARDIRQS
        select MFD_CORE
        select REGMAP_I2C
        select IRQ_DOMAIN
@@ -611,7 +615,7 @@ config MFD_ARIZONA_I2C
        select MFD_ARIZONA
        select MFD_CORE
        select REGMAP_I2C
-       depends on I2C
+       depends on I2C && GENERIC_HARDIRQS
        help
          Support for the Wolfson Microelectronics Arizona platform audio SoC
          core functionality controlled via I2C.
@@ -621,7 +625,7 @@ config MFD_ARIZONA_SPI
        select MFD_ARIZONA
        select MFD_CORE
        select REGMAP_SPI
-       depends on SPI_MASTER
+       depends on SPI_MASTER && GENERIC_HARDIRQS
        help
          Support for the Wolfson Microelectronics Arizona platform audio SoC
          core functionality controlled via I2C.
@@ -641,7 +645,7 @@ config MFD_WM5110
 config MFD_WM8400
        bool "Support Wolfson Microelectronics WM8400"
        select MFD_CORE
-       depends on I2C=y
+       depends on I2C=y && GENERIC_HARDIRQS
        select REGMAP_I2C
        help
          Support for the Wolfson Microelecronics WM8400 PMIC and audio
@@ -785,7 +789,7 @@ config MFD_MC13783
 
 config MFD_MC13XXX
        tristate
-       depends on SPI_MASTER || I2C
+       depends on (SPI_MASTER || I2C) && GENERIC_HARDIRQS
        select MFD_CORE
        select MFD_MC13783
        help
@@ -796,7 +800,7 @@ config MFD_MC13XXX
 
 config MFD_MC13XXX_SPI
        tristate "Freescale MC13783 and MC13892 SPI interface"
-       depends on SPI_MASTER
+       depends on SPI_MASTER && GENERIC_HARDIRQS
        select REGMAP_SPI
        select MFD_MC13XXX
        help
@@ -804,7 +808,7 @@ config MFD_MC13XXX_SPI
 
 config MFD_MC13XXX_I2C
        tristate "Freescale MC13892 I2C interface"
-       depends on I2C
+       depends on I2C && GENERIC_HARDIRQS
        select REGMAP_I2C
        select MFD_MC13XXX
        help
@@ -822,7 +826,7 @@ config ABX500_CORE
 
 config AB3100_CORE
        bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions"
-       depends on I2C=y && ABX500_CORE
+       depends on I2C=y && ABX500_CORE && GENERIC_HARDIRQS
        select MFD_CORE
        default y if ARCH_U300
        help
@@ -909,7 +913,7 @@ config MFD_TIMBERDALE
 
 config LPC_SCH
        tristate "Intel SCH LPC"
-       depends on PCI
+       depends on PCI && GENERIC_HARDIRQS
        select MFD_CORE
        help
          LPC bridge function of the Intel SCH provides support for
@@ -917,7 +921,7 @@ config LPC_SCH
 
 config LPC_ICH
        tristate "Intel ICH LPC"
-       depends on PCI
+       depends on PCI && GENERIC_HARDIRQS
        select MFD_CORE
        help
          The LPC bridge function of the Intel ICH provides support for
@@ -928,7 +932,7 @@ config LPC_ICH
 config MFD_RDC321X
        tristate "Support for RDC-R321x southbridge"
        select MFD_CORE
-       depends on PCI
+       depends on PCI && GENERIC_HARDIRQS
        help
          Say yes here if you want to have support for the RDC R-321x SoC
          southbridge which provides access to GPIOs and Watchdog using the
@@ -937,7 +941,7 @@ config MFD_RDC321X
 config MFD_JANZ_CMODIO
        tristate "Support for Janz CMOD-IO PCI MODULbus Carrier Board"
        select MFD_CORE
-       depends on PCI
+       depends on PCI && GENERIC_HARDIRQS
        help
          This is the core driver for the Janz CMOD-IO PCI MODULbus
          carrier board. This device is a PCI to MODULbus bridge which may
@@ -955,7 +959,7 @@ config MFD_JZ4740_ADC
 
 config MFD_VX855
        tristate "Support for VIA VX855/VX875 integrated south bridge"
-       depends on PCI
+       depends on PCI && GENERIC_HARDIRQS
        select MFD_CORE
        help
          Say yes here to enable support for various functions of the
@@ -964,7 +968,7 @@ config MFD_VX855
 
 config MFD_WL1273_CORE
        tristate "Support for TI WL1273 FM radio."
-       depends on I2C
+       depends on I2C && GENERIC_HARDIRQS
        select MFD_CORE
        default n
        help
@@ -1028,7 +1032,7 @@ config MFD_TPS65090
 config MFD_AAT2870_CORE
        bool "Support for the AnalogicTech AAT2870"
        select MFD_CORE
-       depends on I2C=y && GPIOLIB
+       depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
        help
          If you say yes here you get support for the AAT2870.
          This driver provides common support for accessing the device,
@@ -1060,7 +1064,7 @@ config MFD_RC5T583
 
 config MFD_STA2X11
        bool "STA2X11 multi function device support"
-       depends on STA2X11
+       depends on STA2X11 && GENERIC_HARDIRQS
        select MFD_CORE
        select REGMAP_MMIO
 
@@ -1077,7 +1081,7 @@ config MFD_PALMAS
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
-       depends on I2C=y
+       depends on I2C=y && GENERIC_HARDIRQS
        help
          If you say yes here you get support for the Palmas
          series of PMIC chips from Texas Instruments.
@@ -1085,7 +1089,7 @@ config MFD_PALMAS
 config MFD_VIPERBOARD
         tristate "Support for Nano River Technologies Viperboard"
        select MFD_CORE
-       depends on USB
+       depends on USB && GENERIC_HARDIRQS
        default n
        help
          Say yes here if you want support for Nano River Technologies
@@ -1099,7 +1103,7 @@ config MFD_VIPERBOARD
 config MFD_RETU
        tristate "Support for Retu multi-function device"
        select MFD_CORE
-       depends on I2C
+       depends on I2C && GENERIC_HARDIRQS
        select REGMAP_IRQ
        help
          Retu is a multi-function device found on Nokia Internet Tablets
@@ -1110,7 +1114,7 @@ config MFD_AS3711
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
-       depends on I2C=y
+       depends on I2C=y && GENERIC_HARDIRQS
        help
          Support for the AS3711 PMIC from AMS
 
index 8b977f8045ae8f52cbc283838fa1cbfe375809f9..b90409c236645ea3769e963a142b263e7c3eb35f 100644 (file)
@@ -9,7 +9,7 @@ obj-$(CONFIG_MFD_88PM805)       += 88pm805.o 88pm80x.o
 obj-$(CONFIG_MFD_SM501)                += sm501.o
 obj-$(CONFIG_MFD_ASIC3)                += asic3.o tmio_core.o
 
-rtsx_pci-objs                  := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o
+rtsx_pci-objs                  := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o
 obj-$(CONFIG_MFD_RTSX_PCI)     += rtsx_pci.o
 
 obj-$(CONFIG_HTC_EGPIO)                += htc-egpio.o
index 8b5d685ab98089bdbc0afa2b29d33064193d8f85..7c84ced2e01b44e2de6e2991ebae0e7a388ba246 100644 (file)
@@ -320,6 +320,7 @@ static struct abx500_ops ab8500_ops = {
        .mask_and_set_register = ab8500_mask_and_set_register,
        .event_registers_startup_state_get = NULL,
        .startup_irq_enabled = NULL,
+       .dump_all_banks = ab8500_dump_all_banks,
 };
 
 static void ab8500_irq_lock(struct irq_data *data)
@@ -368,16 +369,48 @@ static void ab8500_irq_mask(struct irq_data *data)
        int mask = 1 << (offset % 8);
 
        ab8500->mask[index] |= mask;
+
+       /* The AB8500 GPIOs have two interrupts each (rising & falling). */
+       if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
+               ab8500->mask[index + 2] |= mask;
+       if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R)
+               ab8500->mask[index + 1] |= mask;
+       if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R)
+               /* Here the falling IRQ is one bit lower */
+               ab8500->mask[index] |= (mask << 1);
 }
 
 static void ab8500_irq_unmask(struct irq_data *data)
 {
        struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
+       unsigned int type = irqd_get_trigger_type(data);
        int offset = data->hwirq;
        int index = offset / 8;
        int mask = 1 << (offset % 8);
 
-       ab8500->mask[index] &= ~mask;
+       if (type & IRQ_TYPE_EDGE_RISING)
+               ab8500->mask[index] &= ~mask;
+
+       /* The AB8500 GPIOs have two interrupts each (rising & falling). */
+       if (type & IRQ_TYPE_EDGE_FALLING) {
+               if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
+                       ab8500->mask[index + 2] &= ~mask;
+               else if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R)
+                       ab8500->mask[index + 1] &= ~mask;
+               else if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R)
+                       /* Here the falling IRQ is one bit lower */
+                       ab8500->mask[index] &= ~(mask << 1);
+               else
+                       ab8500->mask[index] &= ~mask;
+       } else {
+               /* Satisfies the case where type is not set. */
+               ab8500->mask[index] &= ~mask;
+       }
+}
+
+static int ab8500_irq_set_type(struct irq_data *data, unsigned int type)
+{
+       return 0;
 }
 
 static struct irq_chip ab8500_irq_chip = {
@@ -387,6 +420,7 @@ static struct irq_chip ab8500_irq_chip = {
        .irq_mask               = ab8500_irq_mask,
        .irq_disable            = ab8500_irq_mask,
        .irq_unmask             = ab8500_irq_unmask,
+       .irq_set_type           = ab8500_irq_set_type,
 };
 
 static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
@@ -411,6 +445,19 @@ static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
                line = (i << 3) + int_bit;
                latch_val &= ~(1 << int_bit);
 
+               /*
+                * This handles the falling edge hwirqs from the GPIO
+                * lines. Route them back to the line registered for the
+                * rising IRQ, as this is merely a flag for the same IRQ
+                * in linux terms.
+                */
+               if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F)
+                       line -= 16;
+               if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F)
+                       line -= 8;
+               if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F)
+                       line += 1;
+
                handle_nested_irq(ab8500->irq_base + line);
        } while (latch_val);
 
@@ -521,6 +568,7 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
                        int virq = ab8500_irq_get_virq(ab8500, line);
 
                        handle_nested_irq(virq);
+                       ab8500_debug_register_interrupt(line);
                        value &= ~(1 << bit);
 
                } while (value);
@@ -929,7 +977,7 @@ static struct resource ab8505_iddet_resources[] = {
 
 static struct resource ab8500_temp_resources[] = {
        {
-               .name  = "AB8500_TEMP_WARM",
+               .name  = "ABX500_TEMP_WARM",
                .start = AB8500_INT_TEMP_WARM,
                .end   = AB8500_INT_TEMP_WARM,
                .flags = IORESOURCE_IRQ,
@@ -1005,8 +1053,8 @@ static struct mfd_cell abx500_common_devs[] = {
                .of_compatible = "stericsson,ab8500-denc",
        },
        {
-               .name = "ab8500-temp",
-               .of_compatible = "stericsson,ab8500-temp",
+               .name = "abx500-temp",
+               .of_compatible = "stericsson,abx500-temp",
                .num_resources = ARRAY_SIZE(ab8500_temp_resources),
                .resources = ab8500_temp_resources,
        },
@@ -1049,7 +1097,7 @@ static struct mfd_cell ab8500_bm_devs[] = {
 
 static struct mfd_cell ab8500_devs[] = {
        {
-               .name = "ab8500-gpio",
+               .name = "pinctrl-ab8500",
                .of_compatible = "stericsson,ab8500-gpio",
        },
        {
@@ -1066,7 +1114,8 @@ static struct mfd_cell ab8500_devs[] = {
 
 static struct mfd_cell ab9540_devs[] = {
        {
-               .name = "ab8500-gpio",
+               .name = "pinctrl-ab9540",
+               .of_compatible = "stericsson,ab9540-gpio",
        },
        {
                .name = "ab9540-usb",
index 5a8e707bc038858a154a1d6a50657336ad5775fc..45fe3c50eb035f5dfff77e30c7cee3f6127413f3 100644 (file)
@@ -4,6 +4,72 @@
  * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson.
  * License Terms: GNU General Public License v2
  */
+/*
+ * AB8500 register access
+ * ======================
+ *
+ * read:
+ * # echo BANK  >  <debugfs>/ab8500/register-bank
+ * # echo ADDR  >  <debugfs>/ab8500/register-address
+ * # cat <debugfs>/ab8500/register-value
+ *
+ * write:
+ * # echo BANK  >  <debugfs>/ab8500/register-bank
+ * # echo ADDR  >  <debugfs>/ab8500/register-address
+ * # echo VALUE >  <debugfs>/ab8500/register-value
+ *
+ * read all registers from a bank:
+ * # echo BANK  >  <debugfs>/ab8500/register-bank
+ * # cat <debugfs>/ab8500/all-bank-register
+ *
+ * BANK   target AB8500 register bank
+ * ADDR   target AB8500 register address
+ * VALUE  decimal or 0x-prefixed hexadecimal
+ *
+ *
+ * User Space notification on AB8500 IRQ
+ * =====================================
+ *
+ * Allows user space entity to be notified when target AB8500 IRQ occurs.
+ * When subscribed, a sysfs entry is created in ab8500.i2c platform device.
+ * One can pool this file to get target IRQ occurence information.
+ *
+ * subscribe to an AB8500 IRQ:
+ * # echo IRQ  >  <debugfs>/ab8500/irq-subscribe
+ *
+ * unsubscribe from an AB8500 IRQ:
+ * # echo IRQ  >  <debugfs>/ab8500/irq-unsubscribe
+ *
+ *
+ * AB8500 register formated read/write access
+ * ==========================================
+ *
+ * Read:  read data, data>>SHIFT, data&=MASK, output data
+ *        [0xABCDEF98] shift=12 mask=0xFFF => 0x00000CDE
+ * Write: read data, data &= ~(MASK<<SHIFT), data |= (VALUE<<SHIFT), write data
+ *        [0xABCDEF98] shift=12 mask=0xFFF value=0x123 => [0xAB123F98]
+ *
+ * Usage:
+ * # echo "CMD [OPTIONS] BANK ADRESS [VALUE]" > $debugfs/ab8500/hwreg
+ *
+ * CMD      read      read access
+ *          write     write access
+ *
+ * BANK     target reg bank
+ * ADDRESS  target reg address
+ * VALUE    (write) value to be updated
+ *
+ * OPTIONS
+ *  -d|-dec            (read) output in decimal
+ *  -h|-hexa           (read) output in 0x-hexa (default)
+ *  -l|-w|-b           32bit (default), 16bit or 8bit reg access
+ *  -m|-mask MASK      0x-hexa mask (default 0xFFFFFFFF)
+ *  -s|-shift SHIFT    bit shift value (read:left, write:right)
+ *  -o|-offset OFFSET  address offset to add to ADDRESS value
+ *
+ * Warning: bit shift operation is applied to bit-mask.
+ * Warning: bit shift direction depends on read or right command.
+ */
 
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
 #include <linux/module.h>
 #include <linux/debugfs.h>
 #include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/kobject.h>
+#include <linux/slab.h>
 
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-gpadc.h>
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/string.h>
+#include <linux/ctype.h>
+#endif
 
 static u32 debug_bank;
 static u32 debug_address;
 
+static int irq_first;
+static int irq_last;
+static u32 *irq_count;
+static int num_irqs;
+
+static struct device_attribute **dev_attr;
+static char **event_name;
+
 /**
  * struct ab8500_reg_range
  * @first: the first address of the range
@@ -42,15 +125,35 @@ struct ab8500_prcmu_ranges {
        const struct ab8500_reg_range *range;
 };
 
+/* hwreg- "mask" and "shift" entries ressources */
+struct hwreg_cfg {
+       u32  bank;      /* target bank */
+       u32  addr;      /* target address */
+       uint fmt;       /* format */
+       uint mask;      /* read/write mask, applied before any bit shift */
+       int  shift;     /* bit shift (read:right shift, write:left shift */
+};
+/* fmt bit #0: 0=hexa, 1=dec */
+#define REG_FMT_DEC(c) ((c)->fmt & 0x1)
+#define REG_FMT_HEX(c) (!REG_FMT_DEC(c))
+
+static struct hwreg_cfg hwreg_cfg = {
+       .addr = 0,                      /* default: invalid phys addr */
+       .fmt = 0,                       /* default: 32bit access, hex output */
+       .mask = 0xFFFFFFFF,     /* default: no mask */
+       .shift = 0,                     /* default: no bit shift */
+};
+
 #define AB8500_NAME_STRING "ab8500"
-#define AB8500_NUM_BANKS 22
+#define AB8500_ADC_NAME_STRING "gpadc"
+#define AB8500_NUM_BANKS 24
 
 #define AB8500_REV_REG 0x80
 
 static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
        [0x0] = {
                .num_ranges = 0,
-               .range = 0,
+               .range = NULL,
        },
        [AB8500_SYS_CTRL1_BLOCK] = {
                .num_ranges = 3,
@@ -215,7 +318,7 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
                },
        },
        [AB8500_CHARGER] = {
-               .num_ranges = 8,
+               .num_ranges = 9,
                .range = (struct ab8500_reg_range[]) {
                        {
                                .first = 0x00,
@@ -249,6 +352,10 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
                                .first = 0xC0,
                                .last = 0xC2,
                        },
+                       {
+                               .first = 0xf5,
+                               .last = 0xf6,
+                       },
                },
        },
        [AB8500_GAS_GAUGE] = {
@@ -268,6 +375,24 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
                        },
                },
        },
+       [AB8500_DEVELOPMENT] = {
+               .num_ranges = 1,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x00,
+                       },
+               },
+       },
+       [AB8500_DEBUG] = {
+               .num_ranges = 1,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x05,
+                               .last = 0x07,
+                       },
+               },
+       },
        [AB8500_AUDIO] = {
                .num_ranges = 1,
                .range = (struct ab8500_reg_range[]) {
@@ -354,15 +479,30 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
        },
 };
 
-static int ab8500_registers_print(struct seq_file *s, void *p)
+static irqreturn_t ab8500_debug_handler(int irq, void *data)
 {
-       struct device *dev = s->private;
-       unsigned int i;
-       u32 bank = debug_bank;
+       char buf[16];
+       struct kobject *kobj = (struct kobject *)data;
+       unsigned int irq_abb = irq - irq_first;
 
-       seq_printf(s, AB8500_NAME_STRING " register values:\n");
+       if (irq_abb < num_irqs)
+               irq_count[irq_abb]++;
+       /*
+        * This makes it possible to use poll for events (POLLPRI | POLLERR)
+        * from userspace on sysfs file named <irq-nr>
+        */
+       sprintf(buf, "%d", irq);
+       sysfs_notify(kobj, NULL, buf);
+
+       return IRQ_HANDLED;
+}
+
+/* Prints to seq_file or log_buf */
+static int ab8500_registers_print(struct device *dev, u32 bank,
+                               struct seq_file *s)
+{
+       unsigned int i;
 
-       seq_printf(s, " bank %u:\n", bank);
        for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
                u32 reg;
 
@@ -379,22 +519,42 @@ static int ab8500_registers_print(struct seq_file *s, void *p)
                                return err;
                        }
 
-                       err = seq_printf(s, "  [%u/0x%02X]: 0x%02X\n", bank,
-                               reg, value);
-                       if (err < 0) {
-                               dev_err(dev, "seq_printf overflow\n");
-                               /* Error is not returned here since
-                                * the output is wanted in any case */
-                               return 0;
+                       if (s) {
+                               err = seq_printf(s, "  [%u/0x%02X]: 0x%02X\n",
+                                       bank, reg, value);
+                               if (err < 0) {
+                                       dev_err(dev,
+                                       "seq_printf overflow bank=%d reg=%d\n",
+                                               bank, reg);
+                                       /* Error is not returned here since
+                                        * the output is wanted in any case */
+                                       return 0;
+                               }
+                       } else {
+                               printk(KERN_INFO" [%u/0x%02X]: 0x%02X\n", bank,
+                                       reg, value);
                        }
                }
        }
        return 0;
 }
 
+static int ab8500_print_bank_registers(struct seq_file *s, void *p)
+{
+       struct device *dev = s->private;
+       u32 bank = debug_bank;
+
+       seq_printf(s, AB8500_NAME_STRING " register values:\n");
+
+       seq_printf(s, " bank %u:\n", bank);
+
+       ab8500_registers_print(dev, bank, s);
+       return 0;
+}
+
 static int ab8500_registers_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, ab8500_registers_print, inode->i_private);
+       return single_open(file, ab8500_print_bank_registers, inode->i_private);
 }
 
 static const struct file_operations ab8500_registers_fops = {
@@ -405,6 +565,64 @@ static const struct file_operations ab8500_registers_fops = {
        .owner = THIS_MODULE,
 };
 
+static int ab8500_print_all_banks(struct seq_file *s, void *p)
+{
+       struct device *dev = s->private;
+       unsigned int i;
+       int err;
+
+       seq_printf(s, AB8500_NAME_STRING " register values:\n");
+
+       for (i = 1; i < AB8500_NUM_BANKS; i++) {
+               err = seq_printf(s, " bank %u:\n", i);
+               if (err < 0)
+                       dev_err(dev, "seq_printf overflow, bank=%d\n", i);
+
+               ab8500_registers_print(dev, i, s);
+       }
+       return 0;
+}
+
+/* Dump registers to kernel log */
+void ab8500_dump_all_banks(struct device *dev)
+{
+       unsigned int i;
+
+       printk(KERN_INFO"ab8500 register values:\n");
+
+       for (i = 1; i < AB8500_NUM_BANKS; i++) {
+               printk(KERN_INFO" bank %u:\n", i);
+               ab8500_registers_print(dev, i, NULL);
+       }
+}
+
+static int ab8500_all_banks_open(struct inode *inode, struct file *file)
+{
+       struct seq_file *s;
+       int err;
+
+       err = single_open(file, ab8500_print_all_banks, inode->i_private);
+       if (!err) {
+               /* Default buf size in seq_read is not enough */
+               s = (struct seq_file *)file->private_data;
+               s->size = (PAGE_SIZE * 2);
+               s->buf = kmalloc(s->size, GFP_KERNEL);
+               if (!s->buf) {
+                       single_release(inode, file);
+                       err = -ENOMEM;
+               }
+       }
+       return err;
+}
+
+static const struct file_operations ab8500_all_banks_fops = {
+       .open = ab8500_all_banks_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
 static int ab8500_bank_print(struct seq_file *s, void *p)
 {
        return seq_printf(s, "%d\n", debug_bank);
@@ -519,6 +737,761 @@ static ssize_t ab8500_val_write(struct file *file,
        return count;
 }
 
+/*
+ * Interrupt status
+ */
+static u32 num_interrupts[AB8500_MAX_NR_IRQS];
+static int num_interrupt_lines;
+
+void ab8500_debug_register_interrupt(int line)
+{
+       if (line < num_interrupt_lines)
+               num_interrupts[line]++;
+}
+
+static int ab8500_interrupts_print(struct seq_file *s, void *p)
+{
+       int line;
+
+       seq_printf(s, "irq:  number of\n");
+
+       for (line = 0; line < num_interrupt_lines; line++)
+               seq_printf(s, "%3i:  %6i\n", line, num_interrupts[line]);
+
+       return 0;
+}
+
+static int ab8500_interrupts_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ab8500_interrupts_print, inode->i_private);
+}
+
+/*
+ * - HWREG DB8500 formated routines
+ */
+static int ab8500_hwreg_print(struct seq_file *s, void *d)
+{
+       struct device *dev = s->private;
+       int ret;
+       u8 regvalue;
+
+       ret = abx500_get_register_interruptible(dev,
+               (u8)hwreg_cfg.bank, (u8)hwreg_cfg.addr, &regvalue);
+       if (ret < 0) {
+               dev_err(dev, "abx500_get_reg fail %d, %d\n",
+                       ret, __LINE__);
+               return -EINVAL;
+       }
+
+       if (hwreg_cfg.shift >= 0)
+               regvalue >>= hwreg_cfg.shift;
+       else
+               regvalue <<= -hwreg_cfg.shift;
+       regvalue &= hwreg_cfg.mask;
+
+       if (REG_FMT_DEC(&hwreg_cfg))
+               seq_printf(s, "%d\n", regvalue);
+       else
+               seq_printf(s, "0x%02X\n", regvalue);
+       return 0;
+}
+
+static int ab8500_hwreg_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ab8500_hwreg_print, inode->i_private);
+}
+
+static int ab8500_gpadc_bat_ctrl_print(struct seq_file *s, void *p)
+{
+       int bat_ctrl_raw;
+       int bat_ctrl_convert;
+       struct ab8500_gpadc *gpadc;
+
+       gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+       bat_ctrl_raw = ab8500_gpadc_read_raw(gpadc, BAT_CTRL);
+       bat_ctrl_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+                       BAT_CTRL, bat_ctrl_raw);
+
+       return seq_printf(s, "%d,0x%X\n",
+                       bat_ctrl_convert, bat_ctrl_raw);
+}
+
+static int ab8500_gpadc_bat_ctrl_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ab8500_gpadc_bat_ctrl_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_bat_ctrl_fops = {
+       .open = ab8500_gpadc_bat_ctrl_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_btemp_ball_print(struct seq_file *s, void *p)
+{
+       int btemp_ball_raw;
+       int btemp_ball_convert;
+       struct ab8500_gpadc *gpadc;
+
+       gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+       btemp_ball_raw = ab8500_gpadc_read_raw(gpadc, BTEMP_BALL);
+       btemp_ball_convert = ab8500_gpadc_ad_to_voltage(gpadc, BTEMP_BALL,
+                       btemp_ball_raw);
+
+       return seq_printf(s,
+                       "%d,0x%X\n", btemp_ball_convert, btemp_ball_raw);
+}
+
+static int ab8500_gpadc_btemp_ball_open(struct inode *inode,
+               struct file *file)
+{
+       return single_open(file, ab8500_gpadc_btemp_ball_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_btemp_ball_fops = {
+       .open = ab8500_gpadc_btemp_ball_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_main_charger_v_print(struct seq_file *s, void *p)
+{
+       int main_charger_v_raw;
+       int main_charger_v_convert;
+       struct ab8500_gpadc *gpadc;
+
+       gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+       main_charger_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_V);
+       main_charger_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+                       MAIN_CHARGER_V, main_charger_v_raw);
+
+       return seq_printf(s, "%d,0x%X\n",
+                       main_charger_v_convert, main_charger_v_raw);
+}
+
+static int ab8500_gpadc_main_charger_v_open(struct inode *inode,
+               struct file *file)
+{
+       return single_open(file, ab8500_gpadc_main_charger_v_print,
+                       inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_main_charger_v_fops = {
+       .open = ab8500_gpadc_main_charger_v_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_acc_detect1_print(struct seq_file *s, void *p)
+{
+       int acc_detect1_raw;
+       int acc_detect1_convert;
+       struct ab8500_gpadc *gpadc;
+
+       gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+       acc_detect1_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT1);
+       acc_detect1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ACC_DETECT1,
+                       acc_detect1_raw);
+
+       return seq_printf(s, "%d,0x%X\n",
+                       acc_detect1_convert, acc_detect1_raw);
+}
+
+static int ab8500_gpadc_acc_detect1_open(struct inode *inode,
+               struct file *file)
+{
+       return single_open(file, ab8500_gpadc_acc_detect1_print,
+                       inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_acc_detect1_fops = {
+       .open = ab8500_gpadc_acc_detect1_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_acc_detect2_print(struct seq_file *s, void *p)
+{
+       int acc_detect2_raw;
+       int acc_detect2_convert;
+       struct ab8500_gpadc *gpadc;
+
+       gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+       acc_detect2_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT2);
+       acc_detect2_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+           ACC_DETECT2, acc_detect2_raw);
+
+       return seq_printf(s, "%d,0x%X\n",
+                       acc_detect2_convert, acc_detect2_raw);
+}
+
+static int ab8500_gpadc_acc_detect2_open(struct inode *inode,
+               struct file *file)
+{
+       return single_open(file, ab8500_gpadc_acc_detect2_print,
+           inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_acc_detect2_fops = {
+       .open = ab8500_gpadc_acc_detect2_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_aux1_print(struct seq_file *s, void *p)
+{
+       int aux1_raw;
+       int aux1_convert;
+       struct ab8500_gpadc *gpadc;
+
+       gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+       aux1_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX1);
+       aux1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX1,
+                       aux1_raw);
+
+       return seq_printf(s, "%d,0x%X\n",
+                       aux1_convert, aux1_raw);
+}
+
+static int ab8500_gpadc_aux1_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ab8500_gpadc_aux1_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_aux1_fops = {
+       .open = ab8500_gpadc_aux1_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_aux2_print(struct seq_file *s, void *p)
+{
+       int aux2_raw;
+       int aux2_convert;
+       struct ab8500_gpadc *gpadc;
+
+       gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+       aux2_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX2);
+       aux2_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX2,
+                       aux2_raw);
+
+       return seq_printf(s, "%d,0x%X\n",
+                       aux2_convert, aux2_raw);
+}
+
+static int ab8500_gpadc_aux2_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ab8500_gpadc_aux2_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_aux2_fops = {
+       .open = ab8500_gpadc_aux2_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_main_bat_v_print(struct seq_file *s, void *p)
+{
+       int main_bat_v_raw;
+       int main_bat_v_convert;
+       struct ab8500_gpadc *gpadc;
+
+       gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+       main_bat_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_BAT_V);
+       main_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, MAIN_BAT_V,
+                       main_bat_v_raw);
+
+       return seq_printf(s, "%d,0x%X\n",
+                       main_bat_v_convert, main_bat_v_raw);
+}
+
+static int ab8500_gpadc_main_bat_v_open(struct inode *inode,
+               struct file *file)
+{
+       return single_open(file, ab8500_gpadc_main_bat_v_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_main_bat_v_fops = {
+       .open = ab8500_gpadc_main_bat_v_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_vbus_v_print(struct seq_file *s, void *p)
+{
+       int vbus_v_raw;
+       int vbus_v_convert;
+       struct ab8500_gpadc *gpadc;
+
+       gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+       vbus_v_raw = ab8500_gpadc_read_raw(gpadc, VBUS_V);
+       vbus_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, VBUS_V,
+                       vbus_v_raw);
+
+       return seq_printf(s, "%d,0x%X\n",
+                       vbus_v_convert, vbus_v_raw);
+}
+
+static int ab8500_gpadc_vbus_v_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ab8500_gpadc_vbus_v_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_vbus_v_fops = {
+       .open = ab8500_gpadc_vbus_v_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_main_charger_c_print(struct seq_file *s, void *p)
+{
+       int main_charger_c_raw;
+       int main_charger_c_convert;
+       struct ab8500_gpadc *gpadc;
+
+       gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+       main_charger_c_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_C);
+       main_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+                       MAIN_CHARGER_C, main_charger_c_raw);
+
+       return seq_printf(s, "%d,0x%X\n",
+                       main_charger_c_convert, main_charger_c_raw);
+}
+
+static int ab8500_gpadc_main_charger_c_open(struct inode *inode,
+               struct file *file)
+{
+       return single_open(file, ab8500_gpadc_main_charger_c_print,
+                       inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_main_charger_c_fops = {
+       .open = ab8500_gpadc_main_charger_c_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_usb_charger_c_print(struct seq_file *s, void *p)
+{
+       int usb_charger_c_raw;
+       int usb_charger_c_convert;
+       struct ab8500_gpadc *gpadc;
+
+       gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+       usb_charger_c_raw = ab8500_gpadc_read_raw(gpadc, USB_CHARGER_C);
+       usb_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+           USB_CHARGER_C, usb_charger_c_raw);
+
+       return seq_printf(s, "%d,0x%X\n",
+                       usb_charger_c_convert, usb_charger_c_raw);
+}
+
+static int ab8500_gpadc_usb_charger_c_open(struct inode *inode,
+               struct file *file)
+{
+       return single_open(file, ab8500_gpadc_usb_charger_c_print,
+           inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_usb_charger_c_fops = {
+       .open = ab8500_gpadc_usb_charger_c_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_bk_bat_v_print(struct seq_file *s, void *p)
+{
+       int bk_bat_v_raw;
+       int bk_bat_v_convert;
+       struct ab8500_gpadc *gpadc;
+
+       gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+       bk_bat_v_raw = ab8500_gpadc_read_raw(gpadc, BK_BAT_V);
+       bk_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+                       BK_BAT_V, bk_bat_v_raw);
+
+       return seq_printf(s, "%d,0x%X\n",
+                       bk_bat_v_convert, bk_bat_v_raw);
+}
+
+static int ab8500_gpadc_bk_bat_v_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ab8500_gpadc_bk_bat_v_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_bk_bat_v_fops = {
+       .open = ab8500_gpadc_bk_bat_v_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_die_temp_print(struct seq_file *s, void *p)
+{
+       int die_temp_raw;
+       int die_temp_convert;
+       struct ab8500_gpadc *gpadc;
+
+       gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+       die_temp_raw = ab8500_gpadc_read_raw(gpadc, DIE_TEMP);
+       die_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, DIE_TEMP,
+                       die_temp_raw);
+
+       return seq_printf(s, "%d,0x%X\n",
+                       die_temp_convert, die_temp_raw);
+}
+
+static int ab8500_gpadc_die_temp_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ab8500_gpadc_die_temp_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_die_temp_fops = {
+       .open = ab8500_gpadc_die_temp_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+/*
+ * return length of an ASCII numerical value, 0 is string is not a
+ * numerical value.
+ * string shall start at value 1st char.
+ * string can be tailed with \0 or space or newline chars only.
+ * value can be decimal or hexadecimal (prefixed 0x or 0X).
+ */
+static int strval_len(char *b)
+{
+       char *s = b;
+       if ((*s == '0') && ((*(s+1) == 'x') || (*(s+1) == 'X'))) {
+               s += 2;
+               for (; *s && (*s != ' ') && (*s != '\n'); s++) {
+                       if (!isxdigit(*s))
+                               return 0;
+               }
+       } else {
+               if (*s == '-')
+                       s++;
+               for (; *s && (*s != ' ') && (*s != '\n'); s++) {
+                       if (!isdigit(*s))
+                               return 0;
+               }
+       }
+       return (int) (s-b);
+}
+
+/*
+ * parse hwreg input data.
+ * update global hwreg_cfg only if input data syntax is ok.
+ */
+static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg,
+               struct device *dev)
+{
+       uint write, val = 0;
+       u8  regvalue;
+       int ret;
+       struct hwreg_cfg loc = {
+               .bank = 0,          /* default: invalid phys addr */
+               .addr = 0,          /* default: invalid phys addr */
+               .fmt = 0,           /* default: 32bit access, hex output */
+               .mask = 0xFFFFFFFF, /* default: no mask */
+               .shift = 0,         /* default: no bit shift */
+       };
+
+       /* read or write ? */
+       if (!strncmp(b, "read ", 5)) {
+               write = 0;
+               b += 5;
+       } else if (!strncmp(b, "write ", 6)) {
+               write = 1;
+               b += 6;
+       } else
+               return -EINVAL;
+
+       /* OPTIONS -l|-w|-b -s -m -o */
+       while ((*b == ' ') || (*b == '-')) {
+               if (*(b-1) != ' ') {
+                       b++;
+                       continue;
+               }
+               if ((!strncmp(b, "-d ", 3)) ||
+                               (!strncmp(b, "-dec ", 5))) {
+                       b += (*(b+2) == ' ') ? 3 : 5;
+                       loc.fmt |= (1<<0);
+               } else if ((!strncmp(b, "-h ", 3)) ||
+                               (!strncmp(b, "-hex ", 5))) {
+                       b += (*(b+2) == ' ') ? 3 : 5;
+                       loc.fmt &= ~(1<<0);
+               } else if ((!strncmp(b, "-m ", 3)) ||
+                               (!strncmp(b, "-mask ", 6))) {
+                       b += (*(b+2) == ' ') ? 3 : 6;
+                       if (strval_len(b) == 0)
+                               return -EINVAL;
+                       loc.mask = simple_strtoul(b, &b, 0);
+               } else if ((!strncmp(b, "-s ", 3)) ||
+                               (!strncmp(b, "-shift ", 7))) {
+                       b += (*(b+2) == ' ') ? 3 : 7;
+                       if (strval_len(b) == 0)
+                               return -EINVAL;
+                       loc.shift = simple_strtol(b, &b, 0);
+               } else {
+                       return -EINVAL;
+               }
+       }
+       /* get arg BANK and ADDRESS */
+       if (strval_len(b) == 0)
+               return -EINVAL;
+       loc.bank = simple_strtoul(b, &b, 0);
+       while (*b == ' ')
+               b++;
+       if (strval_len(b) == 0)
+               return -EINVAL;
+       loc.addr = simple_strtoul(b, &b, 0);
+
+       if (write) {
+               while (*b == ' ')
+                       b++;
+               if (strval_len(b) == 0)
+                       return -EINVAL;
+               val = simple_strtoul(b, &b, 0);
+       }
+
+       /* args are ok, update target cfg (mainly for read) */
+       *cfg = loc;
+
+#ifdef ABB_HWREG_DEBUG
+       pr_warn("HWREG request: %s, %s, addr=0x%08X, mask=0x%X, shift=%d"
+                       "value=0x%X\n", (write) ? "write" : "read",
+                       REG_FMT_DEC(cfg) ? "decimal" : "hexa",
+                       cfg->addr, cfg->mask, cfg->shift, val);
+#endif
+
+       if (!write)
+               return 0;
+
+       ret = abx500_get_register_interruptible(dev,
+                       (u8)cfg->bank, (u8)cfg->addr, &regvalue);
+       if (ret < 0) {
+               dev_err(dev, "abx500_get_reg fail %d, %d\n",
+                       ret, __LINE__);
+               return -EINVAL;
+       }
+
+       if (cfg->shift >= 0) {
+               regvalue &= ~(cfg->mask << (cfg->shift));
+               val = (val & cfg->mask) << (cfg->shift);
+       } else {
+               regvalue &= ~(cfg->mask >> (-cfg->shift));
+               val = (val & cfg->mask) >> (-cfg->shift);
+       }
+       val = val | regvalue;
+
+       ret = abx500_set_register_interruptible(dev,
+                       (u8)cfg->bank, (u8)cfg->addr, (u8)val);
+       if (ret < 0) {
+               pr_err("abx500_set_reg failed %d, %d", ret, __LINE__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static ssize_t ab8500_hwreg_write(struct file *file,
+       const char __user *user_buf, size_t count, loff_t *ppos)
+{
+       struct device *dev = ((struct seq_file *)(file->private_data))->private;
+       char buf[128];
+       int buf_size, ret;
+
+       /* Get userspace string and assure termination */
+       buf_size = min(count, (sizeof(buf)-1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       buf[buf_size] = 0;
+
+       /* get args and process */
+       ret = hwreg_common_write(buf, &hwreg_cfg, dev);
+       return (ret) ? ret : buf_size;
+}
+
+/*
+ * - irq subscribe/unsubscribe stuff
+ */
+static int ab8500_subscribe_unsubscribe_print(struct seq_file *s, void *p)
+{
+       seq_printf(s, "%d\n", irq_first);
+
+       return 0;
+}
+
+static int ab8500_subscribe_unsubscribe_open(struct inode *inode,
+                                            struct file *file)
+{
+       return single_open(file, ab8500_subscribe_unsubscribe_print,
+                          inode->i_private);
+}
+
+/*
+ * Userspace should use poll() on this file. When an event occur
+ * the blocking poll will be released.
+ */
+static ssize_t show_irq(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       unsigned long name;
+       unsigned int irq_index;
+       int err;
+
+       err = strict_strtoul(attr->attr.name, 0, &name);
+       if (err)
+               return err;
+
+       irq_index = name - irq_first;
+       if (irq_index >= num_irqs)
+               return -EINVAL;
+       else
+               return sprintf(buf, "%u\n", irq_count[irq_index]);
+}
+
+static ssize_t ab8500_subscribe_write(struct file *file,
+                                     const char __user *user_buf,
+                                     size_t count, loff_t *ppos)
+{
+       struct device *dev = ((struct seq_file *)(file->private_data))->private;
+       char buf[32];
+       int buf_size;
+       unsigned long user_val;
+       int err;
+       unsigned int irq_index;
+
+       /* Get userspace string and assure termination */
+       buf_size = min(count, (sizeof(buf)-1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       buf[buf_size] = 0;
+
+       err = strict_strtoul(buf, 0, &user_val);
+       if (err)
+               return -EINVAL;
+       if (user_val < irq_first) {
+               dev_err(dev, "debugfs error input < %d\n", irq_first);
+               return -EINVAL;
+       }
+       if (user_val > irq_last) {
+               dev_err(dev, "debugfs error input > %d\n", irq_last);
+               return -EINVAL;
+       }
+
+       irq_index = user_val - irq_first;
+       if (irq_index >= num_irqs)
+               return -EINVAL;
+
+       /*
+        * This will create a sysfs file named <irq-nr> which userspace can
+        * use to select or poll and get the AB8500 events
+        */
+       dev_attr[irq_index] = kmalloc(sizeof(struct device_attribute),
+               GFP_KERNEL);
+       event_name[irq_index] = kmalloc(buf_size, GFP_KERNEL);
+       sprintf(event_name[irq_index], "%lu", user_val);
+       dev_attr[irq_index]->show = show_irq;
+       dev_attr[irq_index]->store = NULL;
+       dev_attr[irq_index]->attr.name = event_name[irq_index];
+       dev_attr[irq_index]->attr.mode = S_IRUGO;
+       err = sysfs_create_file(&dev->kobj, &dev_attr[irq_index]->attr);
+       if (err < 0) {
+               printk(KERN_ERR "sysfs_create_file failed %d\n", err);
+               return err;
+       }
+
+       err = request_threaded_irq(user_val, NULL, ab8500_debug_handler,
+                                  IRQF_SHARED | IRQF_NO_SUSPEND,
+                                  "ab8500-debug", &dev->kobj);
+       if (err < 0) {
+               printk(KERN_ERR "request_threaded_irq failed %d, %lu\n",
+                       err, user_val);
+               sysfs_remove_file(&dev->kobj, &dev_attr[irq_index]->attr);
+               return err;
+       }
+
+       return buf_size;
+}
+
+static ssize_t ab8500_unsubscribe_write(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct device *dev = ((struct seq_file *)(file->private_data))->private;
+       char buf[32];
+       int buf_size;
+       unsigned long user_val;
+       int err;
+       unsigned int irq_index;
+
+       /* Get userspace string and assure termination */
+       buf_size = min(count, (sizeof(buf)-1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       buf[buf_size] = 0;
+
+       err = strict_strtoul(buf, 0, &user_val);
+       if (err)
+               return -EINVAL;
+       if (user_val < irq_first) {
+               dev_err(dev, "debugfs error input < %d\n", irq_first);
+               return -EINVAL;
+       }
+       if (user_val > irq_last) {
+               dev_err(dev, "debugfs error input > %d\n", irq_last);
+               return -EINVAL;
+       }
+
+       irq_index = user_val - irq_first;
+       if (irq_index >= num_irqs)
+               return -EINVAL;
+
+       /* Set irq count to 0 when unsubscribe */
+       irq_count[irq_index] = 0;
+
+       if (dev_attr[irq_index])
+               sysfs_remove_file(&dev->kobj, &dev_attr[irq_index]->attr);
+
+
+       free_irq(user_val, &dev->kobj);
+       kfree(event_name[irq_index]);
+       kfree(dev_attr[irq_index]);
+
+       return buf_size;
+}
+
+/*
+ * - several deubgfs nodes fops
+ */
+
 static const struct file_operations ab8500_bank_fops = {
        .open = ab8500_bank_open,
        .write = ab8500_bank_write,
@@ -546,64 +1519,231 @@ static const struct file_operations ab8500_val_fops = {
        .owner = THIS_MODULE,
 };
 
+static const struct file_operations ab8500_interrupts_fops = {
+       .open = ab8500_interrupts_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static const struct file_operations ab8500_subscribe_fops = {
+       .open = ab8500_subscribe_unsubscribe_open,
+       .write = ab8500_subscribe_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static const struct file_operations ab8500_unsubscribe_fops = {
+       .open = ab8500_subscribe_unsubscribe_open,
+       .write = ab8500_unsubscribe_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static const struct file_operations ab8500_hwreg_fops = {
+       .open = ab8500_hwreg_open,
+       .write = ab8500_hwreg_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
 static struct dentry *ab8500_dir;
-static struct dentry *ab8500_reg_file;
-static struct dentry *ab8500_bank_file;
-static struct dentry *ab8500_address_file;
-static struct dentry *ab8500_val_file;
+static struct dentry *ab8500_gpadc_dir;
 
 static int ab8500_debug_probe(struct platform_device *plf)
 {
+       struct dentry *file;
+       int ret = -ENOMEM;
+       struct ab8500 *ab8500;
        debug_bank = AB8500_MISC;
        debug_address = AB8500_REV_REG & 0x00FF;
 
+       ab8500 = dev_get_drvdata(plf->dev.parent);
+       num_irqs = ab8500->mask_size;
+
+       irq_count = kzalloc(sizeof(*irq_count)*num_irqs, GFP_KERNEL);
+       if (!irq_count)
+               return -ENOMEM;
+
+       dev_attr = kzalloc(sizeof(*dev_attr)*num_irqs,GFP_KERNEL);
+       if (!dev_attr)
+               goto out_freeirq_count;
+
+       event_name = kzalloc(sizeof(*event_name)*num_irqs, GFP_KERNEL);
+       if (!event_name)
+               goto out_freedev_attr;
+
+       irq_first = platform_get_irq_byname(plf, "IRQ_FIRST");
+       if (irq_first < 0) {
+               dev_err(&plf->dev, "First irq not found, err %d\n",
+                               irq_first);
+               ret = irq_first;
+               goto out_freeevent_name;
+       }
+
+       irq_last = platform_get_irq_byname(plf, "IRQ_LAST");
+       if (irq_last < 0) {
+               dev_err(&plf->dev, "Last irq not found, err %d\n",
+                               irq_last);
+               ret = irq_last;
+                goto out_freeevent_name;
+       }
+
        ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
        if (!ab8500_dir)
-               goto exit_no_debugfs;
+               goto err;
+
+       ab8500_gpadc_dir = debugfs_create_dir(AB8500_ADC_NAME_STRING,
+           ab8500_dir);
+       if (!ab8500_gpadc_dir)
+               goto err;
+
+       file = debugfs_create_file("all-bank-registers", S_IRUGO,
+           ab8500_dir, &plf->dev, &ab8500_registers_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("all-banks", S_IRUGO,
+           ab8500_dir, &plf->dev, &ab8500_all_banks_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("register-bank", (S_IRUGO | S_IWUSR),
+           ab8500_dir, &plf->dev, &ab8500_bank_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("register-address", (S_IRUGO | S_IWUSR),
+           ab8500_dir, &plf->dev, &ab8500_address_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("register-value", (S_IRUGO | S_IWUSR),
+           ab8500_dir, &plf->dev, &ab8500_val_fops);
+       if (!file)
+               goto err;
 
-       ab8500_reg_file = debugfs_create_file("all-bank-registers",
-               S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops);
-       if (!ab8500_reg_file)
-               goto exit_destroy_dir;
+       file = debugfs_create_file("irq-subscribe", (S_IRUGO | S_IWUSR),
+           ab8500_dir, &plf->dev, &ab8500_subscribe_fops);
+       if (!file)
+               goto err;
 
-       ab8500_bank_file = debugfs_create_file("register-bank",
-               (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_bank_fops);
-       if (!ab8500_bank_file)
-               goto exit_destroy_reg;
+       if (is_ab8500(ab8500))
+               num_interrupt_lines = AB8500_NR_IRQS;
+       else if (is_ab8505(ab8500))
+               num_interrupt_lines = AB8505_NR_IRQS;
+       else if (is_ab9540(ab8500))
+               num_interrupt_lines = AB9540_NR_IRQS;
 
-       ab8500_address_file = debugfs_create_file("register-address",
-               (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev,
-               &ab8500_address_fops);
-       if (!ab8500_address_file)
-               goto exit_destroy_bank;
+       file = debugfs_create_file("interrupts", (S_IRUGO),
+           ab8500_dir, &plf->dev, &ab8500_interrupts_fops);
+       if (!file)
+               goto err;
 
-       ab8500_val_file = debugfs_create_file("register-value",
-               (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_val_fops);
-       if (!ab8500_val_file)
-               goto exit_destroy_address;
+       file = debugfs_create_file("irq-unsubscribe", (S_IRUGO | S_IWUSR),
+           ab8500_dir, &plf->dev, &ab8500_unsubscribe_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("hwreg", (S_IRUGO | S_IWUSR),
+           ab8500_dir, &plf->dev, &ab8500_hwreg_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("bat_ctrl", (S_IRUGO | S_IWUSR),
+           ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bat_ctrl_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("btemp_ball", (S_IRUGO | S_IWUSR),
+           ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_btemp_ball_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("main_charger_v", (S_IRUGO | S_IWUSR),
+           ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_charger_v_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("acc_detect1", (S_IRUGO | S_IWUSR),
+           ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_acc_detect1_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("acc_detect2", (S_IRUGO | S_IWUSR),
+           ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_acc_detect2_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("adc_aux1", (S_IRUGO | S_IWUSR),
+           ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_aux1_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("adc_aux2", (S_IRUGO | S_IWUSR),
+           ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_aux2_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("main_bat_v", (S_IRUGO | S_IWUSR),
+           ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_bat_v_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("vbus_v", (S_IRUGO | S_IWUSR),
+           ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_vbus_v_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("main_charger_c", (S_IRUGO | S_IWUSR),
+           ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_charger_c_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("usb_charger_c", (S_IRUGO | S_IWUSR),
+           ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_usb_charger_c_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("bk_bat_v", (S_IRUGO | S_IWUSR),
+           ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bk_bat_v_fops);
+       if (!file)
+               goto err;
+
+       file = debugfs_create_file("die_temp", (S_IRUGO | S_IWUSR),
+           ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_die_temp_fops);
+       if (!file)
+               goto err;
 
        return 0;
 
-exit_destroy_address:
-       debugfs_remove(ab8500_address_file);
-exit_destroy_bank:
-       debugfs_remove(ab8500_bank_file);
-exit_destroy_reg:
-       debugfs_remove(ab8500_reg_file);
-exit_destroy_dir:
-       debugfs_remove(ab8500_dir);
-exit_no_debugfs:
+err:
+       if (ab8500_dir)
+               debugfs_remove_recursive(ab8500_dir);
        dev_err(&plf->dev, "failed to create debugfs entries.\n");
-       return -ENOMEM;
+out_freeevent_name:
+       kfree(event_name);
+out_freedev_attr:
+       kfree(dev_attr);
+out_freeirq_count:
+       kfree(irq_count);
+
+       return ret;
 }
 
 static int ab8500_debug_remove(struct platform_device *plf)
 {
-       debugfs_remove(ab8500_val_file);
-       debugfs_remove(ab8500_address_file);
-       debugfs_remove(ab8500_bank_file);
-       debugfs_remove(ab8500_reg_file);
-       debugfs_remove(ab8500_dir);
+       debugfs_remove_recursive(ab8500_dir);
+       kfree(event_name);
+       kfree(dev_attr);
+       kfree(irq_count);
 
        return 0;
 }
index 3fb1f40d6389235e45b35aec393b4bf606a1979c..b1f3561b023f0aaa4939bc469e3c0a40a718d0db 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/delay.h>
+#include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
 #include <linux/completion.h>
 #include <linux/regulator/consumer.h>
 /* This is used to not lose precision when dividing to get gain and offset */
 #define CALIB_SCALE                    1000
 
+/* Time in ms before disabling regulator */
+#define GPADC_AUDOSUSPEND_DELAY                1
+
+#define CONVERSION_TIME                        500 /* ms */
+
 enum cal_channels {
        ADC_INPUT_VMAIN = 0,
        ADC_INPUT_BTEMP,
@@ -102,10 +108,10 @@ struct adc_cal_data {
 
 /**
  * struct ab8500_gpadc - AB8500 GPADC device information
- * @chip_id                    ABB chip id
  * @dev:                       pointer to the struct device
  * @node:                      a list of AB8500 GPADCs, hence prepared for
                                reentrance
+ * @parent:                    pointer to the struct ab8500
  * @ab8500_gpadc_complete:     pointer to the struct completion, to indicate
  *                             the completion of gpadc conversion
  * @ab8500_gpadc_lock:         structure of type mutex
@@ -114,9 +120,9 @@ struct adc_cal_data {
  * @cal_data                   array of ADC calibration data structs
  */
 struct ab8500_gpadc {
-       u8 chip_id;
        struct device *dev;
        struct list_head node;
+       struct ab8500 *parent;
        struct completion ab8500_gpadc_complete;
        struct mutex ab8500_gpadc_lock;
        struct regulator *regu;
@@ -282,8 +288,9 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
                return -ENODEV;
 
        mutex_lock(&gpadc->ab8500_gpadc_lock);
+
        /* Enable VTVout LDO this is required for GPADC */
-       regulator_enable(gpadc->regu);
+       pm_runtime_get_sync(gpadc->dev);
 
        /* Check if ADC is not busy, lock and proceed */
        do {
@@ -332,7 +339,7 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
                        EN_BUF | EN_ICHAR);
                break;
        case BTEMP_BALL:
-               if (gpadc->chip_id >= AB8500_CUT3P0) {
+               if (!is_ab8500_2p0_or_earlier(gpadc->parent)) {
                        /* Turn on btemp pull-up on ABB 3.0 */
                        ret = abx500_mask_and_set_register_interruptible(
                                gpadc->dev,
@@ -344,7 +351,7 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
                  * Delay might be needed for ABB8500 cut 3.0, if not, remove
                  * when hardware will be available
                  */
-                       msleep(1);
+                       usleep_range(1000, 1000);
                        break;
                }
                /* Intentional fallthrough */
@@ -367,7 +374,8 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
                goto out;
        }
        /* wait for completion of conversion */
-       if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete, 2*HZ)) {
+       if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete,
+                                        msecs_to_jiffies(CONVERSION_TIME))) {
                dev_err(gpadc->dev,
                        "timeout: didn't receive GPADC conversion interrupt\n");
                ret = -EINVAL;
@@ -397,8 +405,10 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
                dev_err(gpadc->dev, "gpadc_conversion: disable gpadc failed\n");
                goto out;
        }
-       /* Disable VTVout LDO this is required for GPADC */
-       regulator_disable(gpadc->regu);
+
+       pm_runtime_mark_last_busy(gpadc->dev);
+       pm_runtime_put_autosuspend(gpadc->dev);
+
        mutex_unlock(&gpadc->ab8500_gpadc_lock);
 
        return (high_data << 8) | low_data;
@@ -412,7 +422,9 @@ out:
         */
        (void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
                AB8500_GPADC_CTRL1_REG, DIS_GPADC);
-       regulator_disable(gpadc->regu);
+
+       pm_runtime_put(gpadc->dev);
+
        mutex_unlock(&gpadc->ab8500_gpadc_lock);
        dev_err(gpadc->dev,
                "gpadc_conversion: Failed to AD convert channel %d\n", channel);
@@ -571,6 +583,28 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
                gpadc->cal_data[ADC_INPUT_VBAT].offset);
 }
 
+static int ab8500_gpadc_runtime_suspend(struct device *dev)
+{
+       struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
+
+       regulator_disable(gpadc->regu);
+       return 0;
+}
+
+static int ab8500_gpadc_runtime_resume(struct device *dev)
+{
+       struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
+
+       regulator_enable(gpadc->regu);
+       return 0;
+}
+
+static int ab8500_gpadc_runtime_idle(struct device *dev)
+{
+       pm_runtime_suspend(dev);
+       return 0;
+}
+
 static int ab8500_gpadc_probe(struct platform_device *pdev)
 {
        int ret = 0;
@@ -591,6 +625,7 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
        }
 
        gpadc->dev = &pdev->dev;
+       gpadc->parent = dev_get_drvdata(pdev->dev.parent);
        mutex_init(&gpadc->ab8500_gpadc_lock);
 
        /* Initialize completion used to notify completion of conversion */
@@ -607,14 +642,6 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
                goto fail;
        }
 
-       /* Get Chip ID of the ABB ASIC  */
-       ret = abx500_get_chip_id(gpadc->dev);
-       if (ret < 0) {
-               dev_err(gpadc->dev, "failed to get chip ID\n");
-               goto fail_irq;
-       }
-       gpadc->chip_id = (u8) ret;
-
        /* VTVout LDO used to power up ab8500-GPADC */
        gpadc->regu = regulator_get(&pdev->dev, "vddadc");
        if (IS_ERR(gpadc->regu)) {
@@ -622,6 +649,16 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
                dev_err(gpadc->dev, "failed to get vtvout LDO\n");
                goto fail_irq;
        }
+
+       platform_set_drvdata(pdev, gpadc);
+
+       regulator_enable(gpadc->regu);
+
+       pm_runtime_set_autosuspend_delay(gpadc->dev, GPADC_AUDOSUSPEND_DELAY);
+       pm_runtime_use_autosuspend(gpadc->dev);
+       pm_runtime_set_active(gpadc->dev);
+       pm_runtime_enable(gpadc->dev);
+
        ab8500_gpadc_read_calibration_data(gpadc);
        list_add_tail(&gpadc->node, &ab8500_gpadc_list);
        dev_dbg(gpadc->dev, "probe success\n");
@@ -642,19 +679,34 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
        list_del(&gpadc->node);
        /* remove interrupt  - completion of Sw ADC conversion */
        free_irq(gpadc->irq, gpadc);
-       /* disable VTVout LDO that is being used by GPADC */
-       regulator_put(gpadc->regu);
+
+       pm_runtime_get_sync(gpadc->dev);
+       pm_runtime_disable(gpadc->dev);
+
+       regulator_disable(gpadc->regu);
+
+       pm_runtime_set_suspended(gpadc->dev);
+
+       pm_runtime_put_noidle(gpadc->dev);
+
        kfree(gpadc);
        gpadc = NULL;
        return 0;
 }
 
+static const struct dev_pm_ops ab8500_gpadc_pm_ops = {
+       SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend,
+                          ab8500_gpadc_runtime_resume,
+                          ab8500_gpadc_runtime_idle)
+};
+
 static struct platform_driver ab8500_gpadc_driver = {
        .probe = ab8500_gpadc_probe,
        .remove = ab8500_gpadc_remove,
        .driver = {
                .name = "ab8500-gpadc",
                .owner = THIS_MODULE,
+               .pm = &ab8500_gpadc_pm_ops,
        },
 };
 
index 8a33b2c7eeadf1ec900ae80ce0755ef37d19fbc4..108fd86552f0329df01bd905f4109882e236ba62 100644 (file)
@@ -7,12 +7,73 @@
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/reboot.h>
+#include <linux/signal.h>
+#include <linux/power_supply.h>
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500/ab8500.h>
 #include <linux/mfd/abx500/ab8500-sysctrl.h>
 
 static struct device *sysctrl_dev;
 
+void ab8500_power_off(void)
+{
+       sigset_t old;
+       sigset_t all;
+       static char *pss[] = {"ab8500_ac", "ab8500_usb"};
+       int i;
+       bool charger_present = false;
+       union power_supply_propval val;
+       struct power_supply *psy;
+       int ret;
+
+       /*
+        * If we have a charger connected and we're powering off,
+        * reboot into charge-only mode.
+        */
+
+       for (i = 0; i < ARRAY_SIZE(pss); i++) {
+               psy = power_supply_get_by_name(pss[i]);
+               if (!psy)
+                       continue;
+
+               ret = psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &val);
+
+               if (!ret && val.intval) {
+                       charger_present = true;
+                       break;
+               }
+       }
+
+       if (!charger_present)
+               goto shutdown;
+
+       /* Check if battery is known */
+       psy = power_supply_get_by_name("ab8500_btemp");
+       if (psy) {
+               ret = psy->get_property(psy, POWER_SUPPLY_PROP_TECHNOLOGY,
+                                       &val);
+               if (!ret && val.intval != POWER_SUPPLY_TECHNOLOGY_UNKNOWN) {
+                       printk(KERN_INFO
+                              "Charger \"%s\" is connected with known battery."
+                              " Rebooting.\n",
+                              pss[i]);
+                       machine_restart("charging");
+               }
+       }
+
+shutdown:
+       sigfillset(&all);
+
+       if (!sigprocmask(SIG_BLOCK, &all, &old)) {
+               (void)ab8500_sysctrl_set(AB8500_STW4500CTRL1,
+                                        AB8500_STW4500CTRL1_SWOFF |
+                                        AB8500_STW4500CTRL1_SWRESET4500N);
+               (void)sigprocmask(SIG_SETMASK, &old, NULL);
+       }
+}
+
 static inline bool valid_bank(u8 bank)
 {
        return ((bank == AB8500_SYS_CTRL1_BLOCK) ||
@@ -33,6 +94,7 @@ int ab8500_sysctrl_read(u16 reg, u8 *value)
        return abx500_get_register_interruptible(sysctrl_dev, bank,
                (u8)(reg & 0xFF), value);
 }
+EXPORT_SYMBOL(ab8500_sysctrl_read);
 
 int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
 {
@@ -48,10 +110,40 @@ int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
        return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank,
                (u8)(reg & 0xFF), mask, value);
 }
+EXPORT_SYMBOL(ab8500_sysctrl_write);
 
 static int ab8500_sysctrl_probe(struct platform_device *pdev)
 {
+       struct ab8500_platform_data *plat;
+       struct ab8500_sysctrl_platform_data *pdata;
+
        sysctrl_dev = &pdev->dev;
+       plat = dev_get_platdata(pdev->dev.parent);
+       if (plat->pm_power_off)
+               pm_power_off = ab8500_power_off;
+
+       pdata = plat->sysctrl;
+
+       if (pdata) {
+               int ret, i, j;
+
+               for (i = AB8500_SYSCLKREQ1RFCLKBUF;
+                    i <= AB8500_SYSCLKREQ8RFCLKBUF; i++) {
+                       j = i - AB8500_SYSCLKREQ1RFCLKBUF;
+                       ret = ab8500_sysctrl_write(i, 0xff,
+                                                  pdata->initial_req_buf_config[j]);
+                       dev_dbg(&pdev->dev,
+                               "Setting SysClkReq%dRfClkBuf 0x%X\n",
+                               j + 1,
+                               pdata->initial_req_buf_config[j]);
+                       if (ret < 0) {
+                               dev_err(&pdev->dev,
+                                       "unable to set sysClkReq%dRfClkBuf: "
+                                       "%d\n", j + 1, ret);
+                       }
+               }
+       }
+
        return 0;
 }
 
index 7ce65f49480f1bfb4b68d7c693a27451e797e27b..9818afba25153b377cf2b64b54b18bccc02f3e2c 100644 (file)
@@ -153,6 +153,22 @@ int abx500_startup_irq_enabled(struct device *dev, unsigned int irq)
 }
 EXPORT_SYMBOL(abx500_startup_irq_enabled);
 
+void abx500_dump_all_banks(void)
+{
+       struct abx500_ops *ops;
+       struct device dummy_child = {0};
+       struct abx500_device_entry *dev_entry;
+
+       list_for_each_entry(dev_entry, &abx500_list, list) {
+               dummy_child.parent = dev_entry->dev;
+               ops = &dev_entry->ops;
+
+               if ((ops != NULL) && (ops->dump_all_banks != NULL))
+                       ops->dump_all_banks(&dummy_child);
+       }
+}
+EXPORT_SYMBOL(abx500_dump_all_banks);
+
 MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
 MODULE_DESCRIPTION("ABX500 core driver");
 MODULE_LICENSE("GPL");
index 222c03a5ddc0b3d3e9a37af453d4a1745f1b35e3..b562c7bf8a463903bf4b99d0b6c54b9a1358cf4f 100644 (file)
@@ -115,7 +115,7 @@ static irqreturn_t arizona_underclocked(int irq, void *data)
        if (val & ARIZONA_ADC_UNDERCLOCKED_STS)
                dev_err(arizona->dev, "ADC underclocked\n");
        if (val & ARIZONA_MIXER_UNDERCLOCKED_STS)
-               dev_err(arizona->dev, "Mixer underclocked\n");
+               dev_err(arizona->dev, "Mixer dropped sample\n");
 
        return IRQ_HANDLED;
 }
@@ -263,10 +263,36 @@ static int arizona_runtime_suspend(struct device *dev)
 }
 #endif
 
+#ifdef CONFIG_PM_SLEEP
+static int arizona_resume_noirq(struct device *dev)
+{
+       struct arizona *arizona = dev_get_drvdata(dev);
+
+       dev_dbg(arizona->dev, "Early resume, disabling IRQ\n");
+       disable_irq(arizona->irq);
+
+       return 0;
+}
+
+static int arizona_resume(struct device *dev)
+{
+       struct arizona *arizona = dev_get_drvdata(dev);
+
+       dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n");
+       enable_irq(arizona->irq);
+
+       return 0;
+}
+#endif
+
 const struct dev_pm_ops arizona_pm_ops = {
        SET_RUNTIME_PM_OPS(arizona_runtime_suspend,
                           arizona_runtime_resume,
                           NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(NULL, arizona_resume)
+#ifdef CONFIG_PM_SLEEP
+       .resume_noirq = arizona_resume_noirq,
+#endif
 };
 EXPORT_SYMBOL_GPL(arizona_pm_ops);
 
@@ -275,19 +301,19 @@ static struct mfd_cell early_devs[] = {
 };
 
 static struct mfd_cell wm5102_devs[] = {
+       { .name = "arizona-micsupp" },
        { .name = "arizona-extcon" },
        { .name = "arizona-gpio" },
        { .name = "arizona-haptics" },
-       { .name = "arizona-micsupp" },
        { .name = "arizona-pwm" },
        { .name = "wm5102-codec" },
 };
 
 static struct mfd_cell wm5110_devs[] = {
+       { .name = "arizona-micsupp" },
        { .name = "arizona-extcon" },
        { .name = "arizona-gpio" },
        { .name = "arizona-haptics" },
-       { .name = "arizona-micsupp" },
        { .name = "arizona-pwm" },
        { .name = "wm5110-codec" },
 };
@@ -484,6 +510,29 @@ int arizona_dev_init(struct arizona *arizona)
                goto err_reset;
        }
 
+       for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) {
+               if (!arizona->pdata.micbias[i].mV)
+                       continue;
+
+               val = (arizona->pdata.micbias[i].mV - 1500) / 100;
+               val <<= ARIZONA_MICB1_LVL_SHIFT;
+
+               if (arizona->pdata.micbias[i].ext_cap)
+                       val |= ARIZONA_MICB1_EXT_CAP;
+
+               if (arizona->pdata.micbias[i].discharge)
+                       val |= ARIZONA_MICB1_DISCH;
+
+               if (arizona->pdata.micbias[i].fast_start)
+                       val |= ARIZONA_MICB1_RATE;
+
+               regmap_update_bits(arizona->regmap,
+                                  ARIZONA_MIC_BIAS_CTRL_1 + i,
+                                  ARIZONA_MICB1_LVL_MASK |
+                                  ARIZONA_MICB1_DISCH |
+                                  ARIZONA_MICB1_RATE, val);
+       }
+
        for (i = 0; i < ARIZONA_MAX_INPUT; i++) {
                /* Default for both is 0 so noop with defaults */
                val = arizona->pdata.dmic_ref[i]
index 885e567803583a42473ffb532beead311ad68cf2..6a9fec40d018308a39e1ea24b086bfc94dfb77f0 100644 (file)
@@ -60,7 +60,7 @@ static inline bool i2c_safe_reg(unsigned char reg)
  * This fix is to follow any read or write with a dummy read to a safe
  * register.
  */
-int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
+static int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
 {
        int val;
 
@@ -85,7 +85,6 @@ int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
 
        return 0;
 }
-EXPORT_SYMBOL(da9052_i2c_fix);
 
 static int da9052_i2c_enable_multiwrite(struct da9052 *da9052)
 {
index a2bacf95b59ea543ca46104f9137a72497b89905..21f261bf9e95fd27825a50af02e6e014ec768dea 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/regulator/db8500-prcmu.h>
 #include <linux/regulator/machine.h>
 #include <linux/cpufreq.h>
+#include <linux/platform_data/ux500_wdt.h>
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/db8500-regs.h>
@@ -2207,21 +2208,25 @@ int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
                            sleep_auto_off ? A9WDOG_AUTO_OFF_EN :
                            A9WDOG_AUTO_OFF_DIS);
 }
+EXPORT_SYMBOL(db8500_prcmu_config_a9wdog);
 
 int db8500_prcmu_enable_a9wdog(u8 id)
 {
        return prcmu_a9wdog(MB4H_A9WDOG_EN, id, 0, 0, 0);
 }
+EXPORT_SYMBOL(db8500_prcmu_enable_a9wdog);
 
 int db8500_prcmu_disable_a9wdog(u8 id)
 {
        return prcmu_a9wdog(MB4H_A9WDOG_DIS, id, 0, 0, 0);
 }
+EXPORT_SYMBOL(db8500_prcmu_disable_a9wdog);
 
 int db8500_prcmu_kick_a9wdog(u8 id)
 {
        return prcmu_a9wdog(MB4H_A9WDOG_KICK, id, 0, 0, 0);
 }
+EXPORT_SYMBOL(db8500_prcmu_kick_a9wdog);
 
 /*
  * timeout is 28 bit, in ms.
@@ -2239,6 +2244,7 @@ int db8500_prcmu_load_a9wdog(u8 id, u32 timeout)
                            (u8)((timeout >> 12) & 0xff),
                            (u8)((timeout >> 20) & 0xff));
 }
+EXPORT_SYMBOL(db8500_prcmu_load_a9wdog);
 
 /**
  * prcmu_abb_read() - Read register value(s) from the ABB.
@@ -3094,6 +3100,11 @@ static struct resource ab8500_resources[] = {
        }
 };
 
+static struct ux500_wdt_data db8500_wdt_pdata = {
+       .timeout = 600, /* 10 minutes */
+       .has_28_bits_resolution = true,
+};
+
 static struct mfd_cell db8500_prcmu_devs[] = {
        {
                .name = "db8500-prcmu-regulators",
@@ -3107,6 +3118,12 @@ static struct mfd_cell db8500_prcmu_devs[] = {
                .platform_data = &db8500_cpufreq_table,
                .pdata_size = sizeof(db8500_cpufreq_table),
        },
+       {
+               .name = "ux500_wdt",
+               .platform_data = &db8500_wdt_pdata,
+               .pdata_size = sizeof(db8500_wdt_pdata),
+               .id = -1,
+       },
        {
                .name = "ab8500-core",
                .of_compatible = "stericsson,ab8500",
index d9d930302e98123c756e47477ca95cac0acebc59..9f12f91d6296e6793dca0a5f29e07c8a6621b314 100644 (file)
@@ -50,6 +50,7 @@
  *     document number TBD : Panther Point
  *     document number TBD : Lynx Point
  *     document number TBD : Lynx Point-LP
+ *     document number TBD : Wellsburg
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #define ACPIBASE_GCS_OFF       0x3410
 #define ACPIBASE_GCS_END       0x3414
 
-#define GPIOBASE               0x48
-#define GPIOCTRL               0x4C
+#define GPIOBASE_ICH0          0x58
+#define GPIOCTRL_ICH0          0x5C
+#define GPIOBASE_ICH6          0x48
+#define GPIOCTRL_ICH6          0x4C
 
 #define RCBABASE               0xf0
 
 #define wdt_mem_res(i) wdt_res(ICH_RES_MEM_OFF, i)
 #define wdt_res(b, i) (&wdt_ich_res[(b) + (i)])
 
-static int lpc_ich_acpi_save = -1;
-static int lpc_ich_gpio_save = -1;
+struct lpc_ich_cfg {
+       int base;
+       int ctrl;
+       int save;
+};
+
+struct lpc_ich_priv {
+       int chipset;
+       struct lpc_ich_cfg acpi;
+       struct lpc_ich_cfg gpio;
+};
 
 static struct resource wdt_ich_res[] = {
        /* ACPI - TCO */
@@ -194,6 +206,7 @@ enum lpc_chipsets {
        LPC_PPT,        /* Panther Point */
        LPC_LPT,        /* Lynx Point */
        LPC_LPT_LP,     /* Lynx Point-LP */
+       LPC_WBG,        /* Wellsburg */
 };
 
 struct lpc_ich_info lpc_chipset_info[] = {
@@ -474,6 +487,10 @@ struct lpc_ich_info lpc_chipset_info[] = {
                .name = "Lynx Point_LP",
                .iTCO_version = 2,
        },
+       [LPC_WBG] = {
+               .name = "Wellsburg",
+               .iTCO_version = 2,
+       },
 };
 
 /*
@@ -655,45 +672,82 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_ich_ids) = {
        { PCI_VDEVICE(INTEL, 0x9c45), LPC_LPT_LP},
        { PCI_VDEVICE(INTEL, 0x9c46), LPC_LPT_LP},
        { PCI_VDEVICE(INTEL, 0x9c47), LPC_LPT_LP},
+       { PCI_VDEVICE(INTEL, 0x8d40), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d41), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d42), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d43), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d44), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d45), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d46), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d47), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d48), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d49), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d4a), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d4b), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d4c), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d4d), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d4e), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d4f), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d50), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d51), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d52), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d53), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d54), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d55), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d56), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d57), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d58), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d59), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d5a), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d5b), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d5c), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d5d), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d5e), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x8d5f), LPC_WBG},
        { 0, },                 /* End of list */
 };
 MODULE_DEVICE_TABLE(pci, lpc_ich_ids);
 
 static void lpc_ich_restore_config_space(struct pci_dev *dev)
 {
-       if (lpc_ich_acpi_save >= 0) {
-               pci_write_config_byte(dev, ACPICTRL, lpc_ich_acpi_save);
-               lpc_ich_acpi_save = -1;
+       struct lpc_ich_priv *priv = pci_get_drvdata(dev);
+
+       if (priv->acpi.save >= 0) {
+               pci_write_config_byte(dev, priv->acpi.ctrl, priv->acpi.save);
+               priv->acpi.save = -1;
        }
 
-       if (lpc_ich_gpio_save >= 0) {
-               pci_write_config_byte(dev, GPIOCTRL, lpc_ich_gpio_save);
-               lpc_ich_gpio_save = -1;
+       if (priv->gpio.save >= 0) {
+               pci_write_config_byte(dev, priv->gpio.ctrl, priv->gpio.save);
+               priv->gpio.save = -1;
        }
 }
 
 static void lpc_ich_enable_acpi_space(struct pci_dev *dev)
 {
+       struct lpc_ich_priv *priv = pci_get_drvdata(dev);
        u8 reg_save;
 
-       pci_read_config_byte(dev, ACPICTRL, &reg_save);
-       pci_write_config_byte(dev, ACPICTRL, reg_save | 0x10);
-       lpc_ich_acpi_save = reg_save;
+       pci_read_config_byte(dev, priv->acpi.ctrl, &reg_save);
+       pci_write_config_byte(dev, priv->acpi.ctrl, reg_save | 0x10);
+       priv->acpi.save = reg_save;
 }
 
 static void lpc_ich_enable_gpio_space(struct pci_dev *dev)
 {
+       struct lpc_ich_priv *priv = pci_get_drvdata(dev);
        u8 reg_save;
 
-       pci_read_config_byte(dev, GPIOCTRL, &reg_save);
-       pci_write_config_byte(dev, GPIOCTRL, reg_save | 0x10);
-       lpc_ich_gpio_save = reg_save;
+       pci_read_config_byte(dev, priv->gpio.ctrl, &reg_save);
+       pci_write_config_byte(dev, priv->gpio.ctrl, reg_save | 0x10);
+       priv->gpio.save = reg_save;
 }
 
-static void lpc_ich_finalize_cell(struct mfd_cell *cell,
-                                       const struct pci_device_id *id)
+static void lpc_ich_finalize_cell(struct pci_dev *dev, struct mfd_cell *cell)
 {
-       cell->platform_data = &lpc_chipset_info[id->driver_data];
+       struct lpc_ich_priv *priv = pci_get_drvdata(dev);
+
+       cell->platform_data = &lpc_chipset_info[priv->chipset];
        cell->pdata_size = sizeof(struct lpc_ich_info);
 }
 
@@ -721,9 +775,9 @@ static int lpc_ich_check_conflict_gpio(struct resource *res)
        return use_gpio ? use_gpio : ret;
 }
 
-static int lpc_ich_init_gpio(struct pci_dev *dev,
-                               const struct pci_device_id *id)
+static int lpc_ich_init_gpio(struct pci_dev *dev)
 {
+       struct lpc_ich_priv *priv = pci_get_drvdata(dev);
        u32 base_addr_cfg;
        u32 base_addr;
        int ret;
@@ -731,7 +785,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev,
        struct resource *res;
 
        /* Setup power management base register */
-       pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg);
+       pci_read_config_dword(dev, priv->acpi.base, &base_addr_cfg);
        base_addr = base_addr_cfg & 0x0000ff80;
        if (!base_addr) {
                dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n");
@@ -757,7 +811,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev,
 
 gpe0_done:
        /* Setup GPIO base register */
-       pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
+       pci_read_config_dword(dev, priv->gpio.base, &base_addr_cfg);
        base_addr = base_addr_cfg & 0x0000ff80;
        if (!base_addr) {
                dev_notice(&dev->dev, "I/O space for GPIO uninitialized\n");
@@ -768,7 +822,7 @@ gpe0_done:
        /* Older devices provide fewer GPIO and have a smaller resource size. */
        res = &gpio_ich_res[ICH_RES_GPIO];
        res->start = base_addr;
-       switch (lpc_chipset_info[id->driver_data].gpio_version) {
+       switch (lpc_chipset_info[priv->chipset].gpio_version) {
        case ICH_V5_GPIO:
        case ICH_V10CORP_GPIO:
                res->end = res->start + 128 - 1;
@@ -784,10 +838,10 @@ gpe0_done:
                acpi_conflict = true;
                goto gpio_done;
        }
-       lpc_chipset_info[id->driver_data].use_gpio = ret;
+       lpc_chipset_info[priv->chipset].use_gpio = ret;
        lpc_ich_enable_gpio_space(dev);
 
-       lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id);
+       lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_GPIO]);
        ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_GPIO],
                              1, NULL, 0, NULL);
 
@@ -798,16 +852,16 @@ gpio_done:
        return ret;
 }
 
-static int lpc_ich_init_wdt(struct pci_dev *dev,
-                               const struct pci_device_id *id)
+static int lpc_ich_init_wdt(struct pci_dev *dev)
 {
+       struct lpc_ich_priv *priv = pci_get_drvdata(dev);
        u32 base_addr_cfg;
        u32 base_addr;
        int ret;
        struct resource *res;
 
        /* Setup power management base register */
-       pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg);
+       pci_read_config_dword(dev, priv->acpi.base, &base_addr_cfg);
        base_addr = base_addr_cfg & 0x0000ff80;
        if (!base_addr) {
                dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n");
@@ -830,7 +884,7 @@ static int lpc_ich_init_wdt(struct pci_dev *dev,
         * we have to read RCBA from PCI Config space 0xf0 and use
         * it as base. GCS = RCBA + ICH6_GCS(0x3410).
         */
-       if (lpc_chipset_info[id->driver_data].iTCO_version == 1) {
+       if (lpc_chipset_info[priv->chipset].iTCO_version == 1) {
                /* Don't register iomem for TCO ver 1 */
                lpc_ich_cells[LPC_WDT].num_resources--;
        } else {
@@ -847,7 +901,7 @@ static int lpc_ich_init_wdt(struct pci_dev *dev,
                res->end = base_addr + ACPIBASE_GCS_END;
        }
 
-       lpc_ich_finalize_cell(&lpc_ich_cells[LPC_WDT], id);
+       lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_WDT]);
        ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_WDT],
                              1, NULL, 0, NULL);
 
@@ -858,14 +912,36 @@ wdt_done:
 static int lpc_ich_probe(struct pci_dev *dev,
                                const struct pci_device_id *id)
 {
+       struct lpc_ich_priv *priv;
        int ret;
        bool cell_added = false;
 
-       ret = lpc_ich_init_wdt(dev, id);
+       priv = devm_kzalloc(&dev->dev,
+                           sizeof(struct lpc_ich_priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->chipset = id->driver_data;
+       priv->acpi.save = -1;
+       priv->acpi.base = ACPIBASE;
+       priv->acpi.ctrl = ACPICTRL;
+
+       priv->gpio.save = -1;
+       if (priv->chipset <= LPC_ICH5) {
+               priv->gpio.base = GPIOBASE_ICH0;
+               priv->gpio.ctrl = GPIOCTRL_ICH0;
+       } else {
+               priv->gpio.base = GPIOBASE_ICH6;
+               priv->gpio.ctrl = GPIOCTRL_ICH6;
+       }
+
+       pci_set_drvdata(dev, priv);
+
+       ret = lpc_ich_init_wdt(dev);
        if (!ret)
                cell_added = true;
 
-       ret = lpc_ich_init_gpio(dev, id);
+       ret = lpc_ich_init_gpio(dev);
        if (!ret)
                cell_added = true;
 
@@ -876,6 +952,7 @@ static int lpc_ich_probe(struct pci_dev *dev,
        if (!cell_added) {
                dev_warn(&dev->dev, "No MFD cells added\n");
                lpc_ich_restore_config_space(dev);
+               pci_set_drvdata(dev, NULL);
                return -ENODEV;
        }
 
@@ -886,6 +963,7 @@ static void lpc_ich_remove(struct pci_dev *dev)
 {
        mfd_remove_devices(&dev->dev);
        lpc_ich_restore_config_space(dev);
+       pci_set_drvdata(dev, NULL);
 }
 
 static struct pci_driver lpc_ich_driver = {
index 5624fcbba69b939b77468679b40ed16e59f1d1fa..8cc6aac27cb2d5ef77b0c7894dc9670afcfae4a8 100644 (file)
@@ -45,34 +45,32 @@ static struct resource smbus_sch_resource = {
                .flags = IORESOURCE_IO,
 };
 
-
 static struct resource gpio_sch_resource = {
                .flags = IORESOURCE_IO,
 };
 
-static struct mfd_cell lpc_sch_cells[] = {
-       {
-               .name = "isch_smbus",
-               .num_resources = 1,
-               .resources = &smbus_sch_resource,
-       },
-       {
-               .name = "sch_gpio",
-               .num_resources = 1,
-               .resources = &gpio_sch_resource,
-       },
-};
-
 static struct resource wdt_sch_resource = {
                .flags = IORESOURCE_IO,
 };
 
-static struct mfd_cell tunnelcreek_cells[] = {
-       {
-               .name = "ie6xx_wdt",
-               .num_resources = 1,
-               .resources = &wdt_sch_resource,
-       },
+static struct mfd_cell lpc_sch_cells[3];
+
+static struct mfd_cell isch_smbus_cell = {
+       .name = "isch_smbus",
+       .num_resources = 1,
+       .resources = &smbus_sch_resource,
+};
+
+static struct mfd_cell sch_gpio_cell = {
+       .name = "sch_gpio",
+       .num_resources = 1,
+       .resources = &gpio_sch_resource,
+};
+
+static struct mfd_cell wdt_sch_cell = {
+       .name = "ie6xx_wdt",
+       .num_resources = 1,
+       .resources = &wdt_sch_resource,
 };
 
 static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = {
@@ -88,79 +86,76 @@ static int lpc_sch_probe(struct pci_dev *dev,
 {
        unsigned int base_addr_cfg;
        unsigned short base_addr;
-       int i;
+       int i, cells = 0;
        int ret;
 
        pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
-       if (!(base_addr_cfg & (1 << 31))) {
-               dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n");
-               return -ENODEV;
-       }
-       base_addr = (unsigned short)base_addr_cfg;
-       if (base_addr == 0) {
-               dev_err(&dev->dev, "I/O space for SMBus uninitialized\n");
-               return -ENODEV;
-       }
-
-       smbus_sch_resource.start = base_addr;
-       smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
+       base_addr = 0;
+       if (!(base_addr_cfg & (1 << 31)))
+               dev_warn(&dev->dev, "Decode of the SMBus I/O range disabled\n");
+       else
+               base_addr = (unsigned short)base_addr_cfg;
 
-       pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
-       if (!(base_addr_cfg & (1 << 31))) {
-               dev_err(&dev->dev, "Decode of the GPIO I/O range disabled\n");
-               return -ENODEV;
-       }
-       base_addr = (unsigned short)base_addr_cfg;
        if (base_addr == 0) {
-               dev_err(&dev->dev, "I/O space for GPIO uninitialized\n");
-               return -ENODEV;
+               dev_warn(&dev->dev, "I/O space for SMBus uninitialized\n");
+       } else {
+               lpc_sch_cells[cells++] = isch_smbus_cell;
+               smbus_sch_resource.start = base_addr;
+               smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
        }
 
-       gpio_sch_resource.start = base_addr;
-
-       if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB)
-               gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1;
+       pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
+       base_addr = 0;
+       if (!(base_addr_cfg & (1 << 31)))
+               dev_warn(&dev->dev, "Decode of the GPIO I/O range disabled\n");
        else
-               gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1;
-
-       for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++)
-               lpc_sch_cells[i].id = id->device;
+               base_addr = (unsigned short)base_addr_cfg;
 
-       ret = mfd_add_devices(&dev->dev, 0,
-                             lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL,
-                             0, NULL);
-       if (ret)
-               goto out_dev;
+       if (base_addr == 0) {
+               dev_warn(&dev->dev, "I/O space for GPIO uninitialized\n");
+       } else {
+               lpc_sch_cells[cells++] = sch_gpio_cell;
+               gpio_sch_resource.start = base_addr;
+               if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB)
+                       gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1;
+               else
+                       gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1;
+       }
 
        if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC
-        || id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) {
+           || id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) {
                pci_read_config_dword(dev, WDTBASE, &base_addr_cfg);
-               if (!(base_addr_cfg & (1 << 31))) {
-                       dev_err(&dev->dev, "Decode of the WDT I/O range disabled\n");
-                       ret = -ENODEV;
-                       goto out_dev;
+               base_addr = 0;
+               if (!(base_addr_cfg & (1 << 31)))
+                       dev_warn(&dev->dev, "Decode of the WDT I/O range disabled\n");
+               else
+                       base_addr = (unsigned short)base_addr_cfg;
+               if (base_addr == 0)
+                       dev_warn(&dev->dev, "I/O space for WDT uninitialized\n");
+               else {
+                       lpc_sch_cells[cells++] = wdt_sch_cell;
+                       wdt_sch_resource.start = base_addr;
+                       wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1;
                }
-               base_addr = (unsigned short)base_addr_cfg;
-               if (base_addr == 0) {
-                       dev_err(&dev->dev, "I/O space for WDT uninitialized\n");
-                       ret = -ENODEV;
-                       goto out_dev;
-               }
-
-               wdt_sch_resource.start = base_addr;
-               wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1;
+       }
 
-               for (i = 0; i < ARRAY_SIZE(tunnelcreek_cells); i++)
-                       tunnelcreek_cells[i].id = id->device;
+       if (WARN_ON(cells > ARRAY_SIZE(lpc_sch_cells))) {
+               dev_err(&dev->dev, "Cell count exceeds array size");
+               return -ENODEV;
+       }
 
-               ret = mfd_add_devices(&dev->dev, 0, tunnelcreek_cells,
-                                     ARRAY_SIZE(tunnelcreek_cells), NULL,
-                                     0, NULL);
+       if (cells == 0) {
+               dev_err(&dev->dev, "All decode registers disabled.\n");
+               return -ENODEV;
        }
 
-       return ret;
-out_dev:
-       mfd_remove_devices(&dev->dev);
+       for (i = 0; i < cells; i++)
+               lpc_sch_cells[i].id = id->device;
+
+       ret = mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL);
+       if (ret)
+               mfd_remove_devices(&dev->dev);
+
        return ret;
 }
 
index e32466e865b92134b0d2355c7ff721198945bb0b..f0cc40296d8ccc50fab35f0805023bdab6ebc54f 100644 (file)
 #include <linux/i2c.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/machine.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/max8925.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 static struct resource bk_resources[] = {
        { 0x84, 0x84, "mode control", IORESOURCE_REG, },
@@ -639,17 +642,33 @@ static struct irq_chip max8925_irq_chip = {
        .irq_disable    = max8925_irq_disable,
 };
 
+static int max8925_irq_domain_map(struct irq_domain *d, unsigned int virq,
+                                irq_hw_number_t hw)
+{
+       irq_set_chip_data(virq, d->host_data);
+       irq_set_chip_and_handler(virq, &max8925_irq_chip, handle_edge_irq);
+       irq_set_nested_thread(virq, 1);
+#ifdef CONFIG_ARM
+       set_irq_flags(virq, IRQF_VALID);
+#else
+       irq_set_noprobe(virq);
+#endif
+       return 0;
+}
+
+static struct irq_domain_ops max8925_irq_domain_ops = {
+       .map    = max8925_irq_domain_map,
+       .xlate  = irq_domain_xlate_onetwocell,
+};
+
+
 static int max8925_irq_init(struct max8925_chip *chip, int irq,
                            struct max8925_platform_data *pdata)
 {
        unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
-       int i, ret;
-       int __irq;
+       int ret;
+       struct device_node *node = chip->dev->of_node;
 
-       if (!pdata || !pdata->irq_base) {
-               dev_warn(chip->dev, "No interrupt support on IRQ base\n");
-               return -EINVAL;
-       }
        /* clear all interrupts */
        max8925_reg_read(chip->i2c, MAX8925_CHG_IRQ1);
        max8925_reg_read(chip->i2c, MAX8925_CHG_IRQ2);
@@ -667,35 +686,30 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq,
        max8925_reg_write(chip->rtc, MAX8925_RTC_IRQ_MASK, 0xff);
 
        mutex_init(&chip->irq_lock);
-       chip->core_irq = irq;
-       chip->irq_base = pdata->irq_base;
-
-       /* register with genirq */
-       for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) {
-               __irq = i + chip->irq_base;
-               irq_set_chip_data(__irq, chip);
-               irq_set_chip_and_handler(__irq, &max8925_irq_chip,
-                                        handle_edge_irq);
-               irq_set_nested_thread(__irq, 1);
-#ifdef CONFIG_ARM
-               set_irq_flags(__irq, IRQF_VALID);
-#else
-               irq_set_noprobe(__irq);
-#endif
-       }
-       if (!irq) {
-               dev_warn(chip->dev, "No interrupt support on core IRQ\n");
-               goto tsc_irq;
+       chip->irq_base = irq_alloc_descs(-1, 0, MAX8925_NR_IRQS, 0);
+       if (chip->irq_base < 0) {
+               dev_err(chip->dev, "Failed to allocate interrupts, ret:%d\n",
+                       chip->irq_base);
+               return -EBUSY;
        }
 
+       irq_domain_add_legacy(node, MAX8925_NR_IRQS, chip->irq_base, 0,
+                             &max8925_irq_domain_ops, chip);
+
+       /* request irq handler for pmic main irq*/
+       chip->core_irq = irq;
+       if (!chip->core_irq)
+               return -EBUSY;
        ret = request_threaded_irq(irq, NULL, max8925_irq, flags | IRQF_ONESHOT,
                                   "max8925", chip);
        if (ret) {
                dev_err(chip->dev, "Failed to request core IRQ: %d\n", ret);
                chip->core_irq = 0;
+               return -EBUSY;
        }
 
-tsc_irq:
+       /* request irq handler for pmic tsc irq*/
+
        /* mask TSC interrupt */
        max8925_reg_write(chip->adc, MAX8925_TSC_IRQ_MASK, 0x0f);
 
@@ -704,7 +718,6 @@ tsc_irq:
                return 0;
        }
        chip->tsc_irq = pdata->tsc_irq;
-
        ret = request_threaded_irq(chip->tsc_irq, NULL, max8925_tsc_irq,
                                   flags | IRQF_ONESHOT, "max8925-tsc", chip);
        if (ret) {
@@ -846,7 +859,7 @@ int max8925_device_init(struct max8925_chip *chip,
 
        ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
                              ARRAY_SIZE(rtc_devs),
-                             &rtc_resources[0], chip->irq_base, NULL);
+                             NULL, chip->irq_base, NULL);
        if (ret < 0) {
                dev_err(chip->dev, "Failed to add rtc subdev\n");
                goto out;
@@ -854,7 +867,7 @@ int max8925_device_init(struct max8925_chip *chip,
 
        ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
                              ARRAY_SIZE(onkey_devs),
-                             &onkey_resources[0], 0, NULL);
+                             NULL, chip->irq_base, NULL);
        if (ret < 0) {
                dev_err(chip->dev, "Failed to add onkey subdev\n");
                goto out_dev;
@@ -873,21 +886,19 @@ int max8925_device_init(struct max8925_chip *chip,
                goto out_dev;
        }
 
-       if (pdata && pdata->power) {
-               ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
-                                       ARRAY_SIZE(power_devs),
-                                     &power_supply_resources[0], 0, NULL);
-               if (ret < 0) {
-                       dev_err(chip->dev, "Failed to add power supply "
-                               "subdev\n");
-                       goto out_dev;
-               }
+       ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
+                             ARRAY_SIZE(power_devs),
+                             NULL, 0, NULL);
+       if (ret < 0) {
+               dev_err(chip->dev,
+                       "Failed to add power supply subdev, err = %d\n", ret);
+               goto out_dev;
        }
 
        if (pdata && pdata->touch) {
                ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
                                      ARRAY_SIZE(touch_devs),
-                                     &touch_resources[0], 0, NULL);
+                                     NULL, chip->tsc_irq, NULL);
                if (ret < 0) {
                        dev_err(chip->dev, "Failed to add touch subdev\n");
                        goto out_dev;
index 00b5b456063df380fe88eb97144adb8d1282bfb9..92bbebd31598815659e667d890a846249b37db8b 100644 (file)
@@ -135,13 +135,37 @@ static const struct i2c_device_id max8925_id_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max8925_id_table);
 
+static int max8925_dt_init(struct device_node *np, struct device *dev,
+                          struct max8925_platform_data *pdata)
+{
+       int ret;
+
+       ret = of_property_read_u32(np, "maxim,tsc-irq", &pdata->tsc_irq);
+       if (ret) {
+               dev_err(dev, "Not found maxim,tsc-irq property\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
 static int max8925_probe(struct i2c_client *client,
                                   const struct i2c_device_id *id)
 {
        struct max8925_platform_data *pdata = client->dev.platform_data;
        static struct max8925_chip *chip;
-
-       if (!pdata) {
+       struct device_node *node = client->dev.of_node;
+
+       if (node && !pdata) {
+               /* parse DT to get platform data */
+               pdata = devm_kzalloc(&client->dev,
+                                    sizeof(struct max8925_platform_data),
+                                    GFP_KERNEL);
+               if (!pdata)
+                       return -ENOMEM;
+
+               if (max8925_dt_init(node, &client->dev, pdata))
+                       return -EINVAL;
+       } else if (!pdata) {
                pr_info("%s: platform data is missing\n", __func__);
                return -EINVAL;
        }
@@ -203,11 +227,18 @@ static int max8925_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(max8925_pm_ops, max8925_suspend, max8925_resume);
 
+static const struct of_device_id max8925_dt_ids[] = {
+       { .compatible = "maxim,max8925", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, max8925_dt_ids);
+
 static struct i2c_driver max8925_driver = {
        .driver = {
                .name   = "max8925",
                .owner  = THIS_MODULE,
                .pm     = &max8925_pm_ops,
+               .of_match_table = of_match_ptr(max8925_dt_ids),
        },
        .probe          = max8925_probe,
        .remove         = max8925_remove,
@@ -217,7 +248,6 @@ static struct i2c_driver max8925_driver = {
 static int __init max8925_i2c_init(void)
 {
        int ret;
-
        ret = i2c_add_driver(&max8925_driver);
        if (ret != 0)
                pr_err("Failed to register MAX8925 I2C driver: %d\n", ret);
index 05164d7f054b86ccfd6625cc21da545212d5983d..6b5edf64de2b3a4eafbdc0ace93a5a4bd2d4caea 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
-#include <linux/spinlock.h>
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/platform_data/usb-omap.h>
 
 
 struct usbhs_hcd_omap {
+       int                             nports;
+       struct clk                      **utmi_clk;
+       struct clk                      **hsic60m_clk;
+       struct clk                      **hsic480m_clk;
+
        struct clk                      *xclk60mhsp1_ck;
        struct clk                      *xclk60mhsp2_ck;
-       struct clk                      *utmi_p1_fck;
-       struct clk                      *usbhost_p1_fck;
-       struct clk                      *utmi_p2_fck;
-       struct clk                      *usbhost_p2_fck;
+       struct clk                      *utmi_p1_gfclk;
+       struct clk                      *utmi_p2_gfclk;
        struct clk                      *init_60m_fclk;
        struct clk                      *ehci_logic_fck;
 
        void __iomem                    *uhh_base;
 
-       struct usbhs_omap_platform_data platdata;
+       struct usbhs_omap_platform_data *pdata;
 
        u32                             usbhs_rev;
-       spinlock_t                      lock;
 };
 /*-------------------------------------------------------------------------*/
 
@@ -184,19 +185,13 @@ err_end:
 static int omap_usbhs_alloc_children(struct platform_device *pdev)
 {
        struct device                           *dev = &pdev->dev;
-       struct usbhs_hcd_omap                   *omap;
-       struct ehci_hcd_omap_platform_data      *ehci_data;
-       struct ohci_hcd_omap_platform_data      *ohci_data;
+       struct usbhs_omap_platform_data         *pdata = dev->platform_data;
        struct platform_device                  *ehci;
        struct platform_device                  *ohci;
        struct resource                         *res;
        struct resource                         resources[2];
        int                                     ret;
 
-       omap = platform_get_drvdata(pdev);
-       ehci_data = omap->platdata.ehci_data;
-       ohci_data = omap->platdata.ohci_data;
-
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci");
        if (!res) {
                dev_err(dev, "EHCI get resource IORESOURCE_MEM failed\n");
@@ -213,8 +208,8 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
        }
        resources[1] = *res;
 
-       ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, ehci_data,
-               sizeof(*ehci_data), dev);
+       ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, pdata,
+               sizeof(*pdata), dev);
 
        if (!ehci) {
                dev_err(dev, "omap_usbhs_alloc_child failed\n");
@@ -238,8 +233,8 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
        }
        resources[1] = *res;
 
-       ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, ohci_data,
-               sizeof(*ohci_data), dev);
+       ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, pdata,
+               sizeof(*pdata), dev);
        if (!ohci) {
                dev_err(dev, "omap_usbhs_alloc_child failed\n");
                ret = -ENOMEM;
@@ -278,31 +273,52 @@ static bool is_ohci_port(enum usbhs_omap_port_mode pmode)
 static int usbhs_runtime_resume(struct device *dev)
 {
        struct usbhs_hcd_omap           *omap = dev_get_drvdata(dev);
-       struct usbhs_omap_platform_data *pdata = &omap->platdata;
-       unsigned long                   flags;
+       struct usbhs_omap_platform_data *pdata = omap->pdata;
+       int i, r;
 
        dev_dbg(dev, "usbhs_runtime_resume\n");
 
-       if (!pdata) {
-               dev_dbg(dev, "missing platform_data\n");
-               return  -ENODEV;
-       }
-
        omap_tll_enable();
-       spin_lock_irqsave(&omap->lock, flags);
 
-       if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
+       if (!IS_ERR(omap->ehci_logic_fck))
                clk_enable(omap->ehci_logic_fck);
 
-       if (is_ehci_tll_mode(pdata->port_mode[0]))
-               clk_enable(omap->usbhost_p1_fck);
-       if (is_ehci_tll_mode(pdata->port_mode[1]))
-               clk_enable(omap->usbhost_p2_fck);
-
-       clk_enable(omap->utmi_p1_fck);
-       clk_enable(omap->utmi_p2_fck);
+       for (i = 0; i < omap->nports; i++) {
+               switch (pdata->port_mode[i]) {
+               case OMAP_EHCI_PORT_MODE_HSIC:
+                       if (!IS_ERR(omap->hsic60m_clk[i])) {
+                               r = clk_enable(omap->hsic60m_clk[i]);
+                               if (r) {
+                                       dev_err(dev,
+                                        "Can't enable port %d hsic60m clk:%d\n",
+                                        i, r);
+                               }
+                       }
 
-       spin_unlock_irqrestore(&omap->lock, flags);
+                       if (!IS_ERR(omap->hsic480m_clk[i])) {
+                               r = clk_enable(omap->hsic480m_clk[i]);
+                               if (r) {
+                                       dev_err(dev,
+                                        "Can't enable port %d hsic480m clk:%d\n",
+                                        i, r);
+                               }
+                       }
+               /* Fall through as HSIC mode needs utmi_clk */
+
+               case OMAP_EHCI_PORT_MODE_TLL:
+                       if (!IS_ERR(omap->utmi_clk[i])) {
+                               r = clk_enable(omap->utmi_clk[i]);
+                               if (r) {
+                                       dev_err(dev,
+                                        "Can't enable port %d clk : %d\n",
+                                        i, r);
+                               }
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
 
        return 0;
 }
@@ -310,51 +326,122 @@ static int usbhs_runtime_resume(struct device *dev)
 static int usbhs_runtime_suspend(struct device *dev)
 {
        struct usbhs_hcd_omap           *omap = dev_get_drvdata(dev);
-       struct usbhs_omap_platform_data *pdata = &omap->platdata;
-       unsigned long                   flags;
+       struct usbhs_omap_platform_data *pdata = omap->pdata;
+       int i;
 
        dev_dbg(dev, "usbhs_runtime_suspend\n");
 
-       if (!pdata) {
-               dev_dbg(dev, "missing platform_data\n");
-               return  -ENODEV;
-       }
-
-       spin_lock_irqsave(&omap->lock, flags);
+       for (i = 0; i < omap->nports; i++) {
+               switch (pdata->port_mode[i]) {
+               case OMAP_EHCI_PORT_MODE_HSIC:
+                       if (!IS_ERR(omap->hsic60m_clk[i]))
+                               clk_disable(omap->hsic60m_clk[i]);
 
-       if (is_ehci_tll_mode(pdata->port_mode[0]))
-               clk_disable(omap->usbhost_p1_fck);
-       if (is_ehci_tll_mode(pdata->port_mode[1]))
-               clk_disable(omap->usbhost_p2_fck);
+                       if (!IS_ERR(omap->hsic480m_clk[i]))
+                               clk_disable(omap->hsic480m_clk[i]);
+               /* Fall through as utmi_clks were used in HSIC mode */
 
-       clk_disable(omap->utmi_p2_fck);
-       clk_disable(omap->utmi_p1_fck);
+               case OMAP_EHCI_PORT_MODE_TLL:
+                       if (!IS_ERR(omap->utmi_clk[i]))
+                               clk_disable(omap->utmi_clk[i]);
+                       break;
+               default:
+                       break;
+               }
+       }
 
-       if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
+       if (!IS_ERR(omap->ehci_logic_fck))
                clk_disable(omap->ehci_logic_fck);
 
-       spin_unlock_irqrestore(&omap->lock, flags);
        omap_tll_disable();
 
        return 0;
 }
 
+static unsigned omap_usbhs_rev1_hostconfig(struct usbhs_hcd_omap *omap,
+                                               unsigned reg)
+{
+       struct usbhs_omap_platform_data *pdata = omap->pdata;
+       int i;
+
+       for (i = 0; i < omap->nports; i++) {
+               switch (pdata->port_mode[i]) {
+               case OMAP_USBHS_PORT_MODE_UNUSED:
+                       reg &= ~(OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS << i);
+                       break;
+               case OMAP_EHCI_PORT_MODE_PHY:
+                       if (pdata->single_ulpi_bypass)
+                               break;
+
+                       if (i == 0)
+                               reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
+                       else
+                               reg &= ~(OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS
+                                                               << (i-1));
+                       break;
+               default:
+                       if (pdata->single_ulpi_bypass)
+                               break;
+
+                       if (i == 0)
+                               reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
+                       else
+                               reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS
+                                                               << (i-1);
+                       break;
+               }
+       }
+
+       if (pdata->single_ulpi_bypass) {
+               /* bypass ULPI only if none of the ports use PHY mode */
+               reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
+
+               for (i = 0; i < omap->nports; i++) {
+                       if (is_ehci_phy_mode(pdata->port_mode[i])) {
+                               reg &= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
+                               break;
+                       }
+               }
+       }
+
+       return reg;
+}
+
+static unsigned omap_usbhs_rev2_hostconfig(struct usbhs_hcd_omap *omap,
+                                               unsigned reg)
+{
+       struct usbhs_omap_platform_data *pdata = omap->pdata;
+       int i;
+
+       for (i = 0; i < omap->nports; i++) {
+               /* Clear port mode fields for PHY mode */
+               reg &= ~(OMAP4_P1_MODE_CLEAR << 2 * i);
+
+               if (is_ehci_tll_mode(pdata->port_mode[i]) ||
+                               (is_ohci_port(pdata->port_mode[i])))
+                       reg |= OMAP4_P1_MODE_TLL << 2 * i;
+               else if (is_ehci_hsic_mode(pdata->port_mode[i]))
+                       reg |= OMAP4_P1_MODE_HSIC << 2 * i;
+       }
+
+       return reg;
+}
+
 static void omap_usbhs_init(struct device *dev)
 {
        struct usbhs_hcd_omap           *omap = dev_get_drvdata(dev);
-       struct usbhs_omap_platform_data *pdata = &omap->platdata;
-       unsigned long                   flags;
+       struct usbhs_omap_platform_data *pdata = omap->pdata;
        unsigned                        reg;
 
        dev_dbg(dev, "starting TI HSUSB Controller\n");
 
-       if (pdata->ehci_data->phy_reset) {
-               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
-                       gpio_request_one(pdata->ehci_data->reset_gpio_port[0],
+       if (pdata->phy_reset) {
+               if (gpio_is_valid(pdata->reset_gpio_port[0]))
+                       gpio_request_one(pdata->reset_gpio_port[0],
                                         GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
 
-               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
-                       gpio_request_one(pdata->ehci_data->reset_gpio_port[1],
+               if (gpio_is_valid(pdata->reset_gpio_port[1]))
+                       gpio_request_one(pdata->reset_gpio_port[1],
                                         GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
 
                /* Hold the PHY in RESET for enough time till DIR is high */
@@ -362,9 +449,6 @@ static void omap_usbhs_init(struct device *dev)
        }
 
        pm_runtime_get_sync(dev);
-       spin_lock_irqsave(&omap->lock, flags);
-       omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
-       dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
 
        reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
        /* setup ULPI bypass and burst configurations */
@@ -374,89 +458,51 @@ static void omap_usbhs_init(struct device *dev)
        reg |= OMAP4_UHH_HOSTCONFIG_APP_START_CLK;
        reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;
 
-       if (is_omap_usbhs_rev1(omap)) {
-               if (pdata->port_mode[0] == OMAP_USBHS_PORT_MODE_UNUSED)
-                       reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
-               if (pdata->port_mode[1] == OMAP_USBHS_PORT_MODE_UNUSED)
-                       reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
-               if (pdata->port_mode[2] == OMAP_USBHS_PORT_MODE_UNUSED)
-                       reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
-
-               /* Bypass the TLL module for PHY mode operation */
-               if (pdata->single_ulpi_bypass) {
-                       dev_dbg(dev, "OMAP3 ES version <= ES2.1\n");
-                       if (is_ehci_phy_mode(pdata->port_mode[0]) ||
-                               is_ehci_phy_mode(pdata->port_mode[1]) ||
-                                       is_ehci_phy_mode(pdata->port_mode[2]))
-                               reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
-                       else
-                               reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
-               } else {
-                       dev_dbg(dev, "OMAP3 ES version > ES2.1\n");
-                       if (is_ehci_phy_mode(pdata->port_mode[0]))
-                               reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
-                       else
-                               reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
-                       if (is_ehci_phy_mode(pdata->port_mode[1]))
-                               reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
-                       else
-                               reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
-                       if (is_ehci_phy_mode(pdata->port_mode[2]))
-                               reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
-                       else
-                               reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
-               }
-       } else if (is_omap_usbhs_rev2(omap)) {
-               /* Clear port mode fields for PHY mode*/
-               reg &= ~OMAP4_P1_MODE_CLEAR;
-               reg &= ~OMAP4_P2_MODE_CLEAR;
+       switch (omap->usbhs_rev) {
+       case OMAP_USBHS_REV1:
+               omap_usbhs_rev1_hostconfig(omap, reg);
+               break;
 
-               if (is_ehci_tll_mode(pdata->port_mode[0]) ||
-                       (is_ohci_port(pdata->port_mode[0])))
-                       reg |= OMAP4_P1_MODE_TLL;
-               else if (is_ehci_hsic_mode(pdata->port_mode[0]))
-                       reg |= OMAP4_P1_MODE_HSIC;
+       case OMAP_USBHS_REV2:
+               omap_usbhs_rev2_hostconfig(omap, reg);
+               break;
 
-               if (is_ehci_tll_mode(pdata->port_mode[1]) ||
-                       (is_ohci_port(pdata->port_mode[1])))
-                       reg |= OMAP4_P2_MODE_TLL;
-               else if (is_ehci_hsic_mode(pdata->port_mode[1]))
-                       reg |= OMAP4_P2_MODE_HSIC;
+       default:        /* newer revisions */
+               omap_usbhs_rev2_hostconfig(omap, reg);
+               break;
        }
 
        usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
        dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg);
 
-       spin_unlock_irqrestore(&omap->lock, flags);
-
        pm_runtime_put_sync(dev);
-       if (pdata->ehci_data->phy_reset) {
+       if (pdata->phy_reset) {
                /* Hold the PHY in RESET for enough time till
                 * PHY is settled and ready
                 */
                udelay(10);
 
-               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
+               if (gpio_is_valid(pdata->reset_gpio_port[0]))
                        gpio_set_value_cansleep
-                               (pdata->ehci_data->reset_gpio_port[0], 1);
+                               (pdata->reset_gpio_port[0], 1);
 
-               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
+               if (gpio_is_valid(pdata->reset_gpio_port[1]))
                        gpio_set_value_cansleep
-                               (pdata->ehci_data->reset_gpio_port[1], 1);
+                               (pdata->reset_gpio_port[1], 1);
        }
 }
 
 static void omap_usbhs_deinit(struct device *dev)
 {
        struct usbhs_hcd_omap           *omap = dev_get_drvdata(dev);
-       struct usbhs_omap_platform_data *pdata = &omap->platdata;
+       struct usbhs_omap_platform_data *pdata = omap->pdata;
 
-       if (pdata->ehci_data->phy_reset) {
-               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
-                       gpio_free(pdata->ehci_data->reset_gpio_port[0]);
+       if (pdata->phy_reset) {
+               if (gpio_is_valid(pdata->reset_gpio_port[0]))
+                       gpio_free(pdata->reset_gpio_port[0]);
 
-               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
-                       gpio_free(pdata->ehci_data->reset_gpio_port[1]);
+               if (gpio_is_valid(pdata->reset_gpio_port[1]))
+                       gpio_free(pdata->reset_gpio_port[1]);
        }
 }
 
@@ -474,137 +520,185 @@ static int usbhs_omap_probe(struct platform_device *pdev)
        struct resource                 *res;
        int                             ret = 0;
        int                             i;
+       bool                            need_logic_fck;
 
        if (!pdata) {
                dev_err(dev, "Missing platform data\n");
-               ret = -ENOMEM;
-               goto end_probe;
+               return -ENODEV;
        }
 
-       omap = kzalloc(sizeof(*omap), GFP_KERNEL);
+       omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
        if (!omap) {
                dev_err(dev, "Memory allocation failed\n");
-               ret = -ENOMEM;
-               goto end_probe;
+               return -ENOMEM;
        }
 
-       spin_lock_init(&omap->lock);
-
-       for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
-               omap->platdata.port_mode[i] = pdata->port_mode[i];
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
+       omap->uhh_base = devm_request_and_ioremap(dev, res);
+       if (!omap->uhh_base) {
+               dev_err(dev, "Resource request/ioremap failed\n");
+               return -EADDRNOTAVAIL;
+       }
 
-       omap->platdata.ehci_data = pdata->ehci_data;
-       omap->platdata.ohci_data = pdata->ohci_data;
+       omap->pdata = pdata;
 
        pm_runtime_enable(dev);
 
+       platform_set_drvdata(pdev, omap);
+       pm_runtime_get_sync(dev);
+
+       omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
 
-       for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
-               if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) ||
-                       is_ehci_hsic_mode(i)) {
-                       omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck");
-                       if (IS_ERR(omap->ehci_logic_fck)) {
-                               ret = PTR_ERR(omap->ehci_logic_fck);
-                               dev_warn(dev, "ehci_logic_fck failed:%d\n",
-                                        ret);
-                       }
+       /* we need to call runtime suspend before we update omap->nports
+        * to prevent unbalanced clk_disable()
+        */
+       pm_runtime_put_sync(dev);
+
+       /*
+        * If platform data contains nports then use that
+        * else make out number of ports from USBHS revision
+        */
+       if (pdata->nports) {
+               omap->nports = pdata->nports;
+       } else {
+               switch (omap->usbhs_rev) {
+               case OMAP_USBHS_REV1:
+                       omap->nports = 3;
+                       break;
+               case OMAP_USBHS_REV2:
+                       omap->nports = 2;
+                       break;
+               default:
+                       omap->nports = OMAP3_HS_USB_PORTS;
+                       dev_dbg(dev,
+                        "USB HOST Rev:0x%d not recognized, assuming %d ports\n",
+                        omap->usbhs_rev, omap->nports);
                        break;
                }
+       }
 
-       omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
-       if (IS_ERR(omap->utmi_p1_fck)) {
-               ret = PTR_ERR(omap->utmi_p1_fck);
-               dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
-               goto err_end;
+       i = sizeof(struct clk *) * omap->nports;
+       omap->utmi_clk = devm_kzalloc(dev, i, GFP_KERNEL);
+       omap->hsic480m_clk = devm_kzalloc(dev, i, GFP_KERNEL);
+       omap->hsic60m_clk = devm_kzalloc(dev, i, GFP_KERNEL);
+
+       if (!omap->utmi_clk || !omap->hsic480m_clk || !omap->hsic60m_clk) {
+               dev_err(dev, "Memory allocation failed\n");
+               ret = -ENOMEM;
+               goto err_mem;
+       }
+
+       need_logic_fck = false;
+       for (i = 0; i < omap->nports; i++) {
+               if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) ||
+                       is_ehci_hsic_mode(i))
+                               need_logic_fck |= true;
+       }
+
+       omap->ehci_logic_fck = ERR_PTR(-EINVAL);
+       if (need_logic_fck) {
+               omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck");
+               if (IS_ERR(omap->ehci_logic_fck)) {
+                       ret = PTR_ERR(omap->ehci_logic_fck);
+                       dev_dbg(dev, "ehci_logic_fck failed:%d\n", ret);
+               }
+       }
+
+       omap->utmi_p1_gfclk = clk_get(dev, "utmi_p1_gfclk");
+       if (IS_ERR(omap->utmi_p1_gfclk)) {
+               ret = PTR_ERR(omap->utmi_p1_gfclk);
+               dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
+               goto err_p1_gfclk;
+       }
+
+       omap->utmi_p2_gfclk = clk_get(dev, "utmi_p2_gfclk");
+       if (IS_ERR(omap->utmi_p2_gfclk)) {
+               ret = PTR_ERR(omap->utmi_p2_gfclk);
+               dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
+               goto err_p2_gfclk;
        }
 
        omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
        if (IS_ERR(omap->xclk60mhsp1_ck)) {
                ret = PTR_ERR(omap->xclk60mhsp1_ck);
                dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
-               goto err_utmi_p1_fck;
-       }
-
-       omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
-       if (IS_ERR(omap->utmi_p2_fck)) {
-               ret = PTR_ERR(omap->utmi_p2_fck);
-               dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
-               goto err_xclk60mhsp1_ck;
+               goto err_xclk60mhsp1;
        }
 
        omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
        if (IS_ERR(omap->xclk60mhsp2_ck)) {
                ret = PTR_ERR(omap->xclk60mhsp2_ck);
                dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
-               goto err_utmi_p2_fck;
-       }
-
-       omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
-       if (IS_ERR(omap->usbhost_p1_fck)) {
-               ret = PTR_ERR(omap->usbhost_p1_fck);
-               dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
-               goto err_xclk60mhsp2_ck;
-       }
-
-       omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
-       if (IS_ERR(omap->usbhost_p2_fck)) {
-               ret = PTR_ERR(omap->usbhost_p2_fck);
-               dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
-               goto err_usbhost_p1_fck;
+               goto err_xclk60mhsp2;
        }
 
        omap->init_60m_fclk = clk_get(dev, "init_60m_fclk");
        if (IS_ERR(omap->init_60m_fclk)) {
                ret = PTR_ERR(omap->init_60m_fclk);
                dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
-               goto err_usbhost_p2_fck;
+               goto err_init60m;
+       }
+
+       for (i = 0; i < omap->nports; i++) {
+               char clkname[30];
+
+               /* clock names are indexed from 1*/
+               snprintf(clkname, sizeof(clkname),
+                               "usb_host_hs_utmi_p%d_clk", i + 1);
+
+               /* If a clock is not found we won't bail out as not all
+                * platforms have all clocks and we can function without
+                * them
+                */
+               omap->utmi_clk[i] = clk_get(dev, clkname);
+               if (IS_ERR(omap->utmi_clk[i]))
+                       dev_dbg(dev, "Failed to get clock : %s : %ld\n",
+                               clkname, PTR_ERR(omap->utmi_clk[i]));
+
+               snprintf(clkname, sizeof(clkname),
+                               "usb_host_hs_hsic480m_p%d_clk", i + 1);
+               omap->hsic480m_clk[i] = clk_get(dev, clkname);
+               if (IS_ERR(omap->hsic480m_clk[i]))
+                       dev_dbg(dev, "Failed to get clock : %s : %ld\n",
+                               clkname, PTR_ERR(omap->hsic480m_clk[i]));
+
+               snprintf(clkname, sizeof(clkname),
+                               "usb_host_hs_hsic60m_p%d_clk", i + 1);
+               omap->hsic60m_clk[i] = clk_get(dev, clkname);
+               if (IS_ERR(omap->hsic60m_clk[i]))
+                       dev_dbg(dev, "Failed to get clock : %s : %ld\n",
+                               clkname, PTR_ERR(omap->hsic60m_clk[i]));
        }
 
        if (is_ehci_phy_mode(pdata->port_mode[0])) {
-               /* for OMAP3 , the clk set paretn fails */
-               ret = clk_set_parent(omap->utmi_p1_fck,
+               /* for OMAP3, clk_set_parent fails */
+               ret = clk_set_parent(omap->utmi_p1_gfclk,
                                        omap->xclk60mhsp1_ck);
                if (ret != 0)
-                       dev_err(dev, "xclk60mhsp1_ck set parent"
-                               "failed error:%d\n", ret);
+                       dev_dbg(dev, "xclk60mhsp1_ck set parent failed: %d\n",
+                                       ret);
        } else if (is_ehci_tll_mode(pdata->port_mode[0])) {
-               ret = clk_set_parent(omap->utmi_p1_fck,
+               ret = clk_set_parent(omap->utmi_p1_gfclk,
                                        omap->init_60m_fclk);
                if (ret != 0)
-                       dev_err(dev, "init_60m_fclk set parent"
-                               "failed error:%d\n", ret);
+                       dev_dbg(dev, "P0 init_60m_fclk set parent failed: %d\n",
+                                       ret);
        }
 
        if (is_ehci_phy_mode(pdata->port_mode[1])) {
-               ret = clk_set_parent(omap->utmi_p2_fck,
+               ret = clk_set_parent(omap->utmi_p2_gfclk,
                                        omap->xclk60mhsp2_ck);
                if (ret != 0)
-                       dev_err(dev, "xclk60mhsp2_ck set parent"
-                                       "failed error:%d\n", ret);
+                       dev_dbg(dev, "xclk60mhsp2_ck set parent failed: %d\n",
+                                       ret);
        } else if (is_ehci_tll_mode(pdata->port_mode[1])) {
-               ret = clk_set_parent(omap->utmi_p2_fck,
+               ret = clk_set_parent(omap->utmi_p2_gfclk,
                                                omap->init_60m_fclk);
                if (ret != 0)
-                       dev_err(dev, "init_60m_fclk set parent"
-                               "failed error:%d\n", ret);
-       }
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
-       if (!res) {
-               dev_err(dev, "UHH EHCI get resource failed\n");
-               ret = -ENODEV;
-               goto err_init_60m_fclk;
-       }
-
-       omap->uhh_base = ioremap(res->start, resource_size(res));
-       if (!omap->uhh_base) {
-               dev_err(dev, "UHH ioremap failed\n");
-               ret = -ENOMEM;
-               goto err_init_60m_fclk;
+                       dev_dbg(dev, "P1 init_60m_fclk set parent failed: %d\n",
+                                       ret);
        }
 
-       platform_set_drvdata(pdev, omap);
-
        omap_usbhs_init(dev);
        ret = omap_usbhs_alloc_children(pdev);
        if (ret) {
@@ -612,39 +706,41 @@ static int usbhs_omap_probe(struct platform_device *pdev)
                goto err_alloc;
        }
 
-       goto end_probe;
+       return 0;
 
 err_alloc:
        omap_usbhs_deinit(&pdev->dev);
-       iounmap(omap->uhh_base);
-
-err_init_60m_fclk:
-       clk_put(omap->init_60m_fclk);
 
-err_usbhost_p2_fck:
-       clk_put(omap->usbhost_p2_fck);
+       for (i = 0; i < omap->nports; i++) {
+               if (!IS_ERR(omap->utmi_clk[i]))
+                       clk_put(omap->utmi_clk[i]);
+               if (!IS_ERR(omap->hsic60m_clk[i]))
+                       clk_put(omap->hsic60m_clk[i]);
+               if (!IS_ERR(omap->hsic480m_clk[i]))
+                       clk_put(omap->hsic480m_clk[i]);
+       }
 
-err_usbhost_p1_fck:
-       clk_put(omap->usbhost_p1_fck);
+       clk_put(omap->init_60m_fclk);
 
-err_xclk60mhsp2_ck:
+err_init60m:
        clk_put(omap->xclk60mhsp2_ck);
 
-err_utmi_p2_fck:
-       clk_put(omap->utmi_p2_fck);
-
-err_xclk60mhsp1_ck:
+err_xclk60mhsp2:
        clk_put(omap->xclk60mhsp1_ck);
 
-err_utmi_p1_fck:
-       clk_put(omap->utmi_p1_fck);
+err_xclk60mhsp1:
+       clk_put(omap->utmi_p2_gfclk);
 
-err_end:
-       clk_put(omap->ehci_logic_fck);
+err_p2_gfclk:
+       clk_put(omap->utmi_p1_gfclk);
+
+err_p1_gfclk:
+       if (!IS_ERR(omap->ehci_logic_fck))
+               clk_put(omap->ehci_logic_fck);
+
+err_mem:
        pm_runtime_disable(dev);
-       kfree(omap);
 
-end_probe:
        return ret;
 }
 
@@ -657,19 +753,29 @@ end_probe:
 static int usbhs_omap_remove(struct platform_device *pdev)
 {
        struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
+       int i;
 
        omap_usbhs_deinit(&pdev->dev);
-       iounmap(omap->uhh_base);
+
+       for (i = 0; i < omap->nports; i++) {
+               if (!IS_ERR(omap->utmi_clk[i]))
+                       clk_put(omap->utmi_clk[i]);
+               if (!IS_ERR(omap->hsic60m_clk[i]))
+                       clk_put(omap->hsic60m_clk[i]);
+               if (!IS_ERR(omap->hsic480m_clk[i]))
+                       clk_put(omap->hsic480m_clk[i]);
+       }
+
        clk_put(omap->init_60m_fclk);
-       clk_put(omap->usbhost_p2_fck);
-       clk_put(omap->usbhost_p1_fck);
+       clk_put(omap->utmi_p1_gfclk);
+       clk_put(omap->utmi_p2_gfclk);
        clk_put(omap->xclk60mhsp2_ck);
-       clk_put(omap->utmi_p2_fck);
        clk_put(omap->xclk60mhsp1_ck);
-       clk_put(omap->utmi_p1_fck);
-       clk_put(omap->ehci_logic_fck);
+
+       if (!IS_ERR(omap->ehci_logic_fck))
+               clk_put(omap->ehci_logic_fck);
+
        pm_runtime_disable(&pdev->dev);
-       kfree(omap);
 
        return 0;
 }
@@ -685,7 +791,7 @@ static struct platform_driver usbhs_omap_driver = {
                .owner          = THIS_MODULE,
                .pm             = &usbhsomap_dev_pm_ops,
        },
-       .remove         = __exit_p(usbhs_omap_remove),
+       .remove         = usbhs_omap_remove,
 };
 
 MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>");
index eb869153206d27f3d58a45d177f19a1076b3a1dd..0aef1a768880550a3e18ae7da547f55e76cc6fd4 100644 (file)
 
 #define        OMAP_TLL_CHANNEL_CONF(num)                      (0x040 + 0x004 * num)
 #define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT           24
+#define OMAP_TLL_CHANNEL_CONF_DRVVBUS                  (1 << 16)
+#define OMAP_TLL_CHANNEL_CONF_CHRGVBUS                 (1 << 15)
 #define        OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF            (1 << 11)
 #define        OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE         (1 << 10)
 #define        OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE              (1 << 9)
 #define        OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE               (1 << 8)
+#define OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI    (2 << 1)
 #define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS            (1 << 1)
 #define        OMAP_TLL_CHANNEL_CONF_CHANEN                    (1 << 0)
 
 #define OMAP_USBTLL_REV1               0x00000015      /* OMAP3 */
 #define OMAP_USBTLL_REV2               0x00000018      /* OMAP 3630 */
 #define OMAP_USBTLL_REV3               0x00000004      /* OMAP4 */
+#define OMAP_USBTLL_REV4               0x00000006      /* OMAP5 */
 
 #define is_ehci_tll_mode(x)    (x == OMAP_EHCI_PORT_MODE_TLL)
 
+/* only PHY and UNUSED modes don't need TLL */
+#define omap_usb_mode_needs_tll(x)     ((x) != OMAP_USBHS_PORT_MODE_UNUSED &&\
+                                        (x) != OMAP_EHCI_PORT_MODE_PHY)
+
 struct usbtll_omap {
-       struct clk                              *usbtll_p1_fck;
-       struct clk                              *usbtll_p2_fck;
-       struct usbtll_omap_platform_data        platdata;
-       /* secure the register updates */
-       spinlock_t                              lock;
+       int                                     nch;    /* num. of channels */
+       struct usbhs_omap_platform_data         *pdata;
+       struct clk                              **ch_clk;
 };
 
 /*-------------------------------------------------------------------------*/
 
-const char usbtll_driver_name[] = USBTLL_DRIVER_NAME;
-struct platform_device *tll_pdev;
+static const char usbtll_driver_name[] = USBTLL_DRIVER_NAME;
+static struct device   *tll_dev;
+static DEFINE_SPINLOCK(tll_lock);      /* serialize access to tll_dev */
 
 /*-------------------------------------------------------------------------*/
 
@@ -203,84 +210,84 @@ static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode)
 static int usbtll_omap_probe(struct platform_device *pdev)
 {
        struct device                           *dev =  &pdev->dev;
-       struct usbtll_omap_platform_data        *pdata = dev->platform_data;
+       struct usbhs_omap_platform_data         *pdata = dev->platform_data;
        void __iomem                            *base;
        struct resource                         *res;
        struct usbtll_omap                      *tll;
        unsigned                                reg;
-       unsigned long                           flags;
        int                                     ret = 0;
-       int                                     i, ver, count;
+       int                                     i, ver;
+       bool needs_tll;
 
        dev_dbg(dev, "starting TI HSUSB TLL Controller\n");
 
-       tll = kzalloc(sizeof(struct usbtll_omap), GFP_KERNEL);
+       tll = devm_kzalloc(dev, sizeof(struct usbtll_omap), GFP_KERNEL);
        if (!tll) {
                dev_err(dev, "Memory allocation failed\n");
-               ret = -ENOMEM;
-               goto end;
+               return -ENOMEM;
        }
 
-       spin_lock_init(&tll->lock);
-
-       for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
-               tll->platdata.port_mode[i] = pdata->port_mode[i];
-
-       tll->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk");
-       if (IS_ERR(tll->usbtll_p1_fck)) {
-               ret = PTR_ERR(tll->usbtll_p1_fck);
-               dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret);
-               goto err_tll;
+       if (!pdata) {
+               dev_err(dev, "Platform data missing\n");
+               return -ENODEV;
        }
 
-       tll->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk");
-       if (IS_ERR(tll->usbtll_p2_fck)) {
-               ret = PTR_ERR(tll->usbtll_p2_fck);
-               dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret);
-               goto err_usbtll_p1_fck;
-       }
+       tll->pdata = pdata;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(dev, "usb tll get resource failed\n");
-               ret = -ENODEV;
-               goto err_usbtll_p2_fck;
-       }
-
-       base = ioremap(res->start, resource_size(res));
+       base = devm_request_and_ioremap(dev, res);
        if (!base) {
-               dev_err(dev, "TLL ioremap failed\n");
-               ret = -ENOMEM;
-               goto err_usbtll_p2_fck;
+               ret = -EADDRNOTAVAIL;
+               dev_err(dev, "Resource request/ioremap failed:%d\n", ret);
+               return ret;
        }
 
        platform_set_drvdata(pdev, tll);
        pm_runtime_enable(dev);
        pm_runtime_get_sync(dev);
 
-       spin_lock_irqsave(&tll->lock, flags);
-
        ver =  usbtll_read(base, OMAP_USBTLL_REVISION);
        switch (ver) {
        case OMAP_USBTLL_REV1:
-       case OMAP_USBTLL_REV2:
-               count = OMAP_TLL_CHANNEL_COUNT;
+       case OMAP_USBTLL_REV4:
+               tll->nch = OMAP_TLL_CHANNEL_COUNT;
                break;
+       case OMAP_USBTLL_REV2:
        case OMAP_USBTLL_REV3:
-               count = OMAP_REV2_TLL_CHANNEL_COUNT;
+               tll->nch = OMAP_REV2_TLL_CHANNEL_COUNT;
                break;
        default:
-               dev_err(dev, "TLL version failed\n");
-               ret = -ENODEV;
-               goto err_ioremap;
+               tll->nch = OMAP_TLL_CHANNEL_COUNT;
+               dev_dbg(dev,
+                "USB TLL Rev : 0x%x not recognized, assuming %d channels\n",
+                       ver, tll->nch);
+               break;
        }
 
-       if (is_ehci_tll_mode(pdata->port_mode[0]) ||
-           is_ehci_tll_mode(pdata->port_mode[1]) ||
-           is_ehci_tll_mode(pdata->port_mode[2]) ||
-           is_ohci_port(pdata->port_mode[0]) ||
-           is_ohci_port(pdata->port_mode[1]) ||
-           is_ohci_port(pdata->port_mode[2])) {
+       tll->ch_clk = devm_kzalloc(dev, sizeof(struct clk * [tll->nch]),
+                                               GFP_KERNEL);
+       if (!tll->ch_clk) {
+               ret = -ENOMEM;
+               dev_err(dev, "Couldn't allocate memory for channel clocks\n");
+               goto err_clk_alloc;
+       }
+
+       for (i = 0; i < tll->nch; i++) {
+               char clkname[] = "usb_tll_hs_usb_chx_clk";
+
+               snprintf(clkname, sizeof(clkname),
+                                       "usb_tll_hs_usb_ch%d_clk", i);
+               tll->ch_clk[i] = clk_get(dev, clkname);
+
+               if (IS_ERR(tll->ch_clk[i]))
+                       dev_dbg(dev, "can't get clock : %s\n", clkname);
+       }
+
+       needs_tll = false;
+       for (i = 0; i < tll->nch; i++)
+               needs_tll |= omap_usb_mode_needs_tll(pdata->port_mode[i]);
+
+       if (needs_tll) {
 
                /* Program Common TLL register */
                reg = usbtll_read(base, OMAP_TLL_SHARED_CONF);
@@ -292,7 +299,7 @@ static int usbtll_omap_probe(struct platform_device *pdev)
                usbtll_write(base, OMAP_TLL_SHARED_CONF, reg);
 
                /* Enable channels now */
-               for (i = 0; i < count; i++) {
+               for (i = 0; i < tll->nch; i++) {
                        reg = usbtll_read(base, OMAP_TLL_CHANNEL_CONF(i));
 
                        if (is_ohci_port(pdata->port_mode[i])) {
@@ -308,6 +315,15 @@ static int usbtll_omap_probe(struct platform_device *pdev)
                                reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE
                                        | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
                                        | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE);
+                       } else if (pdata->port_mode[i] ==
+                                       OMAP_EHCI_PORT_MODE_HSIC) {
+                               /*
+                                * HSIC Mode requires UTMI port configurations
+                                */
+                               reg |= OMAP_TLL_CHANNEL_CONF_DRVVBUS
+                                | OMAP_TLL_CHANNEL_CONF_CHRGVBUS
+                                | OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI
+                                | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF;
                        } else {
                                continue;
                        }
@@ -320,25 +336,18 @@ static int usbtll_omap_probe(struct platform_device *pdev)
                }
        }
 
-err_ioremap:
-       spin_unlock_irqrestore(&tll->lock, flags);
-       iounmap(base);
        pm_runtime_put_sync(dev);
-       tll_pdev = pdev;
-       if (!ret)
-               goto end;
-       pm_runtime_disable(dev);
+       /* only after this can omap_tll_enable/disable work */
+       spin_lock(&tll_lock);
+       tll_dev = dev;
+       spin_unlock(&tll_lock);
 
-err_usbtll_p2_fck:
-       clk_put(tll->usbtll_p2_fck);
-
-err_usbtll_p1_fck:
-       clk_put(tll->usbtll_p1_fck);
+       return 0;
 
-err_tll:
-       kfree(tll);
+err_clk_alloc:
+       pm_runtime_put_sync(dev);
+       pm_runtime_disable(dev);
 
-end:
        return ret;
 }
 
@@ -351,36 +360,42 @@ end:
 static int usbtll_omap_remove(struct platform_device *pdev)
 {
        struct usbtll_omap *tll = platform_get_drvdata(pdev);
+       int i;
+
+       spin_lock(&tll_lock);
+       tll_dev = NULL;
+       spin_unlock(&tll_lock);
+
+       for (i = 0; i < tll->nch; i++)
+               if (!IS_ERR(tll->ch_clk[i]))
+                       clk_put(tll->ch_clk[i]);
 
-       clk_put(tll->usbtll_p2_fck);
-       clk_put(tll->usbtll_p1_fck);
        pm_runtime_disable(&pdev->dev);
-       kfree(tll);
        return 0;
 }
 
 static int usbtll_runtime_resume(struct device *dev)
 {
        struct usbtll_omap                      *tll = dev_get_drvdata(dev);
-       struct usbtll_omap_platform_data        *pdata = &tll->platdata;
-       unsigned long                           flags;
+       struct usbhs_omap_platform_data         *pdata = tll->pdata;
+       int i;
 
        dev_dbg(dev, "usbtll_runtime_resume\n");
 
-       if (!pdata) {
-               dev_dbg(dev, "missing platform_data\n");
-               return  -ENODEV;
-       }
-
-       spin_lock_irqsave(&tll->lock, flags);
+       for (i = 0; i < tll->nch; i++) {
+               if (omap_usb_mode_needs_tll(pdata->port_mode[i])) {
+                       int r;
 
-       if (is_ehci_tll_mode(pdata->port_mode[0]))
-               clk_enable(tll->usbtll_p1_fck);
-
-       if (is_ehci_tll_mode(pdata->port_mode[1]))
-               clk_enable(tll->usbtll_p2_fck);
+                       if (IS_ERR(tll->ch_clk[i]))
+                               continue;
 
-       spin_unlock_irqrestore(&tll->lock, flags);
+                       r = clk_enable(tll->ch_clk[i]);
+                       if (r) {
+                               dev_err(dev,
+                                "Error enabling ch %d clock: %d\n", i, r);
+                       }
+               }
+       }
 
        return 0;
 }
@@ -388,26 +403,18 @@ static int usbtll_runtime_resume(struct device *dev)
 static int usbtll_runtime_suspend(struct device *dev)
 {
        struct usbtll_omap                      *tll = dev_get_drvdata(dev);
-       struct usbtll_omap_platform_data        *pdata = &tll->platdata;
-       unsigned long                           flags;
+       struct usbhs_omap_platform_data         *pdata = tll->pdata;
+       int i;
 
        dev_dbg(dev, "usbtll_runtime_suspend\n");
 
-       if (!pdata) {
-               dev_dbg(dev, "missing platform_data\n");
-               return  -ENODEV;
+       for (i = 0; i < tll->nch; i++) {
+               if (omap_usb_mode_needs_tll(pdata->port_mode[i])) {
+                       if (!IS_ERR(tll->ch_clk[i]))
+                               clk_disable(tll->ch_clk[i]);
+               }
        }
 
-       spin_lock_irqsave(&tll->lock, flags);
-
-       if (is_ehci_tll_mode(pdata->port_mode[0]))
-               clk_disable(tll->usbtll_p1_fck);
-
-       if (is_ehci_tll_mode(pdata->port_mode[1]))
-               clk_disable(tll->usbtll_p2_fck);
-
-       spin_unlock_irqrestore(&tll->lock, flags);
-
        return 0;
 }
 
@@ -429,21 +436,39 @@ static struct platform_driver usbtll_omap_driver = {
 
 int omap_tll_enable(void)
 {
-       if (!tll_pdev) {
-               pr_err("missing omap usbhs tll platform_data\n");
-               return  -ENODEV;
+       int ret;
+
+       spin_lock(&tll_lock);
+
+       if (!tll_dev) {
+               pr_err("%s: OMAP USB TLL not initialized\n", __func__);
+               ret = -ENODEV;
+       } else {
+               ret = pm_runtime_get_sync(tll_dev);
        }
-       return pm_runtime_get_sync(&tll_pdev->dev);
+
+       spin_unlock(&tll_lock);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(omap_tll_enable);
 
 int omap_tll_disable(void)
 {
-       if (!tll_pdev) {
-               pr_err("missing omap usbhs tll platform_data\n");
-               return  -ENODEV;
+       int ret;
+
+       spin_lock(&tll_lock);
+
+       if (!tll_dev) {
+               pr_err("%s: OMAP USB TLL not initialized\n", __func__);
+               ret = -ENODEV;
+       } else {
+               ret = pm_runtime_put_sync(tll_dev);
        }
-       return pm_runtime_put_sync(&tll_pdev->dev);
+
+       spin_unlock(&tll_lock);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(omap_tll_disable);
 
index 6ffd7a2affdc2df808bad3a75b9389741f415cbc..bbdbc50a3ccadb7ec98d5d6cd6176c36b9d85a50 100644 (file)
@@ -39,6 +39,14 @@ enum palmas_ids {
        PALMAS_USB_ID,
 };
 
+static struct resource palmas_rtc_resources[] = {
+       {
+               .start  = PALMAS_RTC_ALARM_IRQ,
+               .end    = PALMAS_RTC_ALARM_IRQ,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
 static const struct mfd_cell palmas_children[] = {
        {
                .name = "palmas-pmic",
@@ -59,6 +67,8 @@ static const struct mfd_cell palmas_children[] = {
        {
                .name = "palmas-rtc",
                .id = PALMAS_RTC_ID,
+               .resources = &palmas_rtc_resources[0],
+               .num_resources = ARRAY_SIZE(palmas_rtc_resources),
        },
        {
                .name = "palmas-pwrbutton",
@@ -456,8 +466,8 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
 
        ret = mfd_add_devices(palmas->dev, -1,
                              children, ARRAY_SIZE(palmas_children),
-                             NULL, regmap_irq_chip_get_base(palmas->irq_data),
-                             NULL);
+                             NULL, 0,
+                             regmap_irq_get_domain(palmas->irq_data));
        kfree(children);
 
        if (ret < 0)
index 3d3b4addf81a9b73b480ae3874e2675e1678b52b..2a2d31687b72243de84451212ff52198f37ecc29 100644 (file)
@@ -115,14 +115,24 @@ static int rtl8411_card_power_off(struct rtsx_pcr *pcr, int card)
 static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
 {
        u8 mask, val;
+       int err;
 
        mask = (BPP_REG_TUNED18 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_MASK;
-       if (voltage == OUTPUT_3V3)
+       if (voltage == OUTPUT_3V3) {
+               err = rtsx_pci_write_register(pcr,
+                               SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D);
+               if (err < 0)
+                       return err;
                val = (BPP_ASIC_3V3 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_3V3;
-       else if (voltage == OUTPUT_1V8)
+       } else if (voltage == OUTPUT_1V8) {
+               err = rtsx_pci_write_register(pcr,
+                               SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B);
+               if (err < 0)
+                       return err;
                val = (BPP_ASIC_1V8 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_1V8;
-       else
+       } else {
                return -EINVAL;
+       }
 
        return rtsx_pci_write_register(pcr, LDO_CTL, mask, val);
 }
index 98fe0f39463ed1596f1e0881f5d7352349da400d..ec78d9fb08791a9975a825411b6d7a8049f5d801 100644 (file)
@@ -149,10 +149,18 @@ static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
        int err;
 
        if (voltage == OUTPUT_3V3) {
+               err = rtsx_pci_write_register(pcr,
+                               SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D);
+               if (err < 0)
+                       return err;
                err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
                if (err < 0)
                        return err;
        } else if (voltage == OUTPUT_1V8) {
+               err = rtsx_pci_write_register(pcr,
+                               SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B);
+               if (err < 0)
+                       return err;
                err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
                if (err < 0)
                        return err;
diff --git a/drivers/mfd/rts5227.c b/drivers/mfd/rts5227.c
new file mode 100644 (file)
index 0000000..fc831dc
--- /dev/null
@@ -0,0 +1,234 @@
+/* Driver for Realtek PCI-Express card reader
+ *
+ * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * 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, 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Wei WANG <wei_wang@realsil.com.cn>
+ *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
+ *
+ *   Roger Tseng <rogerable@realtek.com>
+ *   No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mfd/rtsx_pci.h>
+
+#include "rtsx_pcr.h"
+
+static int rts5227_extra_init_hw(struct rtsx_pcr *pcr)
+{
+       u16 cap;
+
+       rtsx_pci_init_cmd(pcr);
+
+       /* Configure GPIO as output */
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02);
+       /* Switch LDO3318 source from DV33 to card_3v3 */
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01);
+       /* LED shine disabled, set initial shine cycle period */
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02);
+       /* Configure LTR */
+       pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &cap);
+       if (cap & PCI_EXP_LTR_EN)
+               rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LTR_CTL, 0xFF, 0xA3);
+       /* Configure OBFF */
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OBFF_CFG, 0x03, 0x03);
+       /* Configure force_clock_req
+        * Maybe We should define 0xFF03 as some name
+        */
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, 0xFF03, 0x08, 0x08);
+       /* Correct driving */
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+                       SD30_CLK_DRIVE_SEL, 0xFF, 0x96);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+                       SD30_CMD_DRIVE_SEL, 0xFF, 0x96);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+                       SD30_DAT_DRIVE_SEL, 0xFF, 0x96);
+
+       return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rts5227_optimize_phy(struct rtsx_pcr *pcr)
+{
+       /* Optimize RX sensitivity */
+       return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42);
+}
+
+static int rts5227_turn_on_led(struct rtsx_pcr *pcr)
+{
+       return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02);
+}
+
+static int rts5227_turn_off_led(struct rtsx_pcr *pcr)
+{
+       return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00);
+}
+
+static int rts5227_enable_auto_blink(struct rtsx_pcr *pcr)
+{
+       return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08);
+}
+
+static int rts5227_disable_auto_blink(struct rtsx_pcr *pcr)
+{
+       return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00);
+}
+
+static int rts5227_card_power_on(struct rtsx_pcr *pcr, int card)
+{
+       int err;
+
+       rtsx_pci_init_cmd(pcr);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+                       SD_POWER_MASK, SD_PARTIAL_POWER_ON);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+                       LDO3318_PWR_MASK, 0x02);
+       err = rtsx_pci_send_cmd(pcr, 100);
+       if (err < 0)
+               return err;
+
+       /* To avoid too large in-rush current */
+       udelay(150);
+
+       rtsx_pci_init_cmd(pcr);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+                       SD_POWER_MASK, SD_POWER_ON);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+                       LDO3318_PWR_MASK, 0x06);
+       err = rtsx_pci_send_cmd(pcr, 100);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int rts5227_card_power_off(struct rtsx_pcr *pcr, int card)
+{
+       rtsx_pci_init_cmd(pcr);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+                       SD_POWER_MASK | PMOS_STRG_MASK,
+                       SD_POWER_OFF | PMOS_STRG_400mA);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+                       LDO3318_PWR_MASK, 0X00);
+       return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rts5227_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+       int err;
+       u8 drive_sel;
+
+       if (voltage == OUTPUT_3V3) {
+               err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
+               if (err < 0)
+                       return err;
+               drive_sel = 0x96;
+       } else if (voltage == OUTPUT_1V8) {
+               err = rtsx_pci_write_phy_register(pcr, 0x11, 0x3C02);
+               if (err < 0)
+                       return err;
+               err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C80 | 0x24);
+               if (err < 0)
+                       return err;
+               drive_sel = 0xB3;
+       } else {
+               return -EINVAL;
+       }
+
+       /* set pad drive */
+       rtsx_pci_init_cmd(pcr);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL,
+                       0xFF, drive_sel);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL,
+                       0xFF, drive_sel);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL,
+                       0xFF, drive_sel);
+       return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static const struct pcr_ops rts5227_pcr_ops = {
+       .extra_init_hw = rts5227_extra_init_hw,
+       .optimize_phy = rts5227_optimize_phy,
+       .turn_on_led = rts5227_turn_on_led,
+       .turn_off_led = rts5227_turn_off_led,
+       .enable_auto_blink = rts5227_enable_auto_blink,
+       .disable_auto_blink = rts5227_disable_auto_blink,
+       .card_power_on = rts5227_card_power_on,
+       .card_power_off = rts5227_card_power_off,
+       .switch_output_voltage = rts5227_switch_output_voltage,
+       .cd_deglitch = NULL,
+       .conv_clk_and_div_n = NULL,
+};
+
+/* SD Pull Control Enable:
+ *     SD_DAT[3:0] ==> pull up
+ *     SD_CD       ==> pull up
+ *     SD_WP       ==> pull up
+ *     SD_CMD      ==> pull up
+ *     SD_CLK      ==> pull down
+ */
+static const u32 rts5227_sd_pull_ctl_enable_tbl[] = {
+       RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
+       RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
+       0,
+};
+
+/* SD Pull Control Disable:
+ *     SD_DAT[3:0] ==> pull down
+ *     SD_CD       ==> pull up
+ *     SD_WP       ==> pull down
+ *     SD_CMD      ==> pull down
+ *     SD_CLK      ==> pull down
+ */
+static const u32 rts5227_sd_pull_ctl_disable_tbl[] = {
+       RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+       RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
+       0,
+};
+
+/* MS Pull Control Enable:
+ *     MS CD       ==> pull up
+ *     others      ==> pull down
+ */
+static const u32 rts5227_ms_pull_ctl_enable_tbl[] = {
+       RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
+       RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
+       0,
+};
+
+/* MS Pull Control Disable:
+ *     MS CD       ==> pull up
+ *     others      ==> pull down
+ */
+static const u32 rts5227_ms_pull_ctl_disable_tbl[] = {
+       RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
+       RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
+       0,
+};
+
+void rts5227_init_params(struct rtsx_pcr *pcr)
+{
+       pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
+       pcr->num_slots = 2;
+       pcr->ops = &rts5227_pcr_ops;
+
+       pcr->sd_pull_ctl_enable_tbl = rts5227_sd_pull_ctl_enable_tbl;
+       pcr->sd_pull_ctl_disable_tbl = rts5227_sd_pull_ctl_disable_tbl;
+       pcr->ms_pull_ctl_enable_tbl = rts5227_ms_pull_ctl_enable_tbl;
+       pcr->ms_pull_ctl_disable_tbl = rts5227_ms_pull_ctl_disable_tbl;
+}
index 29d889cbb9c5183262897bc5e29818c536bb227d..58af4dbe358623d2c45385ee5a5e6f31cb04344e 100644 (file)
@@ -119,10 +119,18 @@ static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
        int err;
 
        if (voltage == OUTPUT_3V3) {
+               err = rtsx_pci_write_register(pcr,
+                               SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D);
+               if (err < 0)
+                       return err;
                err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
                if (err < 0)
                        return err;
        } else if (voltage == OUTPUT_1V8) {
+               err = rtsx_pci_write_register(pcr,
+                               SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B);
+               if (err < 0)
+                       return err;
                err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
                if (err < 0)
                        return err;
index 9fc57009e22813fe257481b39352533f2fbd5d45..481a98a10ecde331aca22121427aa9d6ee5c4113 100644 (file)
@@ -55,6 +55,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = {
        { PCI_DEVICE(0x10EC, 0x5209), PCI_CLASS_OTHERS << 16, 0xFF0000 },
        { PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 },
        { PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+       { PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 },
        { 0, }
 };
 
@@ -325,7 +326,6 @@ static void rtsx_pci_add_sg_tbl(struct rtsx_pcr *pcr,
        val = ((u64)addr << 32) | ((u64)len << 12) | option;
 
        put_unaligned_le64(val, ptr);
-       ptr++;
        pcr->sgi++;
 }
 
@@ -591,8 +591,7 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
                u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk)
 {
        int err, clk;
-       u8 N, min_N, max_N, clk_divider;
-       u8 mcu_cnt, div, max_div;
+       u8 n, clk_divider, mcu_cnt, div;
        u8 depth[] = {
                [RTSX_SSC_DEPTH_4M] = SSC_DEPTH_4M,
                [RTSX_SSC_DEPTH_2M] = SSC_DEPTH_2M,
@@ -616,10 +615,6 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
        card_clock /= 1000000;
        dev_dbg(&(pcr->pci->dev), "Switch card clock to %dMHz\n", card_clock);
 
-       min_N = 80;
-       max_N = 208;
-       max_div = CLK_DIV_8;
-
        clk = card_clock;
        if (!initial_mode && double_clk)
                clk = card_clock * 2;
@@ -631,30 +626,30 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
                return 0;
 
        if (pcr->ops->conv_clk_and_div_n)
-               N = (u8)pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N);
+               n = (u8)pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N);
        else
-               N = (u8)(clk - 2);
-       if ((clk <= 2) || (N > max_N))
+               n = (u8)(clk - 2);
+       if ((clk <= 2) || (n > MAX_DIV_N_PCR))
                return -EINVAL;
 
        mcu_cnt = (u8)(125/clk + 3);
        if (mcu_cnt > 15)
                mcu_cnt = 15;
 
-       /* Make sure that the SSC clock div_n is equal or greater than min_N */
+       /* Make sure that the SSC clock div_n is not less than MIN_DIV_N_PCR */
        div = CLK_DIV_1;
-       while ((N < min_N) && (div < max_div)) {
+       while ((n < MIN_DIV_N_PCR) && (div < CLK_DIV_8)) {
                if (pcr->ops->conv_clk_and_div_n) {
-                       int dbl_clk = pcr->ops->conv_clk_and_div_n(N,
+                       int dbl_clk = pcr->ops->conv_clk_and_div_n(n,
                                        DIV_N_TO_CLK) * 2;
-                       N = (u8)pcr->ops->conv_clk_and_div_n(dbl_clk,
+                       n = (u8)pcr->ops->conv_clk_and_div_n(dbl_clk,
                                        CLK_TO_DIV_N);
                } else {
-                       N = (N + 2) * 2 - 2;
+                       n = (n + 2) * 2 - 2;
                }
                div++;
        }
-       dev_dbg(&(pcr->pci->dev), "N = %d, div = %d\n", N, div);
+       dev_dbg(&(pcr->pci->dev), "n = %d, div = %d\n", n, div);
 
        ssc_depth = depth[ssc_depth];
        if (double_clk)
@@ -671,7 +666,7 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2,
                        SSC_DEPTH_MASK, ssc_depth);
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, N);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, n);
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB);
        if (vpclk) {
                rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL,
@@ -713,6 +708,25 @@ int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card)
 }
 EXPORT_SYMBOL_GPL(rtsx_pci_card_power_off);
 
+int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card)
+{
+       unsigned int cd_mask[] = {
+               [RTSX_SD_CARD] = SD_EXIST,
+               [RTSX_MS_CARD] = MS_EXIST
+       };
+
+       if (!pcr->ms_pmos) {
+               /* When using single PMOS, accessing card is not permitted
+                * if the existing card is not the designated one.
+                */
+               if (pcr->card_exist & (~cd_mask[card]))
+                       return -EIO;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_card_exclusive_check);
+
 int rtsx_pci_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
 {
        if (pcr->ops->switch_output_voltage)
@@ -758,7 +772,7 @@ static void rtsx_pci_card_detect(struct work_struct *work)
        struct delayed_work *dwork;
        struct rtsx_pcr *pcr;
        unsigned long flags;
-       unsigned int card_detect = 0;
+       unsigned int card_detect = 0, card_inserted, card_removed;
        u32 irq_status;
 
        dwork = to_delayed_work(work);
@@ -766,25 +780,35 @@ static void rtsx_pci_card_detect(struct work_struct *work)
 
        dev_dbg(&(pcr->pci->dev), "--> %s\n", __func__);
 
+       mutex_lock(&pcr->pcr_mutex);
        spin_lock_irqsave(&pcr->lock, flags);
 
        irq_status = rtsx_pci_readl(pcr, RTSX_BIPR);
        dev_dbg(&(pcr->pci->dev), "irq_status: 0x%08x\n", irq_status);
 
-       if (pcr->card_inserted || pcr->card_removed) {
+       irq_status &= CARD_EXIST;
+       card_inserted = pcr->card_inserted & irq_status;
+       card_removed = pcr->card_removed;
+       pcr->card_inserted = 0;
+       pcr->card_removed = 0;
+
+       spin_unlock_irqrestore(&pcr->lock, flags);
+
+       if (card_inserted || card_removed) {
                dev_dbg(&(pcr->pci->dev),
                                "card_inserted: 0x%x, card_removed: 0x%x\n",
-                               pcr->card_inserted, pcr->card_removed);
+                               card_inserted, card_removed);
 
                if (pcr->ops->cd_deglitch)
-                       pcr->card_inserted = pcr->ops->cd_deglitch(pcr);
+                       card_inserted = pcr->ops->cd_deglitch(pcr);
+
+               card_detect = card_inserted | card_removed;
 
-               card_detect = pcr->card_inserted | pcr->card_removed;
-               pcr->card_inserted = 0;
-               pcr->card_removed = 0;
+               pcr->card_exist |= card_inserted;
+               pcr->card_exist &= ~card_removed;
        }
 
-       spin_unlock_irqrestore(&pcr->lock, flags);
+       mutex_unlock(&pcr->pcr_mutex);
 
        if ((card_detect & SD_EXIST) && pcr->slots[RTSX_SD_CARD].card_event)
                pcr->slots[RTSX_SD_CARD].card_event(
@@ -836,10 +860,6 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
                }
        }
 
-       if (pcr->card_inserted || pcr->card_removed)
-               schedule_delayed_work(&pcr->carddet_work,
-                               msecs_to_jiffies(200));
-
        if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) {
                if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) {
                        pcr->trans_result = TRANS_RESULT_FAIL;
@@ -852,6 +872,10 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
                }
        }
 
+       if (pcr->card_inserted || pcr->card_removed)
+               schedule_delayed_work(&pcr->carddet_work,
+                               msecs_to_jiffies(200));
+
        spin_unlock(&pcr->lock);
        return IRQ_HANDLED;
 }
@@ -974,6 +998,14 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
                        return err;
        }
 
+       /* No CD interrupt if probing driver with card inserted.
+        * So we need to initialize pcr->card_exist here.
+        */
+       if (pcr->ops->cd_deglitch)
+               pcr->card_exist = pcr->ops->cd_deglitch(pcr);
+       else
+               pcr->card_exist = rtsx_pci_readl(pcr, RTSX_BIPR) & CARD_EXIST;
+
        return 0;
 }
 
@@ -997,6 +1029,10 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
        case 0x5289:
                rtl8411_init_params(pcr);
                break;
+
+       case 0x5227:
+               rts5227_init_params(pcr);
+               break;
        }
 
        dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n",
@@ -1030,6 +1066,10 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
                pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device,
                (int)pcidev->revision);
 
+       ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(32));
+       if (ret < 0)
+               return ret;
+
        ret = pci_enable_device(pcidev);
        if (ret)
                return ret;
index 12462c1df1a9dada032e8ca9a1fd729c6147d363..2b3ab8a048237c41c486989c689f60c37b7afe05 100644 (file)
 
 #include <linux/mfd/rtsx_pci.h>
 
+#define MIN_DIV_N_PCR          80
+#define MAX_DIV_N_PCR          208
+
 void rts5209_init_params(struct rtsx_pcr *pcr);
 void rts5229_init_params(struct rtsx_pcr *pcr);
 void rtl8411_init_params(struct rtsx_pcr *pcr);
+void rts5227_init_params(struct rtsx_pcr *pcr);
 
 #endif
index 3f10591ea94e9d2242bf8b79a6689703c93ed238..61aea6381cdf37675595dd3a9a7173ea3fc69eb9 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
 
 static struct platform_driver syscon_driver;
 
index 409afa23d5dc0c2f4bf42278c76d780862c3cec3..5ad4b772b09797bec97c9759bb9c80e609102651 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/of_device.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/tps6507x.h>
 
@@ -116,11 +117,19 @@ static const struct i2c_device_id tps6507x_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, tps6507x_i2c_id);
 
+#ifdef CONFIG_OF
+static struct of_device_id tps6507x_of_match[] = {
+       {.compatible = "ti,tps6507x", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, tps6507x_of_match);
+#endif
 
 static struct i2c_driver tps6507x_i2c_driver = {
        .driver = {
                   .name = "tps6507x",
                   .owner = THIS_MODULE,
+                  .of_match_table = of_match_ptr(tps6507x_of_match),
        },
        .probe = tps6507x_i2c_probe,
        .remove = tps6507x_i2c_remove,
index 8d12a8e00d9c97ecfbfb477bd73515749ca5e663..98edb5be85c6b39d299d4dffdac7a081d60b1d83 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/i2c.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/tps65090.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/err.h>
 
 #define NUM_INT_REG 2
@@ -148,18 +150,31 @@ static const struct regmap_config tps65090_regmap_config = {
        .volatile_reg = is_volatile_reg,
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id tps65090_of_match[] = {
+       { .compatible = "ti,tps65090",},
+       {},
+};
+MODULE_DEVICE_TABLE(of, tps65090_of_match);
+#endif
+
 static int tps65090_i2c_probe(struct i2c_client *client,
                                        const struct i2c_device_id *id)
 {
        struct tps65090_platform_data *pdata = client->dev.platform_data;
+       int irq_base = 0;
        struct tps65090 *tps65090;
        int ret;
 
-       if (!pdata) {
-               dev_err(&client->dev, "tps65090 requires platform data\n");
+       if (!pdata && !client->dev.of_node) {
+               dev_err(&client->dev,
+                       "tps65090 requires platform data or of_node\n");
                return -EINVAL;
        }
 
+       if (pdata)
+               irq_base = pdata->irq_base;
+
        tps65090 = devm_kzalloc(&client->dev, sizeof(*tps65090), GFP_KERNEL);
        if (!tps65090) {
                dev_err(&client->dev, "mem alloc for tps65090 failed\n");
@@ -178,7 +193,7 @@ static int tps65090_i2c_probe(struct i2c_client *client,
 
        if (client->irq) {
                ret = regmap_add_irq_chip(tps65090->rmap, client->irq,
-                       IRQF_ONESHOT | IRQF_TRIGGER_LOW, pdata->irq_base,
+                       IRQF_ONESHOT | IRQF_TRIGGER_LOW, irq_base,
                        &tps65090_irq_chip, &tps65090->irq_data);
                        if (ret) {
                                dev_err(&client->dev,
@@ -189,7 +204,7 @@ static int tps65090_i2c_probe(struct i2c_client *client,
 
        ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
                ARRAY_SIZE(tps65090s), NULL,
-               regmap_irq_chip_get_base(tps65090->irq_data), NULL);
+               0, regmap_irq_get_domain(tps65090->irq_data));
        if (ret) {
                dev_err(&client->dev, "add mfd devices failed with err: %d\n",
                        ret);
@@ -215,28 +230,6 @@ static int tps65090_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int tps65090_suspend(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       if (client->irq)
-               disable_irq(client->irq);
-       return 0;
-}
-
-static int tps65090_resume(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       if (client->irq)
-               enable_irq(client->irq);
-       return 0;
-}
-#endif
-
-static const struct dev_pm_ops tps65090_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(tps65090_suspend, tps65090_resume)
-};
-
 static const struct i2c_device_id tps65090_id_table[] = {
        { "tps65090", 0 },
        { },
@@ -247,7 +240,7 @@ static struct i2c_driver tps65090_driver = {
        .driver = {
                .name   = "tps65090",
                .owner  = THIS_MODULE,
-               .pm     = &tps65090_pm_ops,
+               .of_match_table = of_match_ptr(tps65090_of_match),
        },
        .probe          = tps65090_i2c_probe,
        .remove         = tps65090_i2c_remove,
index 4f3baadd0038e04f44d0a88856218edee23e5646..89ab4d9706431ba26fbfcc3a68e7a513daa8e164 100644 (file)
 
 /* Triton Core internal information (BEGIN) */
 
-#define TWL_NUM_SLAVES         4
-
-#define SUB_CHIP_ID0 0
-#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
-
 /* Base Address defns for twl4030_map[] */
 
 /* subchip/slave 0 - USB ID */
 #define TWL4030_BASEADD_MADC           0x0000
 #define TWL4030_BASEADD_MAIN_CHARGE    0x0074
 #define TWL4030_BASEADD_PRECHARGE      0x00AA
-#define TWL4030_BASEADD_PWM0           0x00F8
-#define TWL4030_BASEADD_PWM1           0x00FB
-#define TWL4030_BASEADD_PWMA           0x00EF
-#define TWL4030_BASEADD_PWMB           0x00F1
+#define TWL4030_BASEADD_PWM            0x00F8
 #define TWL4030_BASEADD_KEYPAD         0x00D2
 
 #define TWL5031_BASEADD_ACCESSORY      0x0074 /* Replaces Main Charge */
 
 /* subchip/slave 0 0x48 - POWER */
 #define TWL6030_BASEADD_RTC            0x0000
-#define TWL6030_BASEADD_MEM            0x0017
+#define TWL6030_BASEADD_SECURED_REG    0x0017
 #define TWL6030_BASEADD_PM_MASTER      0x001F
 #define TWL6030_BASEADD_PM_SLAVE_MISC  0x0030 /* PM_RECEIVER */
 #define TWL6030_BASEADD_PM_MISC                0x00E2
 #define TWL6030_BASEADD_PIH            0x00D0
 #define TWL6030_BASEADD_CHARGER                0x00E0
 #define TWL6025_BASEADD_CHARGER                0x00DA
+#define TWL6030_BASEADD_LED            0x00F4
 
 /* subchip/slave 2 0x4A - DFT */
 #define TWL6030_BASEADD_DIEID          0x00C0
 
 /*----------------------------------------------------------------------*/
 
-/* is driver active, bound to a chip? */
-static bool inuse;
-
-/* TWL IDCODE Register value */
-static u32 twl_idcode;
-
-static unsigned int twl_id;
-unsigned int twl_rev(void)
-{
-       return twl_id;
-}
-EXPORT_SYMBOL(twl_rev);
-
 /* Structure for each TWL4030/TWL6030 Slave */
 struct twl_client {
        struct i2c_client *client;
        struct regmap *regmap;
 };
 
-static struct twl_client twl_modules[TWL_NUM_SLAVES];
-
 /* mapping the module id to slave id and base address */
 struct twl_mapping {
        unsigned char sid;      /* Slave ID */
        unsigned char base;     /* base address */
 };
-static struct twl_mapping *twl_map;
+
+struct twl_private {
+       bool ready; /* The core driver is ready to be used */
+       u32 twl_idcode; /* TWL IDCODE Register value */
+       unsigned int twl_id;
+
+       struct twl_mapping *twl_map;
+       struct twl_client *twl_modules;
+};
+
+static struct twl_private *twl_priv;
 
 static struct twl_mapping twl4030_map[] = {
        /*
@@ -188,34 +171,33 @@ static struct twl_mapping twl4030_map[] = {
         * so they continue to match the order in this table.
         */
 
+       /* Common IPs */
        { 0, TWL4030_BASEADD_USB },
+       { 1, TWL4030_BASEADD_PIH },
+       { 2, TWL4030_BASEADD_MAIN_CHARGE },
+       { 3, TWL4030_BASEADD_PM_MASTER },
+       { 3, TWL4030_BASEADD_PM_RECEIVER },
+
+       { 3, TWL4030_BASEADD_RTC },
+       { 2, TWL4030_BASEADD_PWM },
+       { 2, TWL4030_BASEADD_LED },
+       { 3, TWL4030_BASEADD_SECURED_REG },
+
+       /* TWL4030 specific IPs */
        { 1, TWL4030_BASEADD_AUDIO_VOICE },
        { 1, TWL4030_BASEADD_GPIO },
        { 1, TWL4030_BASEADD_INTBR },
-       { 1, TWL4030_BASEADD_PIH },
-
        { 1, TWL4030_BASEADD_TEST },
        { 2, TWL4030_BASEADD_KEYPAD },
+
        { 2, TWL4030_BASEADD_MADC },
        { 2, TWL4030_BASEADD_INTERRUPTS },
-       { 2, TWL4030_BASEADD_LED },
-
-       { 2, TWL4030_BASEADD_MAIN_CHARGE },
        { 2, TWL4030_BASEADD_PRECHARGE },
-       { 2, TWL4030_BASEADD_PWM0 },
-       { 2, TWL4030_BASEADD_PWM1 },
-       { 2, TWL4030_BASEADD_PWMA },
-
-       { 2, TWL4030_BASEADD_PWMB },
-       { 2, TWL5031_BASEADD_ACCESSORY },
-       { 2, TWL5031_BASEADD_INTERRUPTS },
        { 3, TWL4030_BASEADD_BACKUP },
        { 3, TWL4030_BASEADD_INT },
 
-       { 3, TWL4030_BASEADD_PM_MASTER },
-       { 3, TWL4030_BASEADD_PM_RECEIVER },
-       { 3, TWL4030_BASEADD_RTC },
-       { 3, TWL4030_BASEADD_SECURED_REG },
+       { 2, TWL5031_BASEADD_ACCESSORY },
+       { 2, TWL5031_BASEADD_INTERRUPTS },
 };
 
 static struct regmap_config twl4030_regmap_config[4] = {
@@ -251,35 +233,25 @@ static struct twl_mapping twl6030_map[] = {
         * <linux/i2c/twl.h> defines for TWL4030_MODULE_*
         * so they continue to match the order in this table.
         */
-       { SUB_CHIP_ID1, TWL6030_BASEADD_USB },
-       { 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 },
-
-       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
-       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
-       { SUB_CHIP_ID1, TWL6030_BASEADD_GPADC_CTRL },
-       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
-       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
-
-       { SUB_CHIP_ID1, TWL6030_BASEADD_CHARGER },
-       { SUB_CHIP_ID1, TWL6030_BASEADD_GASGAUGE },
-       { SUB_CHIP_ID1, TWL6030_BASEADD_PWM },
-       { SUB_CHIP_ID0, TWL6030_BASEADD_ZERO },
-       { SUB_CHIP_ID1, TWL6030_BASEADD_ZERO },
-
-       { SUB_CHIP_ID2, TWL6030_BASEADD_ZERO },
-       { SUB_CHIP_ID2, TWL6030_BASEADD_ZERO },
-       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
-       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
-       { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
-
-       { SUB_CHIP_ID0, TWL6030_BASEADD_PM_MASTER },
-       { SUB_CHIP_ID0, TWL6030_BASEADD_PM_SLAVE_MISC },
-       { SUB_CHIP_ID0, TWL6030_BASEADD_RTC },
-       { SUB_CHIP_ID0, TWL6030_BASEADD_MEM },
-       { SUB_CHIP_ID1, TWL6025_BASEADD_CHARGER },
+
+       /* Common IPs */
+       { 1, TWL6030_BASEADD_USB },
+       { 1, TWL6030_BASEADD_PIH },
+       { 1, TWL6030_BASEADD_CHARGER },
+       { 0, TWL6030_BASEADD_PM_MASTER },
+       { 0, TWL6030_BASEADD_PM_SLAVE_MISC },
+
+       { 0, TWL6030_BASEADD_RTC },
+       { 1, TWL6030_BASEADD_PWM },
+       { 1, TWL6030_BASEADD_LED },
+       { 0, TWL6030_BASEADD_SECURED_REG },
+
+       /* TWL6030 specific IPs */
+       { 0, TWL6030_BASEADD_ZERO },
+       { 1, TWL6030_BASEADD_ZERO },
+       { 2, TWL6030_BASEADD_ZERO },
+       { 1, TWL6030_BASEADD_GPADC_CTRL },
+       { 1, TWL6030_BASEADD_GASGAUGE },
 };
 
 static struct regmap_config twl6030_regmap_config[3] = {
@@ -305,8 +277,30 @@ static struct regmap_config twl6030_regmap_config[3] = {
 
 /*----------------------------------------------------------------------*/
 
+static inline int twl_get_num_slaves(void)
+{
+       if (twl_class_is_4030())
+               return 4; /* TWL4030 class have four slave address */
+       else
+               return 3; /* TWL6030 class have three slave address */
+}
+
+static inline int twl_get_last_module(void)
+{
+       if (twl_class_is_4030())
+               return TWL4030_MODULE_LAST;
+       else
+               return TWL6030_MODULE_LAST;
+}
+
 /* Exported Functions */
 
+unsigned int twl_rev(void)
+{
+       return twl_priv ? twl_priv->twl_id : 0;
+}
+EXPORT_SYMBOL(twl_rev);
+
 /**
  * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
  * @mod_no: module number
@@ -314,9 +308,6 @@ static struct regmap_config twl6030_regmap_config[3] = {
  * @reg: register address (just offset will do)
  * @num_bytes: number of bytes to transfer
  *
- * IMPORTANT: for 'value' parameter: Allocate value num_bytes+1 and
- * valid data starts at Offset 1.
- *
  * Returns the result of operation - 0 is success
  */
 int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
@@ -325,24 +316,21 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
        int sid;
        struct twl_client *twl;
 
-       if (unlikely(mod_no >= TWL_MODULE_LAST)) {
-               pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
-               return -EPERM;
-       }
-       if (unlikely(!inuse)) {
+       if (unlikely(!twl_priv || !twl_priv->ready)) {
                pr_err("%s: not initialized\n", DRIVER_NAME);
                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;
+       if (unlikely(mod_no >= twl_get_last_module())) {
+               pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
+               return -EPERM;
        }
-       twl = &twl_modules[sid];
 
-       ret = regmap_bulk_write(twl->regmap, twl_map[mod_no].base + reg,
-                               value, num_bytes);
+       sid = twl_priv->twl_map[mod_no].sid;
+       twl = &twl_priv->twl_modules[sid];
+
+       ret = regmap_bulk_write(twl->regmap,
+                               twl_priv->twl_map[mod_no].base + reg, value,
+                               num_bytes);
 
        if (ret)
                pr_err("%s: Write failed (mod %d, reg 0x%02x count %d)\n",
@@ -367,24 +355,21 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
        int sid;
        struct twl_client *twl;
 
-       if (unlikely(mod_no >= TWL_MODULE_LAST)) {
-               pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
-               return -EPERM;
-       }
-       if (unlikely(!inuse)) {
+       if (unlikely(!twl_priv || !twl_priv->ready)) {
                pr_err("%s: not initialized\n", DRIVER_NAME);
                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;
+       if (unlikely(mod_no >= twl_get_last_module())) {
+               pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
+               return -EPERM;
        }
-       twl = &twl_modules[sid];
 
-       ret = regmap_bulk_read(twl->regmap, twl_map[mod_no].base + reg,
-                              value, num_bytes);
+       sid = twl_priv->twl_map[mod_no].sid;
+       twl = &twl_priv->twl_modules[sid];
+
+       ret = regmap_bulk_read(twl->regmap,
+                              twl_priv->twl_map[mod_no].base + reg, value,
+                              num_bytes);
 
        if (ret)
                pr_err("%s: Read failed (mod %d, reg 0x%02x count %d)\n",
@@ -394,34 +379,6 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
 }
 EXPORT_SYMBOL(twl_i2c_read);
 
-/**
- * twl_i2c_write_u8 - Writes a 8 bit register in TWL4030/TWL5030/TWL60X0
- * @mod_no: module number
- * @value: the value to be written 8 bit
- * @reg: register address (just offset will do)
- *
- * Returns result of operation - 0 is success
- */
-int twl_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
-{
-       return twl_i2c_write(mod_no, &value, reg, 1);
-}
-EXPORT_SYMBOL(twl_i2c_write_u8);
-
-/**
- * twl_i2c_read_u8 - Reads a 8 bit register from TWL4030/TWL5030/TWL60X0
- * @mod_no: module number
- * @value: the value read 8 bit
- * @reg: register address (just offset will do)
- *
- * Returns result of operation - 0 is success
- */
-int twl_i2c_read_u8(u8 mod_no, u8 *value, u8 reg)
-{
-       return twl_i2c_read(mod_no, value, reg, 1);
-}
-EXPORT_SYMBOL(twl_i2c_read_u8);
-
 /*----------------------------------------------------------------------*/
 
 /**
@@ -440,7 +397,7 @@ static int twl_read_idcode_register(void)
                goto fail;
        }
 
-       err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_idcode),
+       err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_priv->twl_idcode),
                                                REG_IDCODE_7_0, 4);
        if (err) {
                pr_err("TWL4030: unable to read IDCODE -%d\n", err);
@@ -461,7 +418,7 @@ fail:
  */
 int twl_get_type(void)
 {
-       return TWL_SIL_TYPE(twl_idcode);
+       return TWL_SIL_TYPE(twl_priv->twl_idcode);
 }
 EXPORT_SYMBOL_GPL(twl_get_type);
 
@@ -472,7 +429,7 @@ EXPORT_SYMBOL_GPL(twl_get_type);
  */
 int twl_get_version(void)
 {
-       return TWL_SIL_REV(twl_idcode);
+       return TWL_SIL_REV(twl_priv->twl_idcode);
 }
 EXPORT_SYMBOL_GPL(twl_get_version);
 
@@ -509,13 +466,20 @@ int twl_get_hfclk_rate(void)
 EXPORT_SYMBOL_GPL(twl_get_hfclk_rate);
 
 static struct device *
-add_numbered_child(unsigned chip, const char *name, int num,
+add_numbered_child(unsigned mod_no, const char *name, int num,
                void *pdata, unsigned pdata_len,
                bool can_wakeup, int irq0, int irq1)
 {
        struct platform_device  *pdev;
-       struct twl_client       *twl = &twl_modules[chip];
-       int                     status;
+       struct twl_client       *twl;
+       int                     status, sid;
+
+       if (unlikely(mod_no >= twl_get_last_module())) {
+               pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
+               return ERR_PTR(-EPERM);
+       }
+       sid = twl_priv->twl_map[mod_no].sid;
+       twl = &twl_priv->twl_modules[sid];
 
        pdev = platform_device_alloc(name, num);
        if (!pdev) {
@@ -560,11 +524,11 @@ err:
        return &pdev->dev;
 }
 
-static inline struct device *add_child(unsigned chip, const char *name,
+static inline struct device *add_child(unsigned mod_no, const char *name,
                void *pdata, unsigned pdata_len,
                bool can_wakeup, int irq0, int irq1)
 {
-       return add_numbered_child(chip, name, -1, pdata, pdata_len,
+       return add_numbered_child(mod_no, name, -1, pdata, pdata_len,
                can_wakeup, irq0, irq1);
 }
 
@@ -573,7 +537,6 @@ add_regulator_linked(int num, struct regulator_init_data *pdata,
                struct regulator_consumer_supply *consumers,
                unsigned num_consumers, unsigned long features)
 {
-       unsigned sub_chip_id;
        struct twl_regulator_driver_data drv_data;
 
        /* regulator framework demands init_data ... */
@@ -600,8 +563,7 @@ add_regulator_linked(int num, struct regulator_init_data *pdata,
        }
 
        /* NOTE:  we currently ignore regulator IRQs, e.g. for short circuits */
-       sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid;
-       return add_numbered_child(sub_chip_id, "twl_reg", num,
+       return add_numbered_child(TWL_MODULE_PM_MASTER, "twl_reg", num,
                pdata, sizeof(*pdata), false, 0, 0);
 }
 
@@ -623,10 +585,9 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
                unsigned long features)
 {
        struct device   *child;
-       unsigned sub_chip_id;
 
        if (IS_ENABLED(CONFIG_GPIO_TWL4030) && pdata->gpio) {
-               child = add_child(SUB_CHIP_ID1, "twl4030_gpio",
+               child = add_child(TWL4030_MODULE_GPIO, "twl4030_gpio",
                                pdata->gpio, sizeof(*pdata->gpio),
                                false, irq_base + GPIO_INTR_OFFSET, 0);
                if (IS_ERR(child))
@@ -634,7 +595,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
        }
 
        if (IS_ENABLED(CONFIG_KEYBOARD_TWL4030) && pdata->keypad) {
-               child = add_child(SUB_CHIP_ID2, "twl4030_keypad",
+               child = add_child(TWL4030_MODULE_KEYPAD, "twl4030_keypad",
                                pdata->keypad, sizeof(*pdata->keypad),
                                true, irq_base + KEYPAD_INTR_OFFSET, 0);
                if (IS_ERR(child))
@@ -643,7 +604,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
 
        if (IS_ENABLED(CONFIG_TWL4030_MADC) && pdata->madc &&
            twl_class_is_4030()) {
-               child = add_child(SUB_CHIP_ID2, "twl4030_madc",
+               child = add_child(TWL4030_MODULE_MADC, "twl4030_madc",
                                pdata->madc, sizeof(*pdata->madc),
                                true, irq_base + MADC_INTR_OFFSET, 0);
                if (IS_ERR(child))
@@ -658,22 +619,21 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
                 * Eventually, Linux might become more aware of such
                 * HW security concerns, and "least privilege".
                 */
-               sub_chip_id = twl_map[TWL_MODULE_RTC].sid;
-               child = add_child(sub_chip_id, "twl_rtc", NULL, 0,
+               child = add_child(TWL_MODULE_RTC, "twl_rtc", NULL, 0,
                                true, irq_base + RTC_INTR_OFFSET, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
 
        if (IS_ENABLED(CONFIG_PWM_TWL)) {
-               child = add_child(SUB_CHIP_ID1, "twl-pwm", NULL, 0,
+               child = add_child(TWL_MODULE_PWM, "twl-pwm", NULL, 0,
                                  false, 0, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
 
        if (IS_ENABLED(CONFIG_PWM_TWL_LED)) {
-               child = add_child(SUB_CHIP_ID1, "twl-pwmled", NULL, 0,
+               child = add_child(TWL_MODULE_LED, "twl-pwmled", NULL, 0,
                                  false, 0, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
@@ -725,7 +685,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
 
                }
 
-               child = add_child(SUB_CHIP_ID0, "twl4030_usb",
+               child = add_child(TWL_MODULE_USB, "twl4030_usb",
                                pdata->usb, sizeof(*pdata->usb), true,
                                /* irq0 = USB_PRES, irq1 = USB */
                                irq_base + USB_PRES_INTR_OFFSET,
@@ -774,7 +734,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
 
                pdata->usb->features = features;
 
-               child = add_child(SUB_CHIP_ID0, "twl6030_usb",
+               child = add_child(TWL_MODULE_USB, "twl6030_usb",
                        pdata->usb, sizeof(*pdata->usb), true,
                        /* irq1 = VBUS_PRES, irq0 = USB ID */
                        irq_base + USBOTG_INTR_OFFSET,
@@ -799,22 +759,22 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
        }
 
        if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) {
-               child = add_child(SUB_CHIP_ID3, "twl4030_wdt", NULL, 0,
-                                 false, 0, 0);
+               child = add_child(TWL_MODULE_PM_RECEIVER, "twl4030_wdt", NULL,
+                                 0, false, 0, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
 
        if (IS_ENABLED(CONFIG_INPUT_TWL4030_PWRBUTTON) && twl_class_is_4030()) {
-               child = add_child(SUB_CHIP_ID3, "twl4030_pwrbutton", NULL, 0,
-                                 true, irq_base + 8 + 0, 0);
+               child = add_child(TWL_MODULE_PM_MASTER, "twl4030_pwrbutton",
+                                 NULL, 0, true, irq_base + 8 + 0, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
 
        if (IS_ENABLED(CONFIG_MFD_TWL4030_AUDIO) && pdata->audio &&
            twl_class_is_4030()) {
-               child = add_child(SUB_CHIP_ID1, "twl4030-audio",
+               child = add_child(TWL4030_MODULE_AUDIO_VOICE, "twl4030-audio",
                                pdata->audio, sizeof(*pdata->audio),
                                false, 0, 0);
                if (IS_ERR(child))
@@ -1054,7 +1014,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
 
        if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci &&
                        !(features & (TPS_SUBSET | TWL5031))) {
-               child = add_child(SUB_CHIP_ID3, "twl4030_bci",
+               child = add_child(TWL_MODULE_MAIN_CHARGE, "twl4030_bci",
                                pdata->bci, sizeof(*pdata->bci), false,
                                /* irq0 = CHG_PRES, irq1 = BCI */
                                irq_base + BCI_PRES_INTR_OFFSET,
@@ -1145,25 +1105,23 @@ static int twl_remove(struct i2c_client *client)
        unsigned i, num_slaves;
        int status;
 
-       if (twl_class_is_4030()) {
+       if (twl_class_is_4030())
                status = twl4030_exit_irq();
-               num_slaves = TWL_NUM_SLAVES;
-       } else {
+       else
                status = twl6030_exit_irq();
-               num_slaves = TWL_NUM_SLAVES - 1;
-       }
 
        if (status < 0)
                return status;
 
+       num_slaves = twl_get_num_slaves();
        for (i = 0; i < num_slaves; i++) {
-               struct twl_client       *twl = &twl_modules[i];
+               struct twl_client       *twl = &twl_priv->twl_modules[i];
 
                if (twl->client && twl->client != client)
                        i2c_unregister_device(twl->client);
-               twl_modules[i].client = NULL;
+               twl->client = NULL;
        }
-       inuse = false;
+       twl_priv->ready = false;
        return 0;
 }
 
@@ -1179,6 +1137,17 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
        int                             status;
        unsigned                        i, num_slaves;
 
+       if (!node && !pdata) {
+               dev_err(&client->dev, "no platform data\n");
+               return -EINVAL;
+       }
+
+       if (twl_priv) {
+               dev_dbg(&client->dev, "only one instance of %s allowed\n",
+                       DRIVER_NAME);
+               return -EBUSY;
+       }
+
        pdev = platform_device_alloc(DRIVER_NAME, -1);
        if (!pdev) {
                dev_err(&client->dev, "can't alloc pdev\n");
@@ -1191,54 +1160,44 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
                return status;
        }
 
-       if (node && !pdata) {
-               /*
-                * XXX: Temporary pdata until the information is correctly
-                * retrieved by every TWL modules from DT.
-                */
-               pdata = devm_kzalloc(&client->dev,
-                                    sizeof(struct twl4030_platform_data),
-                                    GFP_KERNEL);
-               if (!pdata) {
-                       status = -ENOMEM;
-                       goto free;
-               }
-       }
-
-       if (!pdata) {
-               dev_dbg(&client->dev, "no platform data?\n");
-               status = -EINVAL;
-               goto free;
-       }
-
-       platform_set_drvdata(pdev, pdata);
-
        if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
                dev_dbg(&client->dev, "can't talk I2C?\n");
                status = -EIO;
                goto free;
        }
 
-       if (inuse) {
-               dev_dbg(&client->dev, "driver is already in use\n");
-               status = -EBUSY;
+       twl_priv = devm_kzalloc(&client->dev, sizeof(struct twl_private),
+                               GFP_KERNEL);
+       if (!twl_priv) {
+               status = -ENOMEM;
                goto free;
        }
 
        if ((id->driver_data) & TWL6030_CLASS) {
-               twl_id = TWL6030_CLASS_ID;
-               twl_map = &twl6030_map[0];
+               twl_priv->twl_id = TWL6030_CLASS_ID;
+               twl_priv->twl_map = &twl6030_map[0];
+               /* The charger base address is different in twl6025 */
+               if ((id->driver_data) & TWL6025_SUBCLASS)
+                       twl_priv->twl_map[TWL_MODULE_MAIN_CHARGE].base =
+                                                       TWL6025_BASEADD_CHARGER;
                twl_regmap_config = twl6030_regmap_config;
-               num_slaves = TWL_NUM_SLAVES - 1;
        } else {
-               twl_id = TWL4030_CLASS_ID;
-               twl_map = &twl4030_map[0];
+               twl_priv->twl_id = TWL4030_CLASS_ID;
+               twl_priv->twl_map = &twl4030_map[0];
                twl_regmap_config = twl4030_regmap_config;
-               num_slaves = TWL_NUM_SLAVES;
+       }
+
+       num_slaves = twl_get_num_slaves();
+       twl_priv->twl_modules = devm_kzalloc(&client->dev,
+                                        sizeof(struct twl_client) * num_slaves,
+                                        GFP_KERNEL);
+       if (!twl_priv->twl_modules) {
+               status = -ENOMEM;
+               goto free;
        }
 
        for (i = 0; i < num_slaves; i++) {
-               struct twl_client *twl = &twl_modules[i];
+               struct twl_client *twl = &twl_priv->twl_modules[i];
 
                if (i == 0) {
                        twl->client = client;
@@ -1264,19 +1223,19 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
                }
        }
 
-       inuse = true;
+       twl_priv->ready = true;
 
        /* setup clock framework */
-       clocks_init(&pdev->dev, pdata->clock);
+       clocks_init(&pdev->dev, pdata ? pdata->clock : NULL);
 
        /* read TWL IDCODE Register */
-       if (twl_id == TWL4030_CLASS_ID) {
+       if (twl_class_is_4030()) {
                status = twl_read_idcode_register();
                WARN(status < 0, "Error: reading twl_idcode register value\n");
        }
 
        /* load power event scripts */
-       if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power)
+       if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata && pdata->power)
                twl4030_power_init(pdata->power);
 
        /* Maybe init the T2 Interrupt subsystem */
@@ -1308,10 +1267,9 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
                twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
        }
 
-       status = -ENODEV;
        if (node)
                status = of_platform_populate(node, NULL, NULL, &client->dev);
-       if (status)
+       else
                status = add_children(pdata, irq_base, id->driver_data);
 
 fail:
index 558c2928f2613f9011b00dafcbac5da71e0551d4..bf75e967a1f304f1b102d275464353c2067319b4 100644 (file)
@@ -49,6 +49,8 @@
 #define SYS_ID_HBI_SHIFT       16
 #define SYS_PROCIDx_HBI_SHIFT  0
 
+#define SYS_LED_LED(n)         (1 << (n))
+
 #define SYS_MCI_CARDIN         (1 << 0)
 #define SYS_MCI_WPROT          (1 << 1)
 
@@ -336,34 +338,40 @@ void __init vexpress_sysreg_early_init(void __iomem *base)
 
 void __init vexpress_sysreg_of_early_init(void)
 {
-       struct device_node *node = of_find_compatible_node(NULL, NULL,
-                       "arm,vexpress-sysreg");
+       struct device_node *node;
+
+       if (vexpress_sysreg_base)
+               return;
 
+       node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg");
        if (node) {
                vexpress_sysreg_base = of_iomap(node, 0);
                vexpress_sysreg_setup(node);
-       } else {
-               pr_info("vexpress-sysreg: No Device Tree node found.");
        }
 }
 
 
+#define VEXPRESS_SYSREG_GPIO(_name, _reg, _value) \
+       [VEXPRESS_GPIO_##_name] = { \
+               .reg = _reg, \
+               .value = _reg##_##_value, \
+       }
+
 static struct vexpress_sysreg_gpio {
        unsigned long reg;
        u32 value;
 } vexpress_sysreg_gpios[] = {
-       [VEXPRESS_GPIO_MMC_CARDIN] = {
-               .reg = SYS_MCI,
-               .value = SYS_MCI_CARDIN,
-       },
-       [VEXPRESS_GPIO_MMC_WPROT] = {
-               .reg = SYS_MCI,
-               .value = SYS_MCI_WPROT,
-       },
-       [VEXPRESS_GPIO_FLASH_WPn] = {
-               .reg = SYS_FLASH,
-               .value = SYS_FLASH_WPn,
-       },
+       VEXPRESS_SYSREG_GPIO(MMC_CARDIN,        SYS_MCI,        CARDIN),
+       VEXPRESS_SYSREG_GPIO(MMC_WPROT,         SYS_MCI,        WPROT),
+       VEXPRESS_SYSREG_GPIO(FLASH_WPn,         SYS_FLASH,      WPn),
+       VEXPRESS_SYSREG_GPIO(LED0,              SYS_LED,        LED(0)),
+       VEXPRESS_SYSREG_GPIO(LED1,              SYS_LED,        LED(1)),
+       VEXPRESS_SYSREG_GPIO(LED2,              SYS_LED,        LED(2)),
+       VEXPRESS_SYSREG_GPIO(LED3,              SYS_LED,        LED(3)),
+       VEXPRESS_SYSREG_GPIO(LED4,              SYS_LED,        LED(4)),
+       VEXPRESS_SYSREG_GPIO(LED5,              SYS_LED,        LED(5)),
+       VEXPRESS_SYSREG_GPIO(LED6,              SYS_LED,        LED(6)),
+       VEXPRESS_SYSREG_GPIO(LED7,              SYS_LED,        LED(7)),
 };
 
 static int vexpress_sysreg_gpio_direction_input(struct gpio_chip *chip,
@@ -372,12 +380,6 @@ static int vexpress_sysreg_gpio_direction_input(struct gpio_chip *chip,
        return 0;
 }
 
-static int vexpress_sysreg_gpio_direction_output(struct gpio_chip *chip,
-                                               unsigned offset, int value)
-{
-       return 0;
-}
-
 static int vexpress_sysreg_gpio_get(struct gpio_chip *chip,
                                       unsigned offset)
 {
@@ -401,6 +403,14 @@ static void vexpress_sysreg_gpio_set(struct gpio_chip *chip,
        writel(reg_value, vexpress_sysreg_base + gpio->reg);
 }
 
+static int vexpress_sysreg_gpio_direction_output(struct gpio_chip *chip,
+                                               unsigned offset, int value)
+{
+       vexpress_sysreg_gpio_set(chip, offset, value);
+
+       return 0;
+}
+
 static struct gpio_chip vexpress_sysreg_gpio_chip = {
        .label = "vexpress-sysreg",
        .direction_input = vexpress_sysreg_gpio_direction_input,
@@ -412,6 +422,30 @@ static struct gpio_chip vexpress_sysreg_gpio_chip = {
 };
 
 
+#define VEXPRESS_SYSREG_GREEN_LED(_name, _default_trigger, _gpio) \
+       { \
+               .name = "v2m:green:"_name, \
+               .default_trigger = _default_trigger, \
+               .gpio = VEXPRESS_GPIO_##_gpio, \
+       }
+
+struct gpio_led vexpress_sysreg_leds[] = {
+       VEXPRESS_SYSREG_GREEN_LED("user1",      "heartbeat",    LED0),
+       VEXPRESS_SYSREG_GREEN_LED("user2",      "mmc0",         LED1),
+       VEXPRESS_SYSREG_GREEN_LED("user3",      "cpu0",         LED2),
+       VEXPRESS_SYSREG_GREEN_LED("user4",      "cpu1",         LED3),
+       VEXPRESS_SYSREG_GREEN_LED("user5",      "cpu2",         LED4),
+       VEXPRESS_SYSREG_GREEN_LED("user6",      "cpu3",         LED5),
+       VEXPRESS_SYSREG_GREEN_LED("user7",      "cpu4",         LED6),
+       VEXPRESS_SYSREG_GREEN_LED("user8",      "cpu5",         LED7),
+};
+
+struct gpio_led_platform_data vexpress_sysreg_leds_pdata = {
+       .num_leds = ARRAY_SIZE(vexpress_sysreg_leds),
+       .leds = vexpress_sysreg_leds,
+};
+
+
 static ssize_t vexpress_sysreg_sys_id_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
@@ -456,6 +490,10 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
                return err;
        }
 
+       platform_device_register_data(vexpress_sysreg_dev, "leds-gpio",
+                       PLATFORM_DEVID_AUTO, &vexpress_sysreg_leds_pdata,
+                       sizeof(vexpress_sysreg_leds_pdata));
+
        vexpress_sysreg_dev = &pdev->dev;
 
        device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id);
@@ -478,6 +516,7 @@ static struct platform_driver vexpress_sysreg_driver = {
 
 static int __init vexpress_sysreg_init(void)
 {
+       vexpress_sysreg_of_early_init();
        return platform_driver_register(&vexpress_sysreg_driver);
 }
 core_initcall(vexpress_sysreg_init);
index a9d9d41d95d342df8bcc95fa38055ac0bd47bec5..a433f580aa4c4edb94810685684e317a6afd3575 100644 (file)
@@ -59,12 +59,13 @@ static const struct reg_default wm5102_reva_patch[] = {
 static const struct reg_default wm5102_revb_patch[] = {
        { 0x80, 0x0003 },
        { 0x081, 0xE022 },
-       { 0x410, 0x6080 },
-       { 0x418, 0x6080 },
-       { 0x420, 0x6080 },
+       { 0x410, 0x4080 },
+       { 0x418, 0x4080 },
+       { 0x420, 0x4080 },
        { 0x428, 0xC000 },
-       { 0x441, 0x8014 },
+       { 0x4B0, 0x0066 },
        { 0x458, 0x000b },
+       { 0x212, 0x0000 },
        { 0x80, 0x0000 },
 };
 
@@ -231,11 +232,9 @@ const struct regmap_irq_chip wm5102_irq = {
 static const struct reg_default wm5102_reg_default[] = {
        { 0x00000008, 0x0019 },   /* R8     - Ctrl IF SPI CFG 1 */ 
        { 0x00000009, 0x0001 },   /* R9     - Ctrl IF I2C1 CFG 1 */ 
-       { 0x0000000D, 0x0000 },   /* R13    - Ctrl IF Status 1 */ 
        { 0x00000016, 0x0000 },   /* R22    - Write Sequencer Ctrl 0 */ 
        { 0x00000017, 0x0000 },   /* R23    - Write Sequencer Ctrl 1 */ 
        { 0x00000018, 0x0000 },   /* R24    - Write Sequencer Ctrl 2 */ 
-       { 0x0000001A, 0x0000 },   /* R26    - Write Sequencer PROM */ 
        { 0x00000020, 0x0000 },   /* R32    - Tone Generator 1 */ 
        { 0x00000021, 0x1000 },   /* R33    - Tone Generator 2 */ 
        { 0x00000022, 0x0000 },   /* R34    - Tone Generator 3 */ 
@@ -250,12 +249,14 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000062, 0x01FF },   /* R98    - Sample Rate Sequence Select 2 */ 
        { 0x00000063, 0x01FF },   /* R99    - Sample Rate Sequence Select 3 */ 
        { 0x00000064, 0x01FF },   /* R100   - Sample Rate Sequence Select 4 */ 
-       { 0x00000068, 0x01FF },   /* R104   - Always On Triggers Sequence Select 1 */ 
-       { 0x00000069, 0x01FF },   /* R105   - Always On Triggers Sequence Select 2 */ 
-       { 0x0000006A, 0x01FF },   /* R106   - Always On Triggers Sequence Select 3 */ 
-       { 0x0000006B, 0x01FF },   /* R107   - Always On Triggers Sequence Select 4 */ 
-       { 0x0000006C, 0x01FF },   /* R108   - Always On Triggers Sequence Select 5 */ 
-       { 0x0000006D, 0x01FF },   /* R109   - Always On Triggers Sequence Select 6 */ 
+       { 0x00000066, 0x01FF },   /* R102   - Always On Triggers Sequence Select 1 */
+       { 0x00000067, 0x01FF },   /* R103   - Always On Triggers Sequence Select 2 */
+       { 0x00000068, 0x01FF },   /* R104   - Always On Triggers Sequence Select 3 */
+       { 0x00000069, 0x01FF },   /* R105   - Always On Triggers Sequence Select 4 */
+       { 0x0000006A, 0x01FF },   /* R106   - Always On Triggers Sequence Select 5 */
+       { 0x0000006B, 0x01FF },   /* R107   - Always On Triggers Sequence Select 6 */
+       { 0x0000006E, 0x01FF },   /* R110   - Trigger Sequence Select 32 */
+       { 0x0000006F, 0x01FF },   /* R111   - Trigger Sequence Select 33 */
        { 0x00000070, 0x0000 },   /* R112   - Comfort Noise Generator */ 
        { 0x00000090, 0x0000 },   /* R144   - Haptics Control 1 */ 
        { 0x00000091, 0x7FFF },   /* R145   - Haptics Control 2 */ 
@@ -265,13 +266,14 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000095, 0x0000 },   /* R149   - Haptics phase 2 duration */ 
        { 0x00000096, 0x0000 },   /* R150   - Haptics phase 3 intensity */ 
        { 0x00000097, 0x0000 },   /* R151   - Haptics phase 3 duration */ 
-       { 0x00000100, 0x0001 },   /* R256   - Clock 32k 1 */ 
+       { 0x00000100, 0x0002 },   /* R256   - Clock 32k 1 */
        { 0x00000101, 0x0304 },   /* R257   - System Clock 1 */ 
        { 0x00000102, 0x0011 },   /* R258   - Sample rate 1 */ 
        { 0x00000103, 0x0011 },   /* R259   - Sample rate 2 */ 
        { 0x00000104, 0x0011 },   /* R260   - Sample rate 3 */ 
        { 0x00000112, 0x0305 },   /* R274   - Async clock 1 */ 
        { 0x00000113, 0x0011 },   /* R275   - Async sample rate 1 */ 
+       { 0x00000114, 0x0011 },   /* R276   - Async sample rate 2 */
        { 0x00000149, 0x0000 },   /* R329   - Output system clock */ 
        { 0x0000014A, 0x0000 },   /* R330   - Output async clock */ 
        { 0x00000152, 0x0000 },   /* R338   - Rate Estimator 1 */ 
@@ -280,13 +282,14 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000155, 0x0000 },   /* R341   - Rate Estimator 4 */ 
        { 0x00000156, 0x0000 },   /* R342   - Rate Estimator 5 */ 
        { 0x00000161, 0x0000 },   /* R353   - Dynamic Frequency Scaling 1 */ 
-       { 0x00000171, 0x0000 },   /* R369   - FLL1 Control 1 */ 
+       { 0x00000171, 0x0002 },   /* R369   - FLL1 Control 1 */
        { 0x00000172, 0x0008 },   /* R370   - FLL1 Control 2 */ 
        { 0x00000173, 0x0018 },   /* R371   - FLL1 Control 3 */ 
        { 0x00000174, 0x007D },   /* R372   - FLL1 Control 4 */ 
        { 0x00000175, 0x0004 },   /* R373   - FLL1 Control 5 */ 
        { 0x00000176, 0x0000 },   /* R374   - FLL1 Control 6 */ 
        { 0x00000177, 0x0181 },   /* R375   - FLL1 Loop Filter Test 1 */ 
+       { 0x00000178, 0x0000 },   /* R376   - FLL1 NCO Test 0 */
        { 0x00000181, 0x0000 },   /* R385   - FLL1 Synchroniser 1 */ 
        { 0x00000182, 0x0000 },   /* R386   - FLL1 Synchroniser 2 */ 
        { 0x00000183, 0x0000 },   /* R387   - FLL1 Synchroniser 3 */ 
@@ -302,6 +305,7 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000195, 0x0004 },   /* R405   - FLL2 Control 5 */ 
        { 0x00000196, 0x0000 },   /* R406   - FLL2 Control 6 */ 
        { 0x00000197, 0x0000 },   /* R407   - FLL2 Loop Filter Test 1 */ 
+       { 0x00000198, 0x0000 },   /* R408   - FLL2 NCO Test 0 */
        { 0x000001A1, 0x0000 },   /* R417   - FLL2 Synchroniser 1 */ 
        { 0x000001A2, 0x0000 },   /* R418   - FLL2 Synchroniser 2 */ 
        { 0x000001A3, 0x0000 },   /* R419   - FLL2 Synchroniser 3 */ 
@@ -317,8 +321,12 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000218, 0x01A6 },   /* R536   - Mic Bias Ctrl 1 */ 
        { 0x00000219, 0x01A6 },   /* R537   - Mic Bias Ctrl 2 */ 
        { 0x0000021A, 0x01A6 },   /* R538   - Mic Bias Ctrl 3 */ 
+       { 0x00000225, 0x0400 },   /* R549   - HP Ctrl 1L */
+       { 0x00000226, 0x0400 },   /* R550   - HP Ctrl 1R */
        { 0x00000293, 0x0000 },   /* R659   - Accessory Detect Mode 1 */ 
        { 0x0000029B, 0x0020 },   /* R667   - Headphone Detect 1 */ 
+       { 0x0000029C, 0x0000 },   /* R668   - Headphone Detect 2 */
+       { 0x0000029F, 0x0000 },   /* R671   - Headphone Detect Test */
        { 0x000002A2, 0x0000 },   /* R674   - Micd clamp control */
        { 0x000002A3, 0x1102 },   /* R675   - Mic Detect 1 */ 
        { 0x000002A4, 0x009F },   /* R676   - Mic Detect 2 */ 
@@ -350,53 +358,44 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000400, 0x0000 },   /* R1024  - Output Enables 1 */ 
        { 0x00000408, 0x0000 },   /* R1032  - Output Rate 1 */ 
        { 0x00000409, 0x0022 },   /* R1033  - Output Volume Ramp */ 
-       { 0x00000410, 0x0080 },   /* R1040  - Output Path Config 1L */ 
+       { 0x00000410, 0x4080 },   /* R1040  - Output Path Config 1L */
        { 0x00000411, 0x0180 },   /* R1041  - DAC Digital Volume 1L */ 
-       { 0x00000412, 0x0080 },   /* R1042  - DAC Volume Limit 1L */ 
+       { 0x00000412, 0x0081 },   /* R1042  - DAC Volume Limit 1L */
        { 0x00000413, 0x0001 },   /* R1043  - Noise Gate Select 1L */ 
        { 0x00000414, 0x0080 },   /* R1044  - Output Path Config 1R */ 
        { 0x00000415, 0x0180 },   /* R1045  - DAC Digital Volume 1R */ 
-       { 0x00000416, 0x0080 },   /* R1046  - DAC Volume Limit 1R */ 
+       { 0x00000416, 0x0081 },   /* R1046  - DAC Volume Limit 1R */
        { 0x00000417, 0x0002 },   /* R1047  - Noise Gate Select 1R */ 
-       { 0x00000418, 0x0080 },   /* R1048  - Output Path Config 2L */ 
+       { 0x00000418, 0x4080 },   /* R1048  - Output Path Config 2L */
        { 0x00000419, 0x0180 },   /* R1049  - DAC Digital Volume 2L */ 
-       { 0x0000041A, 0x0080 },   /* R1050  - DAC Volume Limit 2L */ 
+       { 0x0000041A, 0x0081 },   /* R1050  - DAC Volume Limit 2L */
        { 0x0000041B, 0x0004 },   /* R1051  - Noise Gate Select 2L */ 
        { 0x0000041C, 0x0080 },   /* R1052  - Output Path Config 2R */ 
        { 0x0000041D, 0x0180 },   /* R1053  - DAC Digital Volume 2R */ 
-       { 0x0000041E, 0x0080 },   /* R1054  - DAC Volume Limit 2R */ 
+       { 0x0000041E, 0x0081 },   /* R1054  - DAC Volume Limit 2R */
        { 0x0000041F, 0x0008 },   /* R1055  - Noise Gate Select 2R */ 
-       { 0x00000420, 0x0080 },   /* R1056  - Output Path Config 3L */ 
+       { 0x00000420, 0x4080 },   /* R1056  - Output Path Config 3L */
        { 0x00000421, 0x0180 },   /* R1057  - DAC Digital Volume 3L */ 
-       { 0x00000422, 0x0080 },   /* R1058  - DAC Volume Limit 3L */ 
+       { 0x00000422, 0x0081 },   /* R1058  - DAC Volume Limit 3L */
        { 0x00000423, 0x0010 },   /* R1059  - Noise Gate Select 3L */ 
-       { 0x00000424, 0x0080 },   /* R1060  - Output Path Config 3R */ 
-       { 0x00000425, 0x0180 },   /* R1061  - DAC Digital Volume 3R */ 
-       { 0x00000426, 0x0080 },   /* R1062  - DAC Volume Limit 3R */ 
-       { 0x00000428, 0x0000 },   /* R1064  - Output Path Config 4L */ 
+       { 0x00000428, 0xC000 },   /* R1064  - Output Path Config 4L */
        { 0x00000429, 0x0180 },   /* R1065  - DAC Digital Volume 4L */ 
-       { 0x0000042A, 0x0080 },   /* R1066  - Out Volume 4L */ 
+       { 0x0000042A, 0x0081 },   /* R1066  - Out Volume 4L */
        { 0x0000042B, 0x0040 },   /* R1067  - Noise Gate Select 4L */ 
-       { 0x0000042C, 0x0000 },   /* R1068  - Output Path Config 4R */ 
        { 0x0000042D, 0x0180 },   /* R1069  - DAC Digital Volume 4R */ 
-       { 0x0000042E, 0x0080 },   /* R1070  - Out Volume 4R */ 
+       { 0x0000042E, 0x0081 },   /* R1070  - Out Volume 4R */
        { 0x0000042F, 0x0080 },   /* R1071  - Noise Gate Select 4R */ 
        { 0x00000430, 0x0000 },   /* R1072  - Output Path Config 5L */ 
        { 0x00000431, 0x0180 },   /* R1073  - DAC Digital Volume 5L */ 
-       { 0x00000432, 0x0080 },   /* R1074  - DAC Volume Limit 5L */ 
+       { 0x00000432, 0x0081 },   /* R1074  - DAC Volume Limit 5L */
        { 0x00000433, 0x0100 },   /* R1075  - Noise Gate Select 5L */ 
-       { 0x00000434, 0x0000 },   /* R1076  - Output Path Config 5R */ 
        { 0x00000435, 0x0180 },   /* R1077  - DAC Digital Volume 5R */ 
-       { 0x00000436, 0x0080 },   /* R1078  - DAC Volume Limit 5R */ 
-       { 0x00000437, 0x0200 },   /* R1079  - Noise Gate Select 5R */ 
+       { 0x00000436, 0x0081 },   /* R1078  - DAC Volume Limit 5R */
+       { 0x00000437, 0x0200 },   /* R1079  - Noise Gate Select 5R */
        { 0x00000450, 0x0000 },   /* R1104  - DAC AEC Control 1 */ 
        { 0x00000458, 0x0001 },   /* R1112  - Noise Gate Control */ 
        { 0x00000490, 0x0069 },   /* R1168  - PDM SPK1 CTRL 1 */ 
        { 0x00000491, 0x0000 },   /* R1169  - PDM SPK1 CTRL 2 */ 
-       { 0x000004DC, 0x0000 },   /* R1244  - DAC comp 1 */ 
-       { 0x000004DD, 0x0000 },   /* R1245  - DAC comp 2 */ 
-       { 0x000004DE, 0x0000 },   /* R1246  - DAC comp 3 */ 
-       { 0x000004DF, 0x0000 },   /* R1247  - DAC comp 4 */ 
        { 0x00000500, 0x000C },   /* R1280  - AIF1 BCLK Ctrl */ 
        { 0x00000501, 0x0008 },   /* R1281  - AIF1 Tx Pin Ctrl */ 
        { 0x00000502, 0x0000 },   /* R1282  - AIF1 Rx Pin Ctrl */ 
@@ -424,7 +423,6 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000518, 0x0007 },   /* R1304  - AIF1 Frame Ctrl 18 */ 
        { 0x00000519, 0x0000 },   /* R1305  - AIF1 Tx Enables */ 
        { 0x0000051A, 0x0000 },   /* R1306  - AIF1 Rx Enables */ 
-       { 0x0000051B, 0x0000 },   /* R1307  - AIF1 Force Write */ 
        { 0x00000540, 0x000C },   /* R1344  - AIF2 BCLK Ctrl */ 
        { 0x00000541, 0x0008 },   /* R1345  - AIF2 Tx Pin Ctrl */ 
        { 0x00000542, 0x0000 },   /* R1346  - AIF2 Rx Pin Ctrl */ 
@@ -440,7 +438,6 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000552, 0x0001 },   /* R1362  - AIF2 Frame Ctrl 12 */ 
        { 0x00000559, 0x0000 },   /* R1369  - AIF2 Tx Enables */ 
        { 0x0000055A, 0x0000 },   /* R1370  - AIF2 Rx Enables */ 
-       { 0x0000055B, 0x0000 },   /* R1371  - AIF2 Force Write */ 
        { 0x00000580, 0x000C },   /* R1408  - AIF3 BCLK Ctrl */ 
        { 0x00000581, 0x0008 },   /* R1409  - AIF3 Tx Pin Ctrl */ 
        { 0x00000582, 0x0000 },   /* R1410  - AIF3 Rx Pin Ctrl */ 
@@ -456,7 +453,6 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000592, 0x0001 },   /* R1426  - AIF3 Frame Ctrl 12 */ 
        { 0x00000599, 0x0000 },   /* R1433  - AIF3 Tx Enables */ 
        { 0x0000059A, 0x0000 },   /* R1434  - AIF3 Rx Enables */ 
-       { 0x0000059B, 0x0000 },   /* R1435  - AIF3 Force Write */ 
        { 0x000005E3, 0x0004 },   /* R1507  - SLIMbus Framer Ref Gear */ 
        { 0x000005E5, 0x0000 },   /* R1509  - SLIMbus Rates 1 */ 
        { 0x000005E6, 0x0000 },   /* R1510  - SLIMbus Rates 2 */ 
@@ -780,22 +776,6 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x000008CD, 0x0080 },   /* R2253  - DRC1RMIX Input 3 Volume */ 
        { 0x000008CE, 0x0000 },   /* R2254  - DRC1RMIX Input 4 Source */ 
        { 0x000008CF, 0x0080 },   /* R2255  - DRC1RMIX Input 4 Volume */ 
-       { 0x000008D0, 0x0000 },   /* R2256  - DRC2LMIX Input 1 Source */ 
-       { 0x000008D1, 0x0080 },   /* R2257  - DRC2LMIX Input 1 Volume */ 
-       { 0x000008D2, 0x0000 },   /* R2258  - DRC2LMIX Input 2 Source */ 
-       { 0x000008D3, 0x0080 },   /* R2259  - DRC2LMIX Input 2 Volume */ 
-       { 0x000008D4, 0x0000 },   /* R2260  - DRC2LMIX Input 3 Source */ 
-       { 0x000008D5, 0x0080 },   /* R2261  - DRC2LMIX Input 3 Volume */ 
-       { 0x000008D6, 0x0000 },   /* R2262  - DRC2LMIX Input 4 Source */ 
-       { 0x000008D7, 0x0080 },   /* R2263  - DRC2LMIX Input 4 Volume */ 
-       { 0x000008D8, 0x0000 },   /* R2264  - DRC2RMIX Input 1 Source */ 
-       { 0x000008D9, 0x0080 },   /* R2265  - DRC2RMIX Input 1 Volume */ 
-       { 0x000008DA, 0x0000 },   /* R2266  - DRC2RMIX Input 2 Source */ 
-       { 0x000008DB, 0x0080 },   /* R2267  - DRC2RMIX Input 2 Volume */ 
-       { 0x000008DC, 0x0000 },   /* R2268  - DRC2RMIX Input 3 Source */ 
-       { 0x000008DD, 0x0080 },   /* R2269  - DRC2RMIX Input 3 Volume */ 
-       { 0x000008DE, 0x0000 },   /* R2270  - DRC2RMIX Input 4 Source */ 
-       { 0x000008DF, 0x0080 },   /* R2271  - DRC2RMIX Input 4 Volume */ 
        { 0x00000900, 0x0000 },   /* R2304  - HPLP1MIX Input 1 Source */ 
        { 0x00000901, 0x0080 },   /* R2305  - HPLP1MIX Input 1 Volume */ 
        { 0x00000902, 0x0000 },   /* R2306  - HPLP1MIX Input 2 Source */ 
@@ -887,7 +867,7 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000D1B, 0xFFFF },   /* R3355  - IRQ2 Status 4 Mask */ 
        { 0x00000D1C, 0xFFFF },   /* R3356  - IRQ2 Status 5 Mask */ 
        { 0x00000D1F, 0x0000 },   /* R3359  - IRQ2 Control */ 
-       { 0x00000D41, 0x0000 },   /* R3393  - ADSP2 IRQ0 */ 
+       { 0x00000D50, 0x0000 },   /* R3408  - AOD wkup and trig */
        { 0x00000D53, 0xFFFF },   /* R3411  - AOD IRQ Mask IRQ1 */ 
        { 0x00000D54, 0xFFFF },   /* R3412  - AOD IRQ Mask IRQ2 */ 
        { 0x00000D56, 0x0000 },   /* R3414  - Jack detect debounce */ 
@@ -982,11 +962,6 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000E82, 0x0018 },   /* R3714  - DRC1 ctrl3 */ 
        { 0x00000E83, 0x0000 },   /* R3715  - DRC1 ctrl4 */ 
        { 0x00000E84, 0x0000 },   /* R3716  - DRC1 ctrl5 */ 
-       { 0x00000E89, 0x0018 },   /* R3721  - DRC2 ctrl1 */ 
-       { 0x00000E8A, 0x0933 },   /* R3722  - DRC2 ctrl2 */ 
-       { 0x00000E8B, 0x0018 },   /* R3723  - DRC2 ctrl3 */ 
-       { 0x00000E8C, 0x0000 },   /* R3724  - DRC2 ctrl4 */ 
-       { 0x00000E8D, 0x0000 },   /* R3725  - DRC2 ctrl5 */ 
        { 0x00000EC0, 0x0000 },   /* R3776  - HPLPF1_1 */ 
        { 0x00000EC1, 0x0000 },   /* R3777  - HPLPF1_2 */ 
        { 0x00000EC4, 0x0000 },   /* R3780  - HPLPF2_1 */ 
@@ -997,16 +972,12 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000ECD, 0x0000 },   /* R3789  - HPLPF4_2 */ 
        { 0x00000EE0, 0x0000 },   /* R3808  - ASRC_ENABLE */ 
        { 0x00000EE2, 0x0000 },   /* R3810  - ASRC_RATE1 */ 
-       { 0x00000EE3, 0x4000 },   /* R3811  - ASRC_RATE2 */ 
        { 0x00000EF0, 0x0000 },   /* R3824  - ISRC 1 CTRL 1 */ 
        { 0x00000EF1, 0x0000 },   /* R3825  - ISRC 1 CTRL 2 */ 
        { 0x00000EF2, 0x0000 },   /* R3826  - ISRC 1 CTRL 3 */ 
        { 0x00000EF3, 0x0000 },   /* R3827  - ISRC 2 CTRL 1 */ 
        { 0x00000EF4, 0x0000 },   /* R3828  - ISRC 2 CTRL 2 */ 
        { 0x00000EF5, 0x0000 },   /* R3829  - ISRC 2 CTRL 3 */ 
-       { 0x00000EF6, 0x0000 },   /* R3830  - ISRC 3 CTRL 1 */ 
-       { 0x00000EF7, 0x0000 },   /* R3831  - ISRC 3 CTRL 2 */ 
-       { 0x00000EF8, 0x0000 },   /* R3832  - ISRC 3 CTRL 3 */ 
        { 0x00001100, 0x0010 },   /* R4352  - DSP1 Control 1 */ 
        { 0x00001101, 0x0000 },   /* R4353  - DSP1 Clocking 1 */ 
 };
@@ -1833,17 +1804,24 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_DSP1_STATUS_1:
        case ARIZONA_DSP1_STATUS_2:
        case ARIZONA_DSP1_STATUS_3:
+       case ARIZONA_DSP1_SCRATCH_0:
+       case ARIZONA_DSP1_SCRATCH_1:
+       case ARIZONA_DSP1_SCRATCH_2:
+       case ARIZONA_DSP1_SCRATCH_3:
                return true;
        default:
-               return false;
+               if ((reg >= 0x100000 && reg < 0x106000) ||
+                   (reg >= 0x180000 && reg < 0x180800) ||
+                   (reg >= 0x190000 && reg < 0x194800) ||
+                   (reg >= 0x1a8000 && reg < 0x1a9800))
+                       return true;
+               else
+                       return false;
        }
 }
 
 static bool wm5102_volatile_register(struct device *dev, unsigned int reg)
 {
-       if (reg > 0xffff)
-               return true;
-
        switch (reg) {
        case ARIZONA_SOFTWARE_RESET:
        case ARIZONA_DEVICE_REVISION:
@@ -1884,12 +1862,22 @@ static bool wm5102_volatile_register(struct device *dev, unsigned int reg)
        case ARIZONA_DSP1_STATUS_1:
        case ARIZONA_DSP1_STATUS_2:
        case ARIZONA_DSP1_STATUS_3:
+       case ARIZONA_DSP1_SCRATCH_0:
+       case ARIZONA_DSP1_SCRATCH_1:
+       case ARIZONA_DSP1_SCRATCH_2:
+       case ARIZONA_DSP1_SCRATCH_3:
        case ARIZONA_HEADPHONE_DETECT_2:
        case ARIZONA_HP_DACVAL:
        case ARIZONA_MIC_DETECT_3:
                return true;
        default:
-               return false;
+               if ((reg >= 0x100000 && reg < 0x106000) ||
+                   (reg >= 0x180000 && reg < 0x180800) ||
+                   (reg >= 0x190000 && reg < 0x194800) ||
+                   (reg >= 0x1a8000 && reg < 0x1a9800))
+                       return true;
+               else
+                       return false;
        }
 }
 
index 57c488d42d3e9b21e1ddd1dc68db4069e704aa44..803e93fae56aacb49c4960b8f0b156e8a85b7a6c 100644 (file)
@@ -467,7 +467,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                goto err;
        }
                
-       ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
+       ret = devm_regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
                                 wm8994->supplies);
        if (ret != 0) {
                dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret);
@@ -478,7 +478,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                                    wm8994->supplies);
        if (ret != 0) {
                dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret);
-               goto err_get;
+               goto err;
        }
 
        ret = wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET);
@@ -658,8 +658,6 @@ err_irq:
 err_enable:
        regulator_bulk_disable(wm8994->num_supplies,
                               wm8994->supplies);
-err_get:
-       regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
 err:
        mfd_remove_devices(wm8994->dev);
        return ret;
@@ -672,7 +670,6 @@ static void wm8994_device_exit(struct wm8994 *wm8994)
        wm8994_irq_exit(wm8994);
        regulator_bulk_disable(wm8994->num_supplies,
                               wm8994->supplies);
-       regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
 }
 
 static const struct of_device_id wm8994_of_match[] = {
index f74b5adca64232dd4a8ab7d4a397281b8f02c7a0..468c92303167acdeb37b77e1010b79a19d51c096 100644 (file)
@@ -678,12 +678,19 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        struct mmc_command *cmd = mrq->cmd;
        struct mmc_data *data = mrq->data;
        unsigned int data_size = 0;
+       int err;
 
        if (host->eject) {
                cmd->error = -ENOMEDIUM;
                goto finish;
        }
 
+       err = rtsx_pci_card_exclusive_check(host->pcr, RTSX_SD_CARD);
+       if (err) {
+               cmd->error = err;
+               goto finish;
+       }
+
        mutex_lock(&pcr->pcr_mutex);
 
        rtsx_pci_start_run(pcr);
@@ -901,6 +908,9 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        if (host->eject)
                return;
 
+       if (rtsx_pci_card_exclusive_check(host->pcr, RTSX_SD_CARD))
+               return;
+
        mutex_lock(&pcr->pcr_mutex);
 
        rtsx_pci_start_run(pcr);
@@ -1073,6 +1083,10 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
        if (host->eject)
                return -ENOMEDIUM;
 
+       err = rtsx_pci_card_exclusive_check(host->pcr, RTSX_SD_CARD);
+       if (err)
+               return err;
+
        mutex_lock(&pcr->pcr_mutex);
 
        rtsx_pci_start_run(pcr);
@@ -1122,6 +1136,10 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
        if (host->eject)
                return -ENOMEDIUM;
 
+       err = rtsx_pci_card_exclusive_check(host->pcr, RTSX_SD_CARD);
+       if (err)
+               return err;
+
        mutex_lock(&pcr->pcr_mutex);
 
        rtsx_pci_start_run(pcr);
index e6ab071fb6fddece886b00be334fe6810f17993d..79fbe3832dfc6f3bfd5e140143b0b51bb40cc36c 100644 (file)
@@ -305,6 +305,16 @@ config RTC_DRV_X1205
          This driver can also be built as a module. If so, the module
          will be called rtc-x1205.
 
+config RTC_DRV_PALMAS
+       tristate "TI Palmas RTC driver"
+       depends on MFD_PALMAS
+       help
+         If you say yes here you get support for the RTC of TI PALMA series PMIC
+         chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-palma.
+
 config RTC_DRV_PCF8523
        tristate "NXP PCF8523"
        help
index e8f2e2fee06f59ac5298b68529e722bbc43af8cc..c33f86f1a69b313f84f7c0e5ceb492474a59f892 100644 (file)
@@ -81,6 +81,7 @@ obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
 obj-$(CONFIG_RTC_DRV_MV)       += rtc-mv.o
 obj-$(CONFIG_RTC_DRV_NUC900)   += rtc-nuc900.o
 obj-$(CONFIG_RTC_DRV_OMAP)     += rtc-omap.o
+obj-$(CONFIG_RTC_DRV_PALMAS)   += rtc-palmas.o
 obj-$(CONFIG_RTC_DRV_PCAP)     += rtc-pcap.o
 obj-$(CONFIG_RTC_DRV_PCF8523)  += rtc-pcf8523.o
 obj-$(CONFIG_RTC_DRV_PCF8563)  += rtc-pcf8563.o
diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c
new file mode 100644 (file)
index 0000000..59c4298
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * rtc-palmas.c -- Palmas Real Time Clock driver.
+
+ * RTC driver for TI Palma series devices like TPS65913,
+ * TPS65914 power management IC.
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+#include <linux/bcd.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/palmas.h>
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+
+struct palmas_rtc {
+       struct rtc_device       *rtc;
+       struct device           *dev;
+       unsigned int            irq;
+};
+
+/* Total number of RTC registers needed to set time*/
+#define PALMAS_NUM_TIME_REGS   (PALMAS_YEARS_REG - PALMAS_SECONDS_REG + 1)
+
+static int palmas_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       unsigned char rtc_data[PALMAS_NUM_TIME_REGS];
+       struct palmas *palmas = dev_get_drvdata(dev->parent);
+       int ret;
+
+       /* Copy RTC counting registers to static registers or latches */
+       ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,
+               PALMAS_RTC_CTRL_REG_GET_TIME, PALMAS_RTC_CTRL_REG_GET_TIME);
+       if (ret < 0) {
+               dev_err(dev, "RTC CTRL reg update failed, err: %d\n", ret);
+               return ret;
+       }
+
+       ret = palmas_bulk_read(palmas, PALMAS_RTC_BASE, PALMAS_SECONDS_REG,
+                       rtc_data, PALMAS_NUM_TIME_REGS);
+       if (ret < 0) {
+               dev_err(dev, "RTC_SECONDS reg read failed, err = %d\n", ret);
+               return ret;
+       }
+
+       tm->tm_sec = bcd2bin(rtc_data[0]);
+       tm->tm_min = bcd2bin(rtc_data[1]);
+       tm->tm_hour = bcd2bin(rtc_data[2]);
+       tm->tm_mday = bcd2bin(rtc_data[3]);
+       tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
+       tm->tm_year = bcd2bin(rtc_data[5]) + 100;
+
+       return ret;
+}
+
+static int palmas_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       unsigned char rtc_data[PALMAS_NUM_TIME_REGS];
+       struct palmas *palmas = dev_get_drvdata(dev->parent);
+       int ret;
+
+       rtc_data[0] = bin2bcd(tm->tm_sec);
+       rtc_data[1] = bin2bcd(tm->tm_min);
+       rtc_data[2] = bin2bcd(tm->tm_hour);
+       rtc_data[3] = bin2bcd(tm->tm_mday);
+       rtc_data[4] = bin2bcd(tm->tm_mon + 1);
+       rtc_data[5] = bin2bcd(tm->tm_year - 100);
+
+       /* Stop RTC while updating the RTC time registers */
+       ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,
+               PALMAS_RTC_CTRL_REG_STOP_RTC, 0);
+       if (ret < 0) {
+               dev_err(dev, "RTC stop failed, err = %d\n", ret);
+               return ret;
+       }
+
+       ret = palmas_bulk_write(palmas, PALMAS_RTC_BASE, PALMAS_SECONDS_REG,
+               rtc_data, PALMAS_NUM_TIME_REGS);
+       if (ret < 0) {
+               dev_err(dev, "RTC_SECONDS reg write failed, err = %d\n", ret);
+               return ret;
+       }
+
+       /* Start back RTC */
+       ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,
+               PALMAS_RTC_CTRL_REG_STOP_RTC, PALMAS_RTC_CTRL_REG_STOP_RTC);
+       if (ret < 0)
+               dev_err(dev, "RTC start failed, err = %d\n", ret);
+       return ret;
+}
+
+static int palmas_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
+{
+       struct palmas *palmas = dev_get_drvdata(dev->parent);
+       u8 val;
+
+       val = enabled ? PALMAS_RTC_INTERRUPTS_REG_IT_ALARM : 0;
+       return palmas_write(palmas, PALMAS_RTC_BASE,
+               PALMAS_RTC_INTERRUPTS_REG, val);
+}
+
+static int palmas_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+       unsigned char alarm_data[PALMAS_NUM_TIME_REGS];
+       u32 int_val;
+       struct palmas *palmas = dev_get_drvdata(dev->parent);
+       int ret;
+
+       ret = palmas_bulk_read(palmas, PALMAS_RTC_BASE,
+                       PALMAS_ALARM_SECONDS_REG,
+                       alarm_data, PALMAS_NUM_TIME_REGS);
+       if (ret < 0) {
+               dev_err(dev, "RTC_ALARM_SECONDS read failed, err = %d\n", ret);
+               return ret;
+       }
+
+       alm->time.tm_sec = bcd2bin(alarm_data[0]);
+       alm->time.tm_min = bcd2bin(alarm_data[1]);
+       alm->time.tm_hour = bcd2bin(alarm_data[2]);
+       alm->time.tm_mday = bcd2bin(alarm_data[3]);
+       alm->time.tm_mon = bcd2bin(alarm_data[4]) - 1;
+       alm->time.tm_year = bcd2bin(alarm_data[5]) + 100;
+
+       ret = palmas_read(palmas, PALMAS_RTC_BASE, PALMAS_RTC_INTERRUPTS_REG,
+                       &int_val);
+       if (ret < 0) {
+               dev_err(dev, "RTC_INTERRUPTS reg read failed, err = %d\n", ret);
+               return ret;
+       }
+
+       if (int_val & PALMAS_RTC_INTERRUPTS_REG_IT_ALARM)
+               alm->enabled = 1;
+       return ret;
+}
+
+static int palmas_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+       unsigned char alarm_data[PALMAS_NUM_TIME_REGS];
+       struct palmas *palmas = dev_get_drvdata(dev->parent);
+       int ret;
+
+       ret = palmas_rtc_alarm_irq_enable(dev, 0);
+       if (ret < 0) {
+               dev_err(dev, "Disable RTC alarm failed\n");
+               return ret;
+       }
+
+       alarm_data[0] = bin2bcd(alm->time.tm_sec);
+       alarm_data[1] = bin2bcd(alm->time.tm_min);
+       alarm_data[2] = bin2bcd(alm->time.tm_hour);
+       alarm_data[3] = bin2bcd(alm->time.tm_mday);
+       alarm_data[4] = bin2bcd(alm->time.tm_mon + 1);
+       alarm_data[5] = bin2bcd(alm->time.tm_year - 100);
+
+       ret = palmas_bulk_write(palmas, PALMAS_RTC_BASE,
+               PALMAS_ALARM_SECONDS_REG, alarm_data, PALMAS_NUM_TIME_REGS);
+       if (ret < 0) {
+               dev_err(dev, "ALARM_SECONDS_REG write failed, err = %d\n", ret);
+               return ret;
+       }
+
+       if (alm->enabled)
+               ret = palmas_rtc_alarm_irq_enable(dev, 1);
+       return ret;
+}
+
+static int palmas_clear_interrupts(struct device *dev)
+{
+       struct palmas *palmas = dev_get_drvdata(dev->parent);
+       unsigned int rtc_reg;
+       int ret;
+
+       ret = palmas_read(palmas, PALMAS_RTC_BASE, PALMAS_RTC_STATUS_REG,
+                               &rtc_reg);
+       if (ret < 0) {
+               dev_err(dev, "RTC_STATUS read failed, err = %d\n", ret);
+               return ret;
+       }
+
+       ret = palmas_write(palmas, PALMAS_RTC_BASE, PALMAS_RTC_STATUS_REG,
+                       rtc_reg);
+       if (ret < 0) {
+               dev_err(dev, "RTC_STATUS write failed, err = %d\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static irqreturn_t palmas_rtc_interrupt(int irq, void *context)
+{
+       struct palmas_rtc *palmas_rtc = context;
+       struct device *dev = palmas_rtc->dev;
+       int ret;
+
+       ret = palmas_clear_interrupts(dev);
+       if (ret < 0) {
+               dev_err(dev, "RTC interrupt clear failed, err = %d\n", ret);
+               return IRQ_NONE;
+       }
+
+       rtc_update_irq(palmas_rtc->rtc, 1, RTC_IRQF | RTC_AF);
+       return IRQ_HANDLED;
+}
+
+static struct rtc_class_ops palmas_rtc_ops = {
+       .read_time      = palmas_rtc_read_time,
+       .set_time       = palmas_rtc_set_time,
+       .read_alarm     = palmas_rtc_read_alarm,
+       .set_alarm      = palmas_rtc_set_alarm,
+       .alarm_irq_enable = palmas_rtc_alarm_irq_enable,
+};
+
+static int palmas_rtc_probe(struct platform_device *pdev)
+{
+       struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
+       struct palmas_rtc *palmas_rtc = NULL;
+       int ret;
+
+       palmas_rtc = devm_kzalloc(&pdev->dev, sizeof(struct palmas_rtc),
+                       GFP_KERNEL);
+       if (!palmas_rtc)
+               return -ENOMEM;
+
+       /* Clear pending interrupts */
+       ret = palmas_clear_interrupts(&pdev->dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "clear RTC int failed, err = %d\n", ret);
+               return ret;
+       }
+
+       palmas_rtc->dev = &pdev->dev;
+       platform_set_drvdata(pdev, palmas_rtc);
+
+       /* Start RTC */
+       ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,
+                       PALMAS_RTC_CTRL_REG_STOP_RTC,
+                       PALMAS_RTC_CTRL_REG_STOP_RTC);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "RTC_CTRL write failed, err = %d\n", ret);
+               return ret;
+       }
+
+       palmas_rtc->irq = platform_get_irq(pdev, 0);
+
+       palmas_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+                               &palmas_rtc_ops, THIS_MODULE);
+       if (IS_ERR(palmas_rtc->rtc)) {
+               ret = PTR_ERR(palmas_rtc->rtc);
+               dev_err(&pdev->dev, "RTC register failed, err = %d\n", ret);
+               return ret;
+       }
+
+       ret = request_threaded_irq(palmas_rtc->irq, NULL,
+                       palmas_rtc_interrupt,
+                       IRQF_TRIGGER_LOW | IRQF_ONESHOT |
+                       IRQF_EARLY_RESUME,
+                       dev_name(&pdev->dev), palmas_rtc);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "IRQ request failed, err = %d\n", ret);
+               rtc_device_unregister(palmas_rtc->rtc);
+               return ret;
+       }
+
+       device_set_wakeup_capable(&pdev->dev, 1);
+       return 0;
+}
+
+static int palmas_rtc_remove(struct platform_device *pdev)
+{
+       struct palmas_rtc *palmas_rtc = platform_get_drvdata(pdev);
+
+       palmas_rtc_alarm_irq_enable(&pdev->dev, 0);
+       free_irq(palmas_rtc->irq, palmas_rtc);
+       rtc_device_unregister(palmas_rtc->rtc);
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int palmas_rtc_suspend(struct device *dev)
+{
+       struct palmas_rtc *palmas_rtc = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(palmas_rtc->irq);
+       return 0;
+}
+
+static int palmas_rtc_resume(struct device *dev)
+{
+       struct palmas_rtc *palmas_rtc = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(palmas_rtc->irq);
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops palmas_rtc_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(palmas_rtc_suspend, palmas_rtc_resume)
+};
+
+static struct platform_driver palmas_rtc_driver = {
+       .probe          = palmas_rtc_probe,
+       .remove         = palmas_rtc_remove,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "palmas-rtc",
+               .pm     = &palmas_rtc_pm_ops,
+       },
+};
+
+module_platform_driver(palmas_rtc_driver);
+
+MODULE_ALIAS("platform:palmas_rtc");
+MODULE_DESCRIPTION("TI PALMAS series RTC driver");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_LICENSE("GPL v2");
index 99899e808c6afc83af6e428fa96e2e781983effd..0555ee42d7cb1882cf284a2f8019ce8a091be961 100644 (file)
@@ -107,7 +107,7 @@ static int omap_ehci_init(struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
        int                     rc;
-       struct ehci_hcd_omap_platform_data      *pdata;
+       struct usbhs_omap_platform_data *pdata;
 
        pdata = hcd->self.controller->platform_data;
 
@@ -151,7 +151,7 @@ static int omap_ehci_init(struct usb_hcd *hcd)
 }
 
 static void disable_put_regulator(
-               struct ehci_hcd_omap_platform_data *pdata)
+               struct usbhs_omap_platform_data *pdata)
 {
        int i;
 
@@ -176,7 +176,7 @@ static void disable_put_regulator(
 static int ehci_hcd_omap_probe(struct platform_device *pdev)
 {
        struct device                           *dev = &pdev->dev;
-       struct ehci_hcd_omap_platform_data      *pdata = dev->platform_data;
+       struct usbhs_omap_platform_data         *pdata = dev->platform_data;
        struct resource                         *res;
        struct usb_hcd                          *hcd;
        void __iomem                            *regs;
index 2c9bce050aa954a03bd04ee09b5be4d45fe9a3a4..5ca11b066b7e51b31e346759fed356e98bfe0d12 100644 (file)
@@ -101,6 +101,29 @@ static const struct backlight_ops max8925_backlight_ops = {
        .get_brightness = max8925_backlight_get_brightness,
 };
 
+#ifdef CONFIG_OF
+static int max8925_backlight_dt_init(struct platform_device *pdev,
+                             struct max8925_backlight_pdata *pdata)
+{
+       struct device_node *nproot = pdev->dev.parent->of_node, *np;
+       int dual_string;
+
+       if (!nproot)
+               return -ENODEV;
+       np = of_find_node_by_name(nproot, "backlight");
+       if (!np) {
+               dev_err(&pdev->dev, "failed to find backlight node\n");
+               return -ENODEV;
+       }
+
+       of_property_read_u32(np, "maxim,max8925-dual-string", &dual_string);
+       pdata->dual_string = dual_string;
+       return 0;
+}
+#else
+#define max8925_backlight_dt_init(x, y)        (-1)
+#endif
+
 static int max8925_backlight_probe(struct platform_device *pdev)
 {
        struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
@@ -147,6 +170,13 @@ static int max8925_backlight_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, bl);
 
        value = 0;
+       if (pdev->dev.parent->of_node && !pdata) {
+               pdata = devm_kzalloc(&pdev->dev,
+                                    sizeof(struct max8925_backlight_pdata),
+                                    GFP_KERNEL);
+               max8925_backlight_dt_init(pdev, pdata);
+       }
+
        if (pdata) {
                if (pdata->lxw_scl)
                        value |= (1 << 7);
@@ -158,7 +188,6 @@ static int max8925_backlight_probe(struct platform_device *pdev)
        ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 0xfe, value);
        if (ret < 0)
                goto out_brt;
-
        backlight_update_status(bl);
        return 0;
 out_brt:
index 7f809fd4a57f950c94c3d5d280fe471f60ebeaf4..26e1fdbddf690c88cd20dbf015955d6b13295a0a 100644 (file)
@@ -364,6 +364,18 @@ config IMX2_WDT
          To compile this driver as a module, choose M here: the
          module will be called imx2_wdt.
 
+config UX500_WATCHDOG
+       tristate "ST-Ericsson Ux500 watchdog"
+       depends on MFD_DB8500_PRCMU
+       select WATCHDOG_CORE
+       default y
+       help
+         Say Y here to include Watchdog timer support for the watchdog
+         existing in the prcmu of ST-Ericsson Ux500 series platforms.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ux500_wdt.
+
 # AVR32 Architecture
 
 config AT32AP700X_WDT
index 97bbdb3a464844588fa97e526b89eb284f302145..bec86ee6e9e3a93f4d14494ec090d51b8dc1654c 100644 (file)
@@ -52,6 +52,7 @@ obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o
 obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
 obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
 obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
+obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
diff --git a/drivers/watchdog/ux500_wdt.c b/drivers/watchdog/ux500_wdt.c
new file mode 100644 (file)
index 0000000..a614d84
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011-2013
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Mathieu Poirier <mathieu.poirier@linaro.org> for ST-Ericsson
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/miscdevice.h>
+#include <linux/err.h>
+#include <linux/uaccess.h>
+#include <linux/watchdog.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/ux500_wdt.h>
+
+#include <linux/mfd/dbx500-prcmu.h>
+
+#define WATCHDOG_TIMEOUT 600 /* 10 minutes */
+
+#define WATCHDOG_MIN   0
+#define WATCHDOG_MAX28 268435  /* 28 bit resolution in ms == 268435.455 s */
+#define WATCHDOG_MAX32 4294967 /* 32 bit resolution in ms == 4294967.295 s */
+
+static unsigned int timeout = WATCHDOG_TIMEOUT;
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout,
+       "Watchdog timeout in seconds. default="
+                               __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+       "Watchdog cannot be stopped once started (default="
+                               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static int ux500_wdt_start(struct watchdog_device *wdd)
+{
+       return prcmu_enable_a9wdog(PRCMU_WDOG_ALL);
+}
+
+static int ux500_wdt_stop(struct watchdog_device *wdd)
+{
+       return prcmu_disable_a9wdog(PRCMU_WDOG_ALL);
+}
+
+static int ux500_wdt_keepalive(struct watchdog_device *wdd)
+{
+       return prcmu_kick_a9wdog(PRCMU_WDOG_ALL);
+}
+
+static int ux500_wdt_set_timeout(struct watchdog_device *wdd,
+                                unsigned int timeout)
+{
+       ux500_wdt_stop(wdd);
+       prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
+       ux500_wdt_start(wdd);
+
+       return 0;
+}
+
+static const struct watchdog_info ux500_wdt_info = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+       .identity = "Ux500 WDT",
+       .firmware_version = 1,
+};
+
+static const struct watchdog_ops ux500_wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = ux500_wdt_start,
+       .stop  = ux500_wdt_stop,
+       .ping  = ux500_wdt_keepalive,
+       .set_timeout = ux500_wdt_set_timeout,
+};
+
+static struct watchdog_device ux500_wdt = {
+       .info = &ux500_wdt_info,
+       .ops = &ux500_wdt_ops,
+       .min_timeout = WATCHDOG_MIN,
+       .max_timeout = WATCHDOG_MAX32,
+};
+
+static int ux500_wdt_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct ux500_wdt_data *pdata = pdev->dev.platform_data;
+
+       if (pdata) {
+               if (pdata->timeout > 0)
+                       timeout = pdata->timeout;
+               if (pdata->has_28_bits_resolution)
+                       ux500_wdt.max_timeout = WATCHDOG_MAX28;
+       }
+
+       watchdog_set_nowayout(&ux500_wdt, nowayout);
+
+       /* disable auto off on sleep */
+       prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false);
+
+       /* set HW initial value */
+       prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
+
+       ret = watchdog_register_device(&ux500_wdt);
+       if (ret)
+               return ret;
+
+       dev_info(&pdev->dev, "initialized\n");
+
+       return 0;
+}
+
+static int ux500_wdt_remove(struct platform_device *dev)
+{
+       watchdog_unregister_device(&ux500_wdt);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int ux500_wdt_suspend(struct platform_device *pdev,
+                            pm_message_t state)
+{
+       if (watchdog_active(&ux500_wdt)) {
+               ux500_wdt_stop(&ux500_wdt);
+               prcmu_config_a9wdog(PRCMU_WDOG_CPU1, true);
+
+               prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
+               ux500_wdt_start(&ux500_wdt);
+       }
+       return 0;
+}
+
+static int ux500_wdt_resume(struct platform_device *pdev)
+{
+       if (watchdog_active(&ux500_wdt)) {
+               ux500_wdt_stop(&ux500_wdt);
+               prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false);
+
+               prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
+               ux500_wdt_start(&ux500_wdt);
+       }
+       return 0;
+}
+#else
+#define ux500_wdt_suspend NULL
+#define ux500_wdt_resume NULL
+#endif
+
+static struct platform_driver ux500_wdt_driver = {
+       .probe          = ux500_wdt_probe,
+       .remove         = ux500_wdt_remove,
+       .suspend        = ux500_wdt_suspend,
+       .resume         = ux500_wdt_resume,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "ux500_wdt",
+       },
+};
+
+module_platform_driver(ux500_wdt_driver);
+
+MODULE_AUTHOR("Jonas Aaberg <jonas.aberg@stericsson.com>");
+MODULE_DESCRIPTION("Ux500 Watchdog Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:ux500_wdt");
index 1ff54b114efcb1971742cfcb584bfd662468ce49..488debbef8959caf079606e0e3876e843d157955 100644 (file)
  * address each module uses within a given i2c slave.
  */
 
+/* Module IDs for similar functionalities found in twl4030/twl6030 */
+enum twl_module_ids {
+       TWL_MODULE_USB,
+       TWL_MODULE_PIH,
+       TWL_MODULE_MAIN_CHARGE,
+       TWL_MODULE_PM_MASTER,
+       TWL_MODULE_PM_RECEIVER,
+
+       TWL_MODULE_RTC,
+       TWL_MODULE_PWM,
+       TWL_MODULE_LED,
+       TWL_MODULE_SECURED_REG,
+
+       TWL_MODULE_LAST,
+};
+
+/* Modules only available in twl4030 series */
 enum twl4030_module_ids {
-       TWL4030_MODULE_USB = 0,         /* Slave 0 (i2c address 0x48) */
-       TWL4030_MODULE_AUDIO_VOICE,     /* Slave 1 (i2c address 0x49) */
+       TWL4030_MODULE_AUDIO_VOICE = TWL_MODULE_LAST,
        TWL4030_MODULE_GPIO,
        TWL4030_MODULE_INTBR,
-       TWL4030_MODULE_PIH,
-
        TWL4030_MODULE_TEST,
-       TWL4030_MODULE_KEYPAD,          /* Slave 2 (i2c address 0x4a) */
+       TWL4030_MODULE_KEYPAD,
+
        TWL4030_MODULE_MADC,
        TWL4030_MODULE_INTERRUPTS,
-       TWL4030_MODULE_LED,
-
-       TWL4030_MODULE_MAIN_CHARGE,
        TWL4030_MODULE_PRECHARGE,
-       TWL4030_MODULE_PWM0,
-       TWL4030_MODULE_PWM1,
-       TWL4030_MODULE_PWMA,
+       TWL4030_MODULE_BACKUP,
+       TWL4030_MODULE_INT,
 
-       TWL4030_MODULE_PWMB,
        TWL5031_MODULE_ACCESSORY,
        TWL5031_MODULE_INTERRUPTS,
-       TWL4030_MODULE_BACKUP,          /* Slave 3 (i2c address 0x4b) */
-       TWL4030_MODULE_INT,
 
-       TWL4030_MODULE_PM_MASTER,
-       TWL4030_MODULE_PM_RECEIVER,
-       TWL4030_MODULE_RTC,
-       TWL4030_MODULE_SECURED_REG,
        TWL4030_MODULE_LAST,
 };
 
-/* Similar functionalities implemented in TWL4030/6030 */
-#define TWL_MODULE_USB         TWL4030_MODULE_USB
-#define TWL_MODULE_PIH         TWL4030_MODULE_PIH
-#define TWL_MODULE_MAIN_CHARGE TWL4030_MODULE_MAIN_CHARGE
-#define TWL_MODULE_PM_MASTER   TWL4030_MODULE_PM_MASTER
-#define TWL_MODULE_PM_RECEIVER TWL4030_MODULE_PM_RECEIVER
-#define TWL_MODULE_RTC         TWL4030_MODULE_RTC
-#define TWL_MODULE_PWM         TWL4030_MODULE_PWM0
-#define TWL_MODULE_LED         TWL4030_MODULE_LED
+/* Modules only available in twl6030 series */
+enum twl6030_module_ids {
+       TWL6030_MODULE_ID0 = TWL_MODULE_LAST,
+       TWL6030_MODULE_ID1,
+       TWL6030_MODULE_ID2,
+       TWL6030_MODULE_GPADC,
+       TWL6030_MODULE_GASGAUGE,
+
+       TWL6030_MODULE_LAST,
+};
 
-#define TWL6030_MODULE_ID0     13
-#define TWL6030_MODULE_ID1     14
-#define TWL6030_MODULE_ID2     15
+/* Until the clients has been converted to use TWL_MODULE_LED */
+#define TWL4030_MODULE_LED     TWL_MODULE_LED
 
 #define GPIO_INTR_OFFSET       0
 #define KEYPAD_INTR_OFFSET     1
@@ -170,21 +174,23 @@ static inline int twl_class_is_ ##class(void)     \
 TWL_CLASS_IS(4030, TWL4030_CLASS_ID)
 TWL_CLASS_IS(6030, TWL6030_CLASS_ID)
 
-/*
- * Read and write single 8-bit registers
- */
-int twl_i2c_write_u8(u8 mod_no, u8 val, u8 reg);
-int twl_i2c_read_u8(u8 mod_no, u8 *val, u8 reg);
-
 /*
  * Read and write several 8-bit registers at once.
- *
- * IMPORTANT:  For twl_i2c_write(), allocate num_bytes + 1
- * for the value, and populate your data starting at offset 1.
  */
 int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
 int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
 
+/*
+ * Read and write single 8-bit registers
+ */
+static inline int twl_i2c_write_u8(u8 mod_no, u8 val, u8 reg) {
+       return twl_i2c_write(mod_no, &val, reg, 1);
+}
+
+static inline int twl_i2c_read_u8(u8 mod_no, u8 *val, u8 reg) {
+       return twl_i2c_read(mod_no, val, reg, 1);
+}
+
 int twl_get_type(void);
 int twl_get_version(void);
 int twl_get_hfclk_rate(void);
index 478672ed0c3d5d45793935a913f2f9a59a9de6a3..e94537befabd018a4d8128bd7134594e59b120f1 100644 (file)
@@ -365,5 +365,5 @@ static inline int pm80x_dev_resume(struct device *dev)
 
 extern int pm80x_init(struct i2c_client *client,
                      const struct i2c_device_id *id);
-extern int pm80x_deinit(struct i2c_client *client);
+extern int pm80x_deinit(void);
 #endif /* __LINUX_MFD_88PM80X_H */
index 80e3b8683a84f1c51fb793e8439bc436cb36117f..9ead60bc66b73be3de722213d91e3eb8d51cbae2 100644 (file)
@@ -311,6 +311,7 @@ int abx500_mask_and_set_register_interruptible(struct device *dev, u8 bank,
 int abx500_get_chip_id(struct device *dev);
 int abx500_event_registers_startup_state_get(struct device *dev, u8 *event);
 int abx500_startup_irq_enabled(struct device *dev, unsigned int irq);
+void abx500_dump_all_banks(void);
 
 struct abx500_ops {
        int (*get_chip_id) (struct device *);
@@ -321,6 +322,7 @@ struct abx500_ops {
        int (*mask_and_set_register) (struct device *, u8, u8, u8, u8);
        int (*event_registers_startup_state_get) (struct device *, u8 *);
        int (*startup_irq_enabled) (struct device *, unsigned int);
+       void (*dump_all_banks) (struct device *);
 };
 
 int abx500_register_ops(struct device *core_dev, struct abx500_ops *ops);
index 10eb50973c393dbd9a75ef8c6e214670e7c0785b..ebf12e793db982fd06e96682c9e1ad1b7f4a6c42 100644 (file)
@@ -37,6 +37,11 @@ static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
        return ab8500_sysctrl_write(reg, bits, 0);
 }
 
+/* Configuration data for SysClkReq1RfClkBuf - SysClkReq8RfClkBuf */
+struct ab8500_sysctrl_platform_data {
+       u8 initial_req_buf_config[8];
+};
+
 /* Registers */
 #define AB8500_TURNONSTATUS            0x100
 #define AB8500_RESETSTATUS             0x101
index fc0534483c726daaefb0cd5e50116b142a17a4dc..9db0bda446a0794a9460178e248162727556e79b 100644 (file)
@@ -368,10 +368,12 @@ struct regulator_reg_init;
 struct regulator_init_data;
 struct ab8500_gpio_platform_data;
 struct ab8500_codec_platform_data;
+struct ab8500_sysctrl_platform_data;
 
 /**
  * struct ab8500_platform_data - AB8500 platform data
  * @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
+ * @pm_power_off: Should machine pm power off hook be registered or not
  * @init: board-specific initialization after detection of ab8500
  * @num_regulator_reg_init: number of regulator init registers
  * @regulator_reg_init: regulator init registers
@@ -380,6 +382,7 @@ struct ab8500_codec_platform_data;
  */
 struct ab8500_platform_data {
        int irq_base;
+       bool pm_power_off;
        void (*init) (struct ab8500 *);
        int num_regulator_reg_init;
        struct ab8500_regulator_reg_init *regulator_reg_init;
@@ -387,6 +390,7 @@ struct ab8500_platform_data {
        struct regulator_init_data *regulator;
        struct abx500_gpio_platform_data *gpio;
        struct ab8500_codec_platform_data *codec;
+       struct ab8500_sysctrl_platform_data *sysctrl;
 };
 
 extern int ab8500_init(struct ab8500 *ab8500,
@@ -508,4 +512,12 @@ static inline int is_ab9540_2p0_or_earlier(struct ab8500 *ab)
        return (is_ab9540(ab) && (ab->chip_id < AB8500_CUT2P0));
 }
 
+#ifdef CONFIG_AB8500_DEBUG
+void ab8500_dump_all_banks(struct device *dev);
+void ab8500_debug_register_interrupt(int line);
+#else
+static inline void ab8500_dump_all_banks(struct device *dev) {}
+static inline void ab8500_debug_register_interrupt(int line) {}
+#endif
+
 #endif /* MFD_AB8500_H */
index 96d64f2b8d781393b5566bf1bacf2a6a6b669e09..455c51d22d6b43e5dd4ccb932021dfcea36182a0 100644 (file)
@@ -56,6 +56,8 @@
 #define ARIZONA_DMIC_MICBIAS2 2
 #define ARIZONA_DMIC_MICBIAS3 3
 
+#define ARIZONA_MAX_MICBIAS 3
+
 #define ARIZONA_INMODE_DIFF 0
 #define ARIZONA_INMODE_SE   1
 #define ARIZONA_INMODE_DMIC 2
 
 struct regulator_init_data;
 
+struct arizona_micbias {
+       int mV;                    /** Regulated voltage */
+       unsigned int ext_cap:1;    /** External capacitor fitted */
+       unsigned int discharge:1;  /** Actively discharge */
+       unsigned int fast_start:1; /** Enable aggressive startup ramp rate */
+};
+
 struct arizona_micd_config {
        unsigned int src;
        unsigned int bias;
@@ -136,6 +145,9 @@ struct arizona_pdata {
        /** Reference voltage for DMIC inputs */
        int dmic_ref[ARIZONA_MAX_INPUT];
 
+       /** MICBIAS configurations */
+       struct arizona_micbias micbias[ARIZONA_MAX_MICBIAS];
+
        /** Mode of input structures */
        int inmode[ARIZONA_MAX_INPUT];
 
index 188d89abd9637c64e39234183e501e7c2bb22f99..3403551360696b3f9900a8a4b1e5bc59bd17a672 100644 (file)
 #define ARIZONA_DSP1_STATUS_1                    0x1104
 #define ARIZONA_DSP1_STATUS_2                    0x1105
 #define ARIZONA_DSP1_STATUS_3                    0x1106
+#define ARIZONA_DSP1_SCRATCH_0                   0x1140
+#define ARIZONA_DSP1_SCRATCH_1                   0x1141
+#define ARIZONA_DSP1_SCRATCH_2                   0x1142
+#define ARIZONA_DSP1_SCRATCH_3                   0x1143
 #define ARIZONA_DSP2_CONTROL_1                   0x1200
 #define ARIZONA_DSP2_CLOCKING_1                  0x1201
 #define ARIZONA_DSP2_STATUS_1                    0x1204
 #define ARIZONA_DSP2_STATUS_2                    0x1205
+#define ARIZONA_DSP2_SCRATCH_0                   0x1240
+#define ARIZONA_DSP2_SCRATCH_1                   0x1241
+#define ARIZONA_DSP2_SCRATCH_2                   0x1242
+#define ARIZONA_DSP2_SCRATCH_3                   0x1243
 #define ARIZONA_DSP3_CONTROL_1                   0x1300
 #define ARIZONA_DSP3_CLOCKING_1                  0x1301
 #define ARIZONA_DSP3_STATUS_1                    0x1304
 #define ARIZONA_DSP3_STATUS_2                    0x1305
+#define ARIZONA_DSP3_SCRATCH_0                   0x1340
+#define ARIZONA_DSP3_SCRATCH_1                   0x1341
+#define ARIZONA_DSP3_SCRATCH_2                   0x1342
+#define ARIZONA_DSP3_SCRATCH_3                   0x1343
 #define ARIZONA_DSP4_CONTROL_1                   0x1400
 #define ARIZONA_DSP4_CLOCKING_1                  0x1401
 #define ARIZONA_DSP4_STATUS_1                    0x1404
 #define ARIZONA_DSP4_STATUS_2                    0x1405
+#define ARIZONA_DSP4_SCRATCH_0                   0x1440
+#define ARIZONA_DSP4_SCRATCH_1                   0x1441
+#define ARIZONA_DSP4_SCRATCH_2                   0x1442
+#define ARIZONA_DSP4_SCRATCH_3                   0x1443
 
 /*
  * Field Definitions.
index f8bac7cfc25fea58be8a3a47d05fffc4da22f8e4..3abcca91eecdbe86dd3f98f8dc21f3989a88260e 100644 (file)
@@ -150,6 +150,18 @@ enum prcmu_clock {
        PRCMU_DSI2ESCCLK,
 };
 
+/**
+ * enum prcmu_wdog_id - PRCMU watchdog IDs
+ * @PRCMU_WDOG_ALL: use all timers
+ * @PRCMU_WDOG_CPU1: use first CPU timer only
+ * @PRCMU_WDOG_CPU2: use second CPU timer conly
+ */
+enum prcmu_wdog_id {
+       PRCMU_WDOG_ALL = 0x00,
+       PRCMU_WDOG_CPU1 = 0x01,
+       PRCMU_WDOG_CPU2 = 0x02,
+};
+
 /**
  * enum ape_opp - APE OPP states definition
  * @APE_OPP_INIT:
index 74d8e2969630de5689957cff6ec0b5fc1e459ffd..ce8502e9e7dcba93f90f90334ceeaeceb1885bc9 100644 (file)
@@ -190,6 +190,8 @@ enum {
        MAX8925_NR_IRQS,
 };
 
+
+
 struct max8925_chip {
        struct device           *dev;
        struct i2c_client       *i2c;
@@ -201,7 +203,6 @@ struct max8925_chip {
        int                     irq_base;
        int                     core_irq;
        int                     tsc_irq;
-
        unsigned int            wakeup_flag;
 };
 
index 29f6616e12f07605379c6b21aa9bad1ff9152df3..a4d13d7cd00187cf2928de2d651d486388078224 100644 (file)
@@ -2789,4 +2789,56 @@ enum usb_irq_events {
 #define PALMAS_GPADC_TRIM15                                    0xE
 #define PALMAS_GPADC_TRIM16                                    0xF
 
+static inline int palmas_read(struct palmas *palmas, unsigned int base,
+               unsigned int reg, unsigned int *val)
+{
+       unsigned int addr =  PALMAS_BASE_TO_REG(base, reg);
+       int slave_id = PALMAS_BASE_TO_SLAVE(base);
+
+       return regmap_read(palmas->regmap[slave_id], addr, val);
+}
+
+static inline int palmas_write(struct palmas *palmas, unsigned int base,
+               unsigned int reg, unsigned int value)
+{
+       unsigned int addr = PALMAS_BASE_TO_REG(base, reg);
+       int slave_id = PALMAS_BASE_TO_SLAVE(base);
+
+       return regmap_write(palmas->regmap[slave_id], addr, value);
+}
+
+static inline int palmas_bulk_write(struct palmas *palmas, unsigned int base,
+       unsigned int reg, const void *val, size_t val_count)
+{
+       unsigned int addr = PALMAS_BASE_TO_REG(base, reg);
+       int slave_id = PALMAS_BASE_TO_SLAVE(base);
+
+       return regmap_bulk_write(palmas->regmap[slave_id], addr,
+                       val, val_count);
+}
+
+static inline int palmas_bulk_read(struct palmas *palmas, unsigned int base,
+               unsigned int reg, void *val, size_t val_count)
+{
+       unsigned int addr = PALMAS_BASE_TO_REG(base, reg);
+       int slave_id = PALMAS_BASE_TO_SLAVE(base);
+
+       return regmap_bulk_read(palmas->regmap[slave_id], addr,
+               val, val_count);
+}
+
+static inline int palmas_update_bits(struct palmas *palmas, unsigned int base,
+       unsigned int reg, unsigned int mask, unsigned int val)
+{
+       unsigned int addr = PALMAS_BASE_TO_REG(base, reg);
+       int slave_id = PALMAS_BASE_TO_SLAVE(base);
+
+       return regmap_update_bits(palmas->regmap[slave_id], addr, mask, val);
+}
+
+static inline int palmas_irq_get_virq(struct palmas *palmas, int irq)
+{
+       return regmap_irq_get_virq(palmas->irq_data, irq);
+}
+
 #endif /*  __LINUX_MFD_PALMAS_H */
index 4b117a3f54d493f59393226c6351e1fa8c1e16ca..26ea7f1b7caf1876626cd5275ddc372611e0933c 100644 (file)
 #define        SD_RSP_TYPE_R6                  0x01
 #define        SD_RSP_TYPE_R7                  0x01
 
-/* SD_CONFIURE3 */
+/* SD_CONFIGURE3 */
 #define        SD_RSP_80CLK_TIMEOUT_EN         0x01
 
 /* Card Transfer Reset Register */
 #define CARD_GPIO_DIR                  0xFD57
 #define CARD_GPIO                      0xFD58
 #define CARD_DATA_SOURCE               0xFD5B
+#define SD30_CLK_DRIVE_SEL             0xFD5A
 #define CARD_SELECT                    0xFD5C
 #define SD30_DRIVE_SEL                 0xFD5E
+#define SD30_CMD_DRIVE_SEL             0xFD5E
+#define SD30_DAT_DRIVE_SEL             0xFD5F
 #define CARD_CLK_EN                    0xFD69
 #define SDIO_CTRL                      0xFD6B
 #define CD_PAD_CTL                     0xFD73
 #define MSGTXDATA3                     0xFE47
 #define MSGTXCTL                       0xFE48
 #define PETXCFG                                0xFE49
+#define LTR_CTL                                0xFE4A
+#define OBFF_CFG                       0xFE4C
 
 #define CDRESUMECTL                    0xFE52
 #define WAKE_SEL_CTL                   0xFE54
@@ -735,6 +740,7 @@ struct rtsx_pcr {
 
        unsigned int                    card_inserted;
        unsigned int                    card_removed;
+       unsigned int                    card_exist;
 
        struct delayed_work             carddet_work;
        struct delayed_work             idle_work;
@@ -799,6 +805,7 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
                u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk);
 int rtsx_pci_card_power_on(struct rtsx_pcr *pcr, int card);
 int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card);
+int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card);
 int rtsx_pci_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage);
 unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr);
 void rtsx_pci_complete_unfinished_transfer(struct rtsx_pcr *pcr);
index e697c85ad3bc47cead3127723c4a3db08bae6b3b..fa579b4c666b185c2912372b1c1148c0e6efbdbc 100644 (file)
@@ -55,6 +55,7 @@ struct ohci_hcd_omap_platform_data {
 };
 
 struct usbhs_omap_platform_data {
+       int                             nports;
        enum usbhs_omap_port_mode       port_mode[OMAP3_HS_USB_PORTS];
        int                             reset_gpio_port[OMAP3_HS_USB_PORTS];
        struct regulator                *regulator[OMAP3_HS_USB_PORTS];
diff --git a/include/linux/platform_data/ux500_wdt.h b/include/linux/platform_data/ux500_wdt.h
new file mode 100644 (file)
index 0000000..1689ff4
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) ST Ericsson SA 2011
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * STE Ux500 Watchdog platform data
+ */
+#ifndef __UX500_WDT_H
+#define __UX500_WDT_H
+
+/**
+ * struct ux500_wdt_data
+ */
+struct ux500_wdt_data {
+       unsigned int timeout;
+       bool has_28_bits_resolution;
+};
+
+#endif /* __UX500_WDT_H */
index c52215ff4245c7a6b65eee7f3852042cca6ccd45..75818744ab5998bdb3f88de62ff87e319548272d 100644 (file)
 #define VEXPRESS_GPIO_MMC_CARDIN       0
 #define VEXPRESS_GPIO_MMC_WPROT                1
 #define VEXPRESS_GPIO_FLASH_WPn                2
+#define VEXPRESS_GPIO_LED0             3
+#define VEXPRESS_GPIO_LED1             4
+#define VEXPRESS_GPIO_LED2             5
+#define VEXPRESS_GPIO_LED3             6
+#define VEXPRESS_GPIO_LED4             7
+#define VEXPRESS_GPIO_LED5             8
+#define VEXPRESS_GPIO_LED6             9
+#define VEXPRESS_GPIO_LED7             10
 
 #define VEXPRESS_RES_FUNC(_site, _func)        \
 {                                      \