]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 13 Dec 2012 18:59:11 +0000 (10:59 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 13 Dec 2012 18:59:11 +0000 (10:59 -0800)
Pull ARM SoC driver specific changes from Olof Johansson:
 "A collection of mostly SoC-specific driver updates:
   - a handful of pincontrol and setup changes
   - new drivers for hwmon and reset controller for vexpress
   - timing support updates for OMAP (gpmc and other interfaces)
   - plus a collection of smaller cleanups"

* tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (21 commits)
  ARM: ux500: fix pin warning
  ARM: OMAP2+: tusb6010: generic timing calculation
  ARM: OMAP2+: smc91x: generic timing calculation
  ARM: OMAP2+: onenand: generic timing calculation
  ARM: OMAP2+: gpmc: generic timing calculation
  ARM: OMAP2+: gpmc: handle additional timings
  ARM: OMAP2+: nand: remove redundant rounding
  gpio: samsung: use pr_* instead of printk
  ARM: ux500: fixup magnetometer pins
  ARM: ux500: add STM pin configuration
  ARM: ux500: 8500: add pinctrl support for uart1 and uart2
  ARM: ux500: cosmetic fixups for uart0
  gpio: samsung: Fix input mode setting function for GPIO int
  ARM: SAMSUNG: Insert bitmap_gpio_int member in samsung_gpio_chip
  ARM: ux500: 8500: define SDI sleep states
  ARM: vexpress: Reset driver
  ARM: ux500: 8500: update SKE keypad pinctrl table
  hwmon: Versatile Express hwmon driver
  ARM: ux500: delete duplicate macro
  ARM: ux500: 8500: add IDLE pin configuration for SPI
  ...

17 files changed:
Documentation/bus-devices/ti-gpmc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/hwmon/vexpress.txt [new file with mode: 0644]
Documentation/hwmon/vexpress [new file with mode: 0644]
arch/arm/mach-omap2/gpmc-nand.c
arch/arm/mach-omap2/gpmc-onenand.c
arch/arm/mach-omap2/gpmc-smc91x.c
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/gpmc.h
arch/arm/mach-omap2/usb-tusb6010.c
arch/arm/mach-ux500/board-mop500-pins.c
arch/arm/mach-vexpress/reset.c [new file with mode: 0644]
arch/arm/plat-samsung/include/plat/gpio-core.h
arch/arm/plat-samsung/s5p-irq-gpioint.c
drivers/gpio/gpio-samsung.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/vexpress.c [new file with mode: 0644]

diff --git a/Documentation/bus-devices/ti-gpmc.txt b/Documentation/bus-devices/ti-gpmc.txt
new file mode 100644 (file)
index 0000000..cc9ce57
--- /dev/null
@@ -0,0 +1,122 @@
+GPMC (General Purpose Memory Controller):
+=========================================
+
+GPMC is an unified memory controller dedicated to interfacing external
+memory devices like
+ * Asynchronous SRAM like memories and application specific integrated
+   circuit devices.
+ * Asynchronous, synchronous, and page mode burst NOR flash devices
+   NAND flash
+ * Pseudo-SRAM devices
+
+GPMC is found on Texas Instruments SoC's (OMAP based)
+IP details: http://www.ti.com/lit/pdf/spruh73 section 7.1
+
+
+GPMC generic timing calculation:
+================================
+
+GPMC has certain timings that has to be programmed for proper
+functioning of the peripheral, while peripheral has another set of
+timings. To have peripheral work with gpmc, peripheral timings has to
+be translated to the form gpmc can understand. The way it has to be
+translated depends on the connected peripheral. Also there is a
+dependency for certain gpmc timings on gpmc clock frequency. Hence a
+generic timing routine was developed to achieve above requirements.
+
+Generic routine provides a generic method to calculate gpmc timings
+from gpmc peripheral timings. struct gpmc_device_timings fields has to
+be updated with timings from the datasheet of the peripheral that is
+connected to gpmc. A few of the peripheral timings can be fed either
+in time or in cycles, provision to handle this scenario has been
+provided (refer struct gpmc_device_timings definition). It may so
+happen that timing as specified by peripheral datasheet is not present
+in timing structure, in this scenario, try to correlate peripheral
+timing to the one available. If that doesn't work, try to add a new
+field as required by peripheral, educate generic timing routine to
+handle it, make sure that it does not break any of the existing.
+Then there may be cases where peripheral datasheet doesn't mention
+certain fields of struct gpmc_device_timings, zero those entries.
+
+Generic timing routine has been verified to work properly on
+multiple onenand's and tusb6010 peripherals.
+
+A word of caution: generic timing routine has been developed based
+on understanding of gpmc timings, peripheral timings, available
+custom timing routines, a kind of reverse engineering without
+most of the datasheets & hardware (to be exact none of those supported
+in mainline having custom timing routine) and by simulation.
+
+gpmc timing dependency on peripheral timings:
+[<gpmc_timing>: <peripheral timing1>, <peripheral timing2> ...]
+
+1. common
+cs_on: t_ceasu
+adv_on: t_avdasu, t_ceavd
+
+2. sync common
+sync_clk: clk
+page_burst_access: t_bacc
+clk_activation: t_ces, t_avds
+
+3. read async muxed
+adv_rd_off: t_avdp_r
+oe_on: t_oeasu, t_aavdh
+access: t_iaa, t_oe, t_ce, t_aa
+rd_cycle: t_rd_cycle, t_cez_r, t_oez
+
+4. read async non-muxed
+adv_rd_off: t_avdp_r
+oe_on: t_oeasu
+access: t_iaa, t_oe, t_ce, t_aa
+rd_cycle: t_rd_cycle, t_cez_r, t_oez
+
+5. read sync muxed
+adv_rd_off: t_avdp_r, t_avdh
+oe_on: t_oeasu, t_ach, cyc_aavdh_oe
+access: t_iaa, cyc_iaa, cyc_oe
+rd_cycle: t_cez_r, t_oez, t_ce_rdyz
+
+6. read sync non-muxed
+adv_rd_off: t_avdp_r
+oe_on: t_oeasu
+access: t_iaa, cyc_iaa, cyc_oe
+rd_cycle: t_cez_r, t_oez, t_ce_rdyz
+
+7. write async muxed
+adv_wr_off: t_avdp_w
+we_on, wr_data_mux_bus: t_weasu, t_aavdh, cyc_aavhd_we
+we_off: t_wpl
+cs_wr_off: t_wph
+wr_cycle: t_cez_w, t_wr_cycle
+
+8. write async non-muxed
+adv_wr_off: t_avdp_w
+we_on, wr_data_mux_bus: t_weasu
+we_off: t_wpl
+cs_wr_off: t_wph
+wr_cycle: t_cez_w, t_wr_cycle
+
+9. write sync muxed
+adv_wr_off: t_avdp_w, t_avdh
+we_on, wr_data_mux_bus: t_weasu, t_rdyo, t_aavdh, cyc_aavhd_we
+we_off: t_wpl, cyc_wpl
+cs_wr_off: t_wph
+wr_cycle: t_cez_w, t_ce_rdyz
+
+10. write sync non-muxed
+adv_wr_off: t_avdp_w
+we_on, wr_data_mux_bus: t_weasu, t_rdyo
+we_off: t_wpl, cyc_wpl
+cs_wr_off: t_wph
+wr_cycle: t_cez_w, t_ce_rdyz
+
+
+Note: Many of gpmc timings are dependent on other gpmc timings (a few
+gpmc timings purely dependent on other gpmc timings, a reason that
+some of the gpmc timings are missing above), and it will result in
+indirect dependency of peripheral timings to gpmc timings other than
+mentioned above, refer timing routine for more details. To know what
+these peripheral timings correspond to, please see explanations in
+struct gpmc_device_timings definition. And for gpmc timings refer
+IP details (link above).
diff --git a/Documentation/devicetree/bindings/hwmon/vexpress.txt b/Documentation/devicetree/bindings/hwmon/vexpress.txt
new file mode 100644 (file)
index 0000000..9c27ed6
--- /dev/null
@@ -0,0 +1,23 @@
+Versatile Express hwmon sensors
+-------------------------------
+
+Requires node properties:
+- "compatible" value : one of
+       "arm,vexpress-volt"
+       "arm,vexpress-amp"
+       "arm,vexpress-temp"
+       "arm,vexpress-power"
+       "arm,vexpress-energy"
+- "arm,vexpress-sysreg,func" when controlled via vexpress-sysreg
+  (see Documentation/devicetree/bindings/arm/vexpress-sysreg.txt
+  for more details)
+
+Optional node properties:
+- label : string describing the monitored value
+
+Example:
+       energy@0 {
+               compatible = "arm,vexpress-energy";
+               arm,vexpress-sysreg,func = <13 0>;
+               label = "A15 Jcore";
+       };
diff --git a/Documentation/hwmon/vexpress b/Documentation/hwmon/vexpress
new file mode 100644 (file)
index 0000000..557d6d5
--- /dev/null
@@ -0,0 +1,34 @@
+Kernel driver vexpress
+======================
+
+Supported systems:
+  * ARM Ltd. Versatile Express platform
+    Prefix: 'vexpress'
+    Datasheets:
+      * "Hardware Description" sections of the Technical Reference Manuals
+        for the Versatile Express boards:
+        http://infocenter.arm.com/help/topic/com.arm.doc.subset.boards.express/index.html
+      * Section "4.4.14. System Configuration registers" of the V2M-P1 TRM:
+        http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0447-/index.html
+
+Author: Pawel Moll
+
+Description
+-----------
+
+Versatile Express platform (http://www.arm.com/versatileexpress/) is a
+reference & prototyping system for ARM Ltd. processors. It can be set up
+from a wide range of boards, each of them containing (apart of the main
+chip/FPGA) a number of microcontrollers responsible for platform
+configuration and control. Theses microcontrollers can also monitor the
+board and its environment by a number of internal and external sensors,
+providing information about power lines voltages and currents, board
+temperature and power usage. Some of them also calculate consumed energy
+and provide a cumulative use counter.
+
+The configuration devices are _not_ memory mapped and must be accessed
+via a custom interface, abstracted by the "vexpress_config" API.
+
+As these devices are non-discoverable, they must be described in a Device
+Tree passed to the kernel. Details of the DT binding for them can be found
+in Documentation/devicetree/bindings/hwmon/vexpress.txt.
index 8607735b3ab3c96b8a6fecf25066843a47aaee57..db969a5c4998d3c9b1904ff90d2134e2eb3c991a 100644 (file)
@@ -52,27 +52,27 @@ static int omap2_nand_gpmc_retime(
 
        memset(&t, 0, sizeof(t));
        t.sync_clk = gpmc_t->sync_clk;
-       t.cs_on = gpmc_round_ns_to_ticks(gpmc_t->cs_on);
-       t.adv_on = gpmc_round_ns_to_ticks(gpmc_t->adv_on);
+       t.cs_on = gpmc_t->cs_on;
+       t.adv_on = gpmc_t->adv_on;
 
        /* Read */
-       t.adv_rd_off = gpmc_round_ns_to_ticks(gpmc_t->adv_rd_off);
+       t.adv_rd_off = gpmc_t->adv_rd_off;
        t.oe_on  = t.adv_on;
-       t.access = gpmc_round_ns_to_ticks(gpmc_t->access);
-       t.oe_off = gpmc_round_ns_to_ticks(gpmc_t->oe_off);
-       t.cs_rd_off = gpmc_round_ns_to_ticks(gpmc_t->cs_rd_off);
-       t.rd_cycle  = gpmc_round_ns_to_ticks(gpmc_t->rd_cycle);
+       t.access = gpmc_t->access;
+       t.oe_off = gpmc_t->oe_off;
+       t.cs_rd_off = gpmc_t->cs_rd_off;
+       t.rd_cycle = gpmc_t->rd_cycle;
 
        /* Write */
-       t.adv_wr_off = gpmc_round_ns_to_ticks(gpmc_t->adv_wr_off);
+       t.adv_wr_off = gpmc_t->adv_wr_off;
        t.we_on  = t.oe_on;
        if (cpu_is_omap34xx()) {
-           t.wr_data_mux_bus = gpmc_round_ns_to_ticks(gpmc_t->wr_data_mux_bus);
-           t.wr_access = gpmc_round_ns_to_ticks(gpmc_t->wr_access);
+               t.wr_data_mux_bus = gpmc_t->wr_data_mux_bus;
+               t.wr_access = gpmc_t->wr_access;
        }
-       t.we_off = gpmc_round_ns_to_ticks(gpmc_t->we_off);
-       t.cs_wr_off = gpmc_round_ns_to_ticks(gpmc_t->cs_wr_off);
-       t.wr_cycle  = gpmc_round_ns_to_ticks(gpmc_t->wr_cycle);
+       t.we_off = gpmc_t->we_off;
+       t.cs_wr_off = gpmc_t->cs_wr_off;
+       t.wr_cycle = gpmc_t->wr_cycle;
 
        /* Configure GPMC */
        if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16)
index d102183ed9a5b21289b61678b9f4b49746d68c31..94a349e4dc966196d763a51f5f719c2fc071a7de 100644 (file)
@@ -33,7 +33,6 @@
 
 static unsigned onenand_flags;
 static unsigned latency;
-static int fclk_offset;
 
 static struct omap_onenand_platform_data *gpmc_onenand_data;
 
@@ -50,6 +49,7 @@ static struct platform_device gpmc_onenand_device = {
 
 static struct gpmc_timings omap2_onenand_calc_async_timings(void)
 {
+       struct gpmc_device_timings dev_t;
        struct gpmc_timings t;
 
        const int t_cer = 15;
@@ -59,35 +59,24 @@ static struct gpmc_timings omap2_onenand_calc_async_timings(void)
        const int t_aa = 76;
        const int t_oe = 20;
        const int t_cez = 20; /* max of t_cez, t_oez */
-       const int t_ds = 30;
        const int t_wpl = 40;
        const int t_wph = 30;
 
-       memset(&t, 0, sizeof(t));
-       t.sync_clk = 0;
-       t.cs_on = 0;
-       t.adv_on = 0;
-
-       /* Read */
-       t.adv_rd_off = gpmc_round_ns_to_ticks(max_t(int, t_avdp, t_cer));
-       t.oe_on  = t.adv_rd_off + gpmc_round_ns_to_ticks(t_aavdh);
-       t.access = t.adv_on + gpmc_round_ns_to_ticks(t_aa);
-       t.access = max_t(int, t.access, t.cs_on + gpmc_round_ns_to_ticks(t_ce));
-       t.access = max_t(int, t.access, t.oe_on + gpmc_round_ns_to_ticks(t_oe));
-       t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
-       t.cs_rd_off = t.oe_off;
-       t.rd_cycle  = t.cs_rd_off + gpmc_round_ns_to_ticks(t_cez);
-
-       /* Write */
-       t.adv_wr_off = t.adv_rd_off;
-       t.we_on  = t.oe_on;
-       if (cpu_is_omap34xx()) {
-               t.wr_data_mux_bus = t.we_on;
-               t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
-       }
-       t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
-       t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
-       t.wr_cycle  = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
+       memset(&dev_t, 0, sizeof(dev_t));
+
+       dev_t.mux = true;
+       dev_t.t_avdp_r = max_t(int, t_avdp, t_cer) * 1000;
+       dev_t.t_avdp_w = dev_t.t_avdp_r;
+       dev_t.t_aavdh = t_aavdh * 1000;
+       dev_t.t_aa = t_aa * 1000;
+       dev_t.t_ce = t_ce * 1000;
+       dev_t.t_oe = t_oe * 1000;
+       dev_t.t_cez_r = t_cez * 1000;
+       dev_t.t_cez_w = dev_t.t_cez_r;
+       dev_t.t_wpl = t_wpl * 1000;
+       dev_t.t_wph = t_wph * 1000;
+
+       gpmc_calc_timings(&t, &dev_t);
 
        return t;
 }
@@ -173,18 +162,15 @@ static struct gpmc_timings
 omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
                                int freq)
 {
+       struct gpmc_device_timings dev_t;
        struct gpmc_timings t;
        const int t_cer  = 15;
        const int t_avdp = 12;
        const int t_cez  = 20; /* max of t_cez, t_oez */
-       const int t_ds   = 30;
        const int t_wpl  = 40;
        const int t_wph  = 30;
        int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
-       u32 reg;
-       int div, fclk_offset_ns, gpmc_clk_ns;
-       int ticks_cez;
-       int cs = cfg->cs;
+       int div, gpmc_clk_ns;
 
        if (cfg->flags & ONENAND_SYNC_READ)
                onenand_flags = ONENAND_FLAG_SYNCREAD;
@@ -251,77 +237,35 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
                latency = 4;
 
        /* Set synchronous read timings */
-       memset(&t, 0, sizeof(t));
-
-       if (div == 1) {
-               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
-               reg |= (1 << 7);
-               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
-               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
-               reg |= (1 << 7);
-               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
-               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
-               reg |= (1 << 7);
-               reg |= (1 << 23);
-               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
-       } else {
-               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
-               reg &= ~(1 << 7);
-               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
-               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
-               reg &= ~(1 << 7);
-               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
-               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
-               reg &= ~(1 << 7);
-               reg &= ~(1 << 23);
-               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
-       }
+       memset(&dev_t, 0, sizeof(dev_t));
 
-       t.sync_clk = min_gpmc_clk_period;
-       t.cs_on = 0;
-       t.adv_on = 0;
-       fclk_offset_ns = gpmc_round_ns_to_ticks(max_t(int, t_ces, t_avds));
-       fclk_offset = gpmc_ns_to_ticks(fclk_offset_ns);
-       t.page_burst_access = gpmc_clk_ns;
-
-       /* Read */
-       t.adv_rd_off = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_avdh));
-       t.oe_on = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_ach));
-       /* Force at least 1 clk between AVD High to OE Low */
-       if (t.oe_on <= t.adv_rd_off)
-               t.oe_on = t.adv_rd_off + gpmc_round_ns_to_ticks(1);
-       t.access = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div);
-       t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
-       t.cs_rd_off = t.oe_off;
-       ticks_cez = ((gpmc_ns_to_ticks(t_cez) + div - 1) / div) * div;
-       t.rd_cycle = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div +
-                    ticks_cez);
-
-       /* Write */
+       dev_t.mux = true;
+       dev_t.sync_read = true;
        if (onenand_flags & ONENAND_FLAG_SYNCWRITE) {
-               t.adv_wr_off = t.adv_rd_off;
-               t.we_on  = 0;
-               t.we_off = t.cs_rd_off;
-               t.cs_wr_off = t.cs_rd_off;
-               t.wr_cycle  = t.rd_cycle;
-               if (cpu_is_omap34xx()) {
-                       t.wr_data_mux_bus = gpmc_ticks_to_ns(fclk_offset +
-                                       gpmc_ps_to_ticks(min_gpmc_clk_period +
-                                       t_rdyo * 1000));
-                       t.wr_access = t.access;
-               }
+               dev_t.sync_write = true;
        } else {
-               t.adv_wr_off = gpmc_round_ns_to_ticks(max_t(int,
-                                                       t_avdp, t_cer));
-               t.we_on  = t.adv_wr_off + gpmc_round_ns_to_ticks(t_aavdh);
-               t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
-               t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
-               t.wr_cycle  = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
-               if (cpu_is_omap34xx()) {
-                       t.wr_data_mux_bus = t.we_on;
-                       t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
-               }
+               dev_t.t_avdp_w = max(t_avdp, t_cer) * 1000;
+               dev_t.t_wpl = t_wpl * 1000;
+               dev_t.t_wph = t_wph * 1000;
+               dev_t.t_aavdh = t_aavdh * 1000;
        }
+       dev_t.ce_xdelay = true;
+       dev_t.avd_xdelay = true;
+       dev_t.oe_xdelay = true;
+       dev_t.we_xdelay = true;
+       dev_t.clk = min_gpmc_clk_period;
+       dev_t.t_bacc = dev_t.clk;
+       dev_t.t_ces = t_ces * 1000;
+       dev_t.t_avds = t_avds * 1000;
+       dev_t.t_avdh = t_avdh * 1000;
+       dev_t.t_ach = t_ach * 1000;
+       dev_t.cyc_iaa = (latency + 1);
+       dev_t.t_cez_r = t_cez * 1000;
+       dev_t.t_cez_w = dev_t.t_cez_r;
+       dev_t.cyc_aavdh_oe = 1;
+       dev_t.t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period;
+
+       gpmc_calc_timings(&t, &dev_t);
 
        return t;
 }
@@ -338,7 +282,6 @@ static int gpmc_set_sync_mode(int cs, struct gpmc_timings *t)
                          (sync_read ? GPMC_CONFIG1_READTYPE_SYNC : 0) |
                          (sync_write ? GPMC_CONFIG1_WRITEMULTIPLE_SUPP : 0) |
                          (sync_write ? GPMC_CONFIG1_WRITETYPE_SYNC : 0) |
-                         GPMC_CONFIG1_CLKACTIVATIONTIME(fclk_offset) |
                          GPMC_CONFIG1_PAGE_LEN(2) |
                          (cpu_is_omap34xx() ? 0 :
                                (GPMC_CONFIG1_WAIT_READ_MON |
index 6eed907d594cc700134ad0e7716df079d1b793c8..11d0b756f09897be435075302392131a35aa686b 100644 (file)
@@ -58,6 +58,7 @@ static struct platform_device gpmc_smc91x_device = {
 static int smc91c96_gpmc_retime(void)
 {
        struct gpmc_timings t;
+       struct gpmc_device_timings dev_t;
        const int t3 = 10;      /* Figure 12.2 read and 12.4 write */
        const int t4_r = 20;    /* Figure 12.2 read */
        const int t4_w = 5;     /* Figure 12.4 write */
@@ -68,32 +69,6 @@ static int smc91c96_gpmc_retime(void)
        const int t20 = 185;    /* Figure 12.2 read and 12.4 write */
        u32 l;
 
-       memset(&t, 0, sizeof(t));
-
-       /* Read timings */
-       t.cs_on = 0;
-       t.adv_on = t.cs_on;
-       t.oe_on = t.adv_on + t3;
-       t.access = t.oe_on + t5;
-       t.oe_off = t.access;
-       t.adv_rd_off = t.oe_off + max(t4_r, t6);
-       t.cs_rd_off = t.oe_off;
-       t.rd_cycle = t20 - t.oe_on;
-
-       /* Write timings */
-       t.we_on = t.adv_on + t3;
-
-       if (cpu_is_omap34xx() && (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)) {
-               t.wr_data_mux_bus = t.we_on;
-               t.we_off = t.wr_data_mux_bus + t7;
-       } else
-               t.we_off = t.we_on + t7;
-       if (cpu_is_omap34xx())
-               t.wr_access = t.we_off;
-       t.adv_wr_off = t.we_off + max(t4_w, t8);
-       t.cs_wr_off = t.we_off + t4_w;
-       t.wr_cycle = t20 - t.we_on;
-
        l = GPMC_CONFIG1_DEVICESIZE_16;
        if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
                l |= GPMC_CONFIG1_MUXADDDATA;
@@ -115,6 +90,22 @@ static int smc91c96_gpmc_retime(void)
        if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
                return 0;
 
+       memset(&dev_t, 0, sizeof(dev_t));
+
+       dev_t.t_oeasu = t3 * 1000;
+       dev_t.t_oe = t5 * 1000;
+       dev_t.t_cez_r = t4_r * 1000;
+       dev_t.t_oez = t6 * 1000;
+       dev_t.t_rd_cycle = (t20 - t3) * 1000;
+
+       dev_t.t_weasu = t3 * 1000;
+       dev_t.t_wpl = t7 * 1000;
+       dev_t.t_wph = t8 * 1000;
+       dev_t.t_cez_w = t4_w * 1000;
+       dev_t.t_wr_cycle = (t20 - t3) * 1000;
+
+       gpmc_calc_timings(&t, &dev_t);
+
        return gpmc_cs_set_timings(gpmc_cfg->cs, &t);
 }
 
index bf6117c32f4bc0302522d0ea6f54b83d7c171ea3..65468f6d7f0e62382ee6df3c16fcb2cad5eb054e 100644 (file)
 #define GPMC_ECC_CTRL_ECCREG8          0x008
 #define GPMC_ECC_CTRL_ECCREG9          0x009
 
+#define        GPMC_CONFIG2_CSEXTRADELAY               BIT(7)
+#define        GPMC_CONFIG3_ADVEXTRADELAY              BIT(7)
+#define        GPMC_CONFIG4_OEEXTRADELAY               BIT(7)
+#define        GPMC_CONFIG4_WEEXTRADELAY               BIT(23)
+#define        GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN        BIT(6)
+#define        GPMC_CONFIG6_CYCLE2CYCLESAMECSEN        BIT(7)
+
 #define GPMC_CS0_OFFSET                0x60
 #define GPMC_CS_SIZE           0x30
 #define        GPMC_BCH_SIZE           0x10
@@ -223,6 +230,51 @@ unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns)
        return ticks * gpmc_get_fclk_period() / 1000;
 }
 
+static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
+{
+       return ticks * gpmc_get_fclk_period();
+}
+
+static unsigned int gpmc_round_ps_to_ticks(unsigned int time_ps)
+{
+       unsigned long ticks = gpmc_ps_to_ticks(time_ps);
+
+       return ticks * gpmc_get_fclk_period();
+}
+
+static inline void gpmc_cs_modify_reg(int cs, int reg, u32 mask, bool value)
+{
+       u32 l;
+
+       l = gpmc_cs_read_reg(cs, reg);
+       if (value)
+               l |= mask;
+       else
+               l &= ~mask;
+       gpmc_cs_write_reg(cs, reg, l);
+}
+
+static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p)
+{
+       gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG1,
+                          GPMC_CONFIG1_TIME_PARA_GRAN,
+                          p->time_para_granularity);
+       gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG2,
+                          GPMC_CONFIG2_CSEXTRADELAY, p->cs_extra_delay);
+       gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG3,
+                          GPMC_CONFIG3_ADVEXTRADELAY, p->adv_extra_delay);
+       gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
+                          GPMC_CONFIG4_OEEXTRADELAY, p->oe_extra_delay);
+       gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
+                          GPMC_CONFIG4_OEEXTRADELAY, p->we_extra_delay);
+       gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
+                          GPMC_CONFIG6_CYCLE2CYCLESAMECSEN,
+                          p->cycle2cyclesamecsen);
+       gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
+                          GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN,
+                          p->cycle2cyclediffcsen);
+}
+
 #ifdef DEBUG
 static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
                               int time, const char *name)
@@ -316,6 +368,12 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 
        GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access);
 
+       GPMC_SET_ONE(GPMC_CS_CONFIG6, 0, 3, bus_turnaround);
+       GPMC_SET_ONE(GPMC_CS_CONFIG6, 8, 11, cycle2cycle_delay);
+
+       GPMC_SET_ONE(GPMC_CS_CONFIG1, 18, 19, wait_monitoring);
+       GPMC_SET_ONE(GPMC_CS_CONFIG1, 25, 26, clk_activation);
+
        if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
                GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
        if (gpmc_capability & GPMC_HAS_WR_ACCESS)
@@ -335,6 +393,8 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
                gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
        }
 
+       gpmc_cs_bool_timings(cs, &t->bool_timings);
+
        return 0;
 }
 
@@ -748,6 +808,319 @@ static int __devinit gpmc_mem_init(void)
        return 0;
 }
 
+static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk)
+{
+       u32 temp;
+       int div;
+
+       div = gpmc_calc_divider(sync_clk);
+       temp = gpmc_ps_to_ticks(time_ps);
+       temp = (temp + div - 1) / div;
+       return gpmc_ticks_to_ps(temp * div);
+}
+
+/* XXX: can the cycles be avoided ? */
+static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
+                               struct gpmc_device_timings *dev_t)
+{
+       bool mux = dev_t->mux;
+       u32 temp;
+
+       /* adv_rd_off */
+       temp = dev_t->t_avdp_r;
+       /* XXX: mux check required ? */
+       if (mux) {
+               /* XXX: t_avdp not to be required for sync, only added for tusb
+                * this indirectly necessitates requirement of t_avdp_r and
+                * t_avdp_w instead of having a single t_avdp
+                */
+               temp = max_t(u32, temp, gpmc_t->clk_activation + dev_t->t_avdh);
+               temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+       }
+       gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
+
+       /* oe_on */
+       temp = dev_t->t_oeasu; /* XXX: remove this ? */
+       if (mux) {
+               temp = max_t(u32, temp, gpmc_t->clk_activation + dev_t->t_ach);
+               temp = max_t(u32, temp, gpmc_t->adv_rd_off +
+                               gpmc_ticks_to_ps(dev_t->cyc_aavdh_oe));
+       }
+       gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
+
+       /* access */
+       /* XXX: any scope for improvement ?, by combining oe_on
+        * and clk_activation, need to check whether
+        * access = clk_activation + round to sync clk ?
+        */
+       temp = max_t(u32, dev_t->t_iaa, dev_t->cyc_iaa * gpmc_t->sync_clk);
+       temp += gpmc_t->clk_activation;
+       if (dev_t->cyc_oe)
+               temp = max_t(u32, temp, gpmc_t->oe_on +
+                               gpmc_ticks_to_ps(dev_t->cyc_oe));
+       gpmc_t->access = gpmc_round_ps_to_ticks(temp);
+
+       gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
+       gpmc_t->cs_rd_off = gpmc_t->oe_off;
+
+       /* rd_cycle */
+       temp = max_t(u32, dev_t->t_cez_r, dev_t->t_oez);
+       temp = gpmc_round_ps_to_sync_clk(temp, gpmc_t->sync_clk) +
+                                                       gpmc_t->access;
+       /* XXX: barter t_ce_rdyz with t_cez_r ? */
+       if (dev_t->t_ce_rdyz)
+               temp = max_t(u32, temp, gpmc_t->cs_rd_off + dev_t->t_ce_rdyz);
+       gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
+
+       return 0;
+}
+
+static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
+                               struct gpmc_device_timings *dev_t)
+{
+       bool mux = dev_t->mux;
+       u32 temp;
+
+       /* adv_wr_off */
+       temp = dev_t->t_avdp_w;
+       if (mux) {
+               temp = max_t(u32, temp,
+                       gpmc_t->clk_activation + dev_t->t_avdh);
+               temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+       }
+       gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
+
+       /* wr_data_mux_bus */
+       temp = max_t(u32, dev_t->t_weasu,
+                       gpmc_t->clk_activation + dev_t->t_rdyo);
+       /* XXX: shouldn't mux be kept as a whole for wr_data_mux_bus ?,
+        * and in that case remember to handle we_on properly
+        */
+       if (mux) {
+               temp = max_t(u32, temp,
+                       gpmc_t->adv_wr_off + dev_t->t_aavdh);
+               temp = max_t(u32, temp, gpmc_t->adv_wr_off +
+                               gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
+       }
+       gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
+
+       /* we_on */
+       if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
+               gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
+       else
+               gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
+
+       /* wr_access */
+       /* XXX: gpmc_capability check reqd ? , even if not, will not harm */
+       gpmc_t->wr_access = gpmc_t->access;
+
+       /* we_off */
+       temp = gpmc_t->we_on + dev_t->t_wpl;
+       temp = max_t(u32, temp,
+                       gpmc_t->wr_access + gpmc_ticks_to_ps(1));
+       temp = max_t(u32, temp,
+               gpmc_t->we_on + gpmc_ticks_to_ps(dev_t->cyc_wpl));
+       gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
+
+       gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
+                                                       dev_t->t_wph);
+
+       /* wr_cycle */
+       temp = gpmc_round_ps_to_sync_clk(dev_t->t_cez_w, gpmc_t->sync_clk);
+       temp += gpmc_t->wr_access;
+       /* XXX: barter t_ce_rdyz with t_cez_w ? */
+       if (dev_t->t_ce_rdyz)
+               temp = max_t(u32, temp,
+                                gpmc_t->cs_wr_off + dev_t->t_ce_rdyz);
+       gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
+
+       return 0;
+}
+
+static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
+                               struct gpmc_device_timings *dev_t)
+{
+       bool mux = dev_t->mux;
+       u32 temp;
+
+       /* adv_rd_off */
+       temp = dev_t->t_avdp_r;
+       if (mux)
+               temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+       gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
+
+       /* oe_on */
+       temp = dev_t->t_oeasu;
+       if (mux)
+               temp = max_t(u32, temp,
+                       gpmc_t->adv_rd_off + dev_t->t_aavdh);
+       gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
+
+       /* access */
+       temp = max_t(u32, dev_t->t_iaa, /* XXX: remove t_iaa in async ? */
+                               gpmc_t->oe_on + dev_t->t_oe);
+       temp = max_t(u32, temp,
+                               gpmc_t->cs_on + dev_t->t_ce);
+       temp = max_t(u32, temp,
+                               gpmc_t->adv_on + dev_t->t_aa);
+       gpmc_t->access = gpmc_round_ps_to_ticks(temp);
+
+       gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
+       gpmc_t->cs_rd_off = gpmc_t->oe_off;
+
+       /* rd_cycle */
+       temp = max_t(u32, dev_t->t_rd_cycle,
+                       gpmc_t->cs_rd_off + dev_t->t_cez_r);
+       temp = max_t(u32, temp, gpmc_t->oe_off + dev_t->t_oez);
+       gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
+
+       return 0;
+}
+
+static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
+                               struct gpmc_device_timings *dev_t)
+{
+       bool mux = dev_t->mux;
+       u32 temp;
+
+       /* adv_wr_off */
+       temp = dev_t->t_avdp_w;
+       if (mux)
+               temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+       gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
+
+       /* wr_data_mux_bus */
+       temp = dev_t->t_weasu;
+       if (mux) {
+               temp = max_t(u32, temp, gpmc_t->adv_wr_off + dev_t->t_aavdh);
+               temp = max_t(u32, temp, gpmc_t->adv_wr_off +
+                               gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
+       }
+       gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
+
+       /* we_on */
+       if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
+               gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
+       else
+               gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
+
+       /* we_off */
+       temp = gpmc_t->we_on + dev_t->t_wpl;
+       gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
+
+       gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
+                                                       dev_t->t_wph);
+
+       /* wr_cycle */
+       temp = max_t(u32, dev_t->t_wr_cycle,
+                               gpmc_t->cs_wr_off + dev_t->t_cez_w);
+       gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
+
+       return 0;
+}
+
+static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t,
+                       struct gpmc_device_timings *dev_t)
+{
+       u32 temp;
+
+       gpmc_t->sync_clk = gpmc_calc_divider(dev_t->clk) *
+                                               gpmc_get_fclk_period();
+
+       gpmc_t->page_burst_access = gpmc_round_ps_to_sync_clk(
+                                       dev_t->t_bacc,
+                                       gpmc_t->sync_clk);
+
+       temp = max_t(u32, dev_t->t_ces, dev_t->t_avds);
+       gpmc_t->clk_activation = gpmc_round_ps_to_ticks(temp);
+
+       if (gpmc_calc_divider(gpmc_t->sync_clk) != 1)
+               return 0;
+
+       if (dev_t->ce_xdelay)
+               gpmc_t->bool_timings.cs_extra_delay = true;
+       if (dev_t->avd_xdelay)
+               gpmc_t->bool_timings.adv_extra_delay = true;
+       if (dev_t->oe_xdelay)
+               gpmc_t->bool_timings.oe_extra_delay = true;
+       if (dev_t->we_xdelay)
+               gpmc_t->bool_timings.we_extra_delay = true;
+
+       return 0;
+}
+
+static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t,
+                       struct gpmc_device_timings *dev_t)
+{
+       u32 temp;
+
+       /* cs_on */
+       gpmc_t->cs_on = gpmc_round_ps_to_ticks(dev_t->t_ceasu);
+
+       /* adv_on */
+       temp = dev_t->t_avdasu;
+       if (dev_t->t_ce_avd)
+               temp = max_t(u32, temp,
+                               gpmc_t->cs_on + dev_t->t_ce_avd);
+       gpmc_t->adv_on = gpmc_round_ps_to_ticks(temp);
+
+       if (dev_t->sync_write || dev_t->sync_read)
+               gpmc_calc_sync_common_timings(gpmc_t, dev_t);
+
+       return 0;
+}
+
+/* TODO: remove this function once all peripherals are confirmed to
+ * work with generic timing. Simultaneously gpmc_cs_set_timings()
+ * has to be modified to handle timings in ps instead of ns
+*/
+static void gpmc_convert_ps_to_ns(struct gpmc_timings *t)
+{
+       t->cs_on /= 1000;
+       t->cs_rd_off /= 1000;
+       t->cs_wr_off /= 1000;
+       t->adv_on /= 1000;
+       t->adv_rd_off /= 1000;
+       t->adv_wr_off /= 1000;
+       t->we_on /= 1000;
+       t->we_off /= 1000;
+       t->oe_on /= 1000;
+       t->oe_off /= 1000;
+       t->page_burst_access /= 1000;
+       t->access /= 1000;
+       t->rd_cycle /= 1000;
+       t->wr_cycle /= 1000;
+       t->bus_turnaround /= 1000;
+       t->cycle2cycle_delay /= 1000;
+       t->wait_monitoring /= 1000;
+       t->clk_activation /= 1000;
+       t->wr_access /= 1000;
+       t->wr_data_mux_bus /= 1000;
+}
+
+int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
+                       struct gpmc_device_timings *dev_t)
+{
+       memset(gpmc_t, 0, sizeof(*gpmc_t));
+
+       gpmc_calc_common_timings(gpmc_t, dev_t);
+
+       if (dev_t->sync_read)
+               gpmc_calc_sync_read_timings(gpmc_t, dev_t);
+       else
+               gpmc_calc_async_read_timings(gpmc_t, dev_t);
+
+       if (dev_t->sync_write)
+               gpmc_calc_sync_write_timings(gpmc_t, dev_t);
+       else
+               gpmc_calc_async_write_timings(gpmc_t, dev_t);
+
+       /* TODO: remove, see function definition */
+       gpmc_convert_ps_to_ns(gpmc_t);
+
+       return 0;
+}
+
 static __devinit int gpmc_probe(struct platform_device *pdev)
 {
        int rc;
index 79f4dfc2adb3cec5d6f40af94796bc8558492a99..fe0a844d5007a7775cadf78e357b541bbb80b153 100644 (file)
 #define GPMC_IRQ_COUNT_EVENT           0x02
 
 
+/* bool type time settings */
+struct gpmc_bool_timings {
+       bool cycle2cyclediffcsen;
+       bool cycle2cyclesamecsen;
+       bool we_extra_delay;
+       bool oe_extra_delay;
+       bool adv_extra_delay;
+       bool cs_extra_delay;
+       bool time_para_granularity;
+};
+
 /*
  * Note that all values in this struct are in nanoseconds except sync_clk
  * (which is in picoseconds), while the register values are in gpmc_fck cycles.
@@ -83,34 +94,104 @@ struct gpmc_timings {
        u32 sync_clk;
 
        /* Chip-select signal timings corresponding to GPMC_CS_CONFIG2 */
-       u16 cs_on;              /* Assertion time */
-       u16 cs_rd_off;          /* Read deassertion time */
-       u16 cs_wr_off;          /* Write deassertion time */
+       u32 cs_on;              /* Assertion time */
+       u32 cs_rd_off;          /* Read deassertion time */
+       u32 cs_wr_off;          /* Write deassertion time */
 
        /* ADV signal timings corresponding to GPMC_CONFIG3 */
-       u16 adv_on;             /* Assertion time */
-       u16 adv_rd_off;         /* Read deassertion time */
-       u16 adv_wr_off;         /* Write deassertion time */
+       u32 adv_on;             /* Assertion time */
+       u32 adv_rd_off;         /* Read deassertion time */
+       u32 adv_wr_off;         /* Write deassertion time */
 
        /* WE signals timings corresponding to GPMC_CONFIG4 */
-       u16 we_on;              /* WE assertion time */
-       u16 we_off;             /* WE deassertion time */
+       u32 we_on;              /* WE assertion time */
+       u32 we_off;             /* WE deassertion time */
 
        /* OE signals timings corresponding to GPMC_CONFIG4 */
-       u16 oe_on;              /* OE assertion time */
-       u16 oe_off;             /* OE deassertion time */
+       u32 oe_on;              /* OE assertion time */
+       u32 oe_off;             /* OE deassertion time */
 
        /* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
-       u16 page_burst_access;  /* Multiple access word delay */
-       u16 access;             /* Start-cycle to first data valid delay */
-       u16 rd_cycle;           /* Total read cycle time */
-       u16 wr_cycle;           /* Total write cycle time */
+       u32 page_burst_access;  /* Multiple access word delay */
+       u32 access;             /* Start-cycle to first data valid delay */
+       u32 rd_cycle;           /* Total read cycle time */
+       u32 wr_cycle;           /* Total write cycle time */
+
+       u32 bus_turnaround;
+       u32 cycle2cycle_delay;
+
+       u32 wait_monitoring;
+       u32 clk_activation;
 
        /* The following are only on OMAP3430 */
-       u16 wr_access;          /* WRACCESSTIME */
-       u16 wr_data_mux_bus;    /* WRDATAONADMUXBUS */
+       u32 wr_access;          /* WRACCESSTIME */
+       u32 wr_data_mux_bus;    /* WRDATAONADMUXBUS */
+
+       struct gpmc_bool_timings bool_timings;
+};
+
+/* Device timings in picoseconds */
+struct gpmc_device_timings {
+       u32 t_ceasu;    /* address setup to CS valid */
+       u32 t_avdasu;   /* address setup to ADV valid */
+       /* XXX: try to combine t_avdp_r & t_avdp_w. Issue is
+        * of tusb using these timings even for sync whilst
+        * ideally for adv_rd/(wr)_off it should have considered
+        * t_avdh instead. This indirectly necessitates r/w
+        * variations of t_avdp as it is possible to have one
+        * sync & other async
+        */
+       u32 t_avdp_r;   /* ADV low time (what about t_cer ?) */
+       u32 t_avdp_w;
+       u32 t_aavdh;    /* address hold time */
+       u32 t_oeasu;    /* address setup to OE valid */
+       u32 t_aa;       /* access time from ADV assertion */
+       u32 t_iaa;      /* initial access time */
+       u32 t_oe;       /* access time from OE assertion */
+       u32 t_ce;       /* access time from CS asertion */
+       u32 t_rd_cycle; /* read cycle time */
+       u32 t_cez_r;    /* read CS deassertion to high Z */
+       u32 t_cez_w;    /* write CS deassertion to high Z */
+       u32 t_oez;      /* OE deassertion to high Z */
+       u32 t_weasu;    /* address setup to WE valid */
+       u32 t_wpl;      /* write assertion time */
+       u32 t_wph;      /* write deassertion time */
+       u32 t_wr_cycle; /* write cycle time */
+
+       u32 clk;
+       u32 t_bacc;     /* burst access valid clock to output delay */
+       u32 t_ces;      /* CS setup time to clk */
+       u32 t_avds;     /* ADV setup time to clk */
+       u32 t_avdh;     /* ADV hold time from clk */
+       u32 t_ach;      /* address hold time from clk */
+       u32 t_rdyo;     /* clk to ready valid */
+
+       u32 t_ce_rdyz;  /* XXX: description ?, or use t_cez instead */
+       u32 t_ce_avd;   /* CS on to ADV on delay */
+
+       /* XXX: check the possibility of combining
+        * cyc_aavhd_oe & cyc_aavdh_we
+        */
+       u8 cyc_aavdh_oe;/* read address hold time in cycles */
+       u8 cyc_aavdh_we;/* write address hold time in cycles */
+       u8 cyc_oe;      /* access time from OE assertion in cycles */
+       u8 cyc_wpl;     /* write deassertion time in cycles */
+       u32 cyc_iaa;    /* initial access time in cycles */
+
+       bool mux;       /* address & data muxed */
+       bool sync_write;/* synchronous write */
+       bool sync_read; /* synchronous read */
+
+       /* extra delays */
+       bool ce_xdelay;
+       bool avd_xdelay;
+       bool oe_xdelay;
+       bool we_xdelay;
 };
 
+extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
+                               struct gpmc_device_timings *dev_t);
+
 extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
 extern int gpmc_get_client_irq(unsigned irq_config);
 
index a8795ff19e6deb6f415ee01b584fb0047e40e27b..c5a3c6f9504e79c8085e12e0aac10904a5177ab3 100644 (file)
@@ -27,180 +27,88 @@ static u8          async_cs, sync_cs;
 static unsigned                refclk_psec;
 
 
-/* t2_ps, when quantized to fclk units, must happen no earlier than
- * the clock after after t1_NS.
- *
- * Return a possibly updated value of t2_ps, converted to nsec.
- */
-static unsigned
-next_clk(unsigned t1_NS, unsigned t2_ps, unsigned fclk_ps)
-{
-       unsigned        t1_ps = t1_NS * 1000;
-       unsigned        t1_f, t2_f;
-
-       if ((t1_ps + fclk_ps) < t2_ps)
-               return t2_ps / 1000;
-
-       t1_f = (t1_ps + fclk_ps - 1) / fclk_ps;
-       t2_f = (t2_ps + fclk_ps - 1) / fclk_ps;
-
-       if (t1_f >= t2_f)
-               t2_f = t1_f + 1;
-
-       return (t2_f * fclk_ps) / 1000;
-}
-
 /* NOTE:  timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */
 
-static int tusb_set_async_mode(unsigned sysclk_ps, unsigned fclk_ps)
+static int tusb_set_async_mode(unsigned sysclk_ps)
 {
+       struct gpmc_device_timings dev_t;
        struct gpmc_timings     t;
        unsigned                t_acsnh_advnh = sysclk_ps + 3000;
-       unsigned                tmp;
-
-       memset(&t, 0, sizeof(t));
-
-       /* CS_ON = t_acsnh_acsnl */
-       t.cs_on = 8;
-       /* ADV_ON = t_acsnh_advnh - t_advn */
-       t.adv_on = next_clk(t.cs_on, t_acsnh_advnh - 7000, fclk_ps);
-
-       /*
-        * READ ... from omap2420 TRM fig 12-13
-        */
-
-       /* ADV_RD_OFF = t_acsnh_advnh */
-       t.adv_rd_off = next_clk(t.adv_on, t_acsnh_advnh, fclk_ps);
-
-       /* OE_ON = t_acsnh_advnh + t_advn_oen (then wait for nRDY) */
-       t.oe_on = next_clk(t.adv_on, t_acsnh_advnh + 1000, fclk_ps);
-
-       /* ACCESS = counters continue only after nRDY */
-       tmp = t.oe_on * 1000 + 300;
-       t.access = next_clk(t.oe_on, tmp, fclk_ps);
-
-       /* OE_OFF = after data gets sampled */
-       tmp = t.access * 1000;
-       t.oe_off = next_clk(t.access, tmp, fclk_ps);
-
-       t.cs_rd_off = t.oe_off;
-
-       tmp = t.cs_rd_off * 1000 + 7000 /* t_acsn_rdy_z */;
-       t.rd_cycle = next_clk(t.cs_rd_off, tmp, fclk_ps);
-
-       /*
-        * WRITE ... from omap2420 TRM fig 12-15
-        */
-
-       /* ADV_WR_OFF = t_acsnh_advnh */
-       t.adv_wr_off = t.adv_rd_off;
 
-       /* WE_ON = t_acsnh_advnh + t_advn_wen (then wait for nRDY) */
-       t.we_on = next_clk(t.adv_wr_off, t_acsnh_advnh + 1000, fclk_ps);
+       memset(&dev_t, 0, sizeof(dev_t));
 
-       /* WE_OFF = after data gets sampled */
-       tmp = t.we_on * 1000 + 300;
-       t.we_off = next_clk(t.we_on, tmp, fclk_ps);
+       dev_t.mux = true;
 
-       t.cs_wr_off = t.we_off;
+       dev_t.t_ceasu = 8 * 1000;
+       dev_t.t_avdasu = t_acsnh_advnh - 7000;
+       dev_t.t_ce_avd = 1000;
+       dev_t.t_avdp_r = t_acsnh_advnh;
+       dev_t.t_oeasu = t_acsnh_advnh + 1000;
+       dev_t.t_oe = 300;
+       dev_t.t_cez_r = 7000;
+       dev_t.t_cez_w = dev_t.t_cez_r;
+       dev_t.t_avdp_w = t_acsnh_advnh;
+       dev_t.t_weasu = t_acsnh_advnh + 1000;
+       dev_t.t_wpl = 300;
+       dev_t.cyc_aavdh_we = 1;
 
-       tmp = t.cs_wr_off * 1000 + 7000 /* t_acsn_rdy_z */;
-       t.wr_cycle = next_clk(t.cs_wr_off, tmp, fclk_ps);
+       gpmc_calc_timings(&t, &dev_t);
 
        return gpmc_cs_set_timings(async_cs, &t);
 }
 
-static int tusb_set_sync_mode(unsigned sysclk_ps, unsigned fclk_ps)
+static int tusb_set_sync_mode(unsigned sysclk_ps)
 {
+       struct gpmc_device_timings dev_t;
        struct gpmc_timings     t;
        unsigned                t_scsnh_advnh = sysclk_ps + 3000;
-       unsigned                tmp;
-
-       memset(&t, 0, sizeof(t));
-       t.cs_on = 8;
-
-       /* ADV_ON = t_acsnh_advnh - t_advn */
-       t.adv_on = next_clk(t.cs_on, t_scsnh_advnh - 7000, fclk_ps);
-
-       /* GPMC_CLK rate = fclk rate / div */
-       t.sync_clk = 11100 /* 11.1 nsec */;
-       tmp = (t.sync_clk + fclk_ps - 1) / fclk_ps;
-       if (tmp > 4)
-               return -ERANGE;
-       if (tmp == 0)
-               tmp = 1;
-       t.page_burst_access = (fclk_ps * tmp) / 1000;
-
-       /*
-        * READ ... based on omap2420 TRM fig 12-19, 12-20
-        */
-
-       /* ADV_RD_OFF = t_scsnh_advnh */
-       t.adv_rd_off = next_clk(t.adv_on, t_scsnh_advnh, fclk_ps);
-
-       /* OE_ON = t_scsnh_advnh + t_advn_oen * fclk_ps (then wait for nRDY) */
-       tmp = (t.adv_rd_off * 1000) + (3 * fclk_ps);
-       t.oe_on = next_clk(t.adv_on, tmp, fclk_ps);
-
-       /* ACCESS = number of clock cycles after t_adv_eon */
-       tmp = (t.oe_on * 1000) + (5 * fclk_ps);
-       t.access = next_clk(t.oe_on, tmp, fclk_ps);
 
-       /* OE_OFF = after data gets sampled */
-       tmp = (t.access * 1000) + (1 * fclk_ps);
-       t.oe_off = next_clk(t.access, tmp, fclk_ps);
-
-       t.cs_rd_off = t.oe_off;
-
-       tmp = t.cs_rd_off * 1000 + 7000 /* t_scsn_rdy_z */;
-       t.rd_cycle = next_clk(t.cs_rd_off, tmp, fclk_ps);
-
-       /*
-        * WRITE ... based on omap2420 TRM fig 12-21
-        */
-
-       /* ADV_WR_OFF = t_scsnh_advnh */
-       t.adv_wr_off = t.adv_rd_off;
-
-       /* WE_ON = t_scsnh_advnh + t_advn_wen * fclk_ps (then wait for nRDY) */
-       tmp = (t.adv_wr_off * 1000) + (3 * fclk_ps);
-       t.we_on = next_clk(t.adv_wr_off, tmp, fclk_ps);
-
-       /* WE_OFF = number of clock cycles after t_adv_wen */
-       tmp = (t.we_on * 1000) + (6 * fclk_ps);
-       t.we_off = next_clk(t.we_on, tmp, fclk_ps);
-
-       t.cs_wr_off = t.we_off;
-
-       tmp = t.cs_wr_off * 1000 + 7000 /* t_scsn_rdy_z */;
-       t.wr_cycle = next_clk(t.cs_wr_off, tmp, fclk_ps);
+       memset(&dev_t, 0, sizeof(dev_t));
+
+       dev_t.mux = true;
+       dev_t.sync_read = true;
+       dev_t.sync_write = true;
+
+       dev_t.clk = 11100;
+       dev_t.t_bacc = 1000;
+       dev_t.t_ces = 1000;
+       dev_t.t_ceasu = 8 * 1000;
+       dev_t.t_avdasu = t_scsnh_advnh - 7000;
+       dev_t.t_ce_avd = 1000;
+       dev_t.t_avdp_r = t_scsnh_advnh;
+       dev_t.cyc_aavdh_oe = 3;
+       dev_t.cyc_oe = 5;
+       dev_t.t_ce_rdyz = 7000;
+       dev_t.t_avdp_w = t_scsnh_advnh;
+       dev_t.cyc_aavdh_we = 3;
+       dev_t.cyc_wpl = 6;
+       dev_t.t_ce_rdyz = 7000;
+
+       gpmc_calc_timings(&t, &dev_t);
 
        return gpmc_cs_set_timings(sync_cs, &t);
 }
 
-extern unsigned long gpmc_get_fclk_period(void);
-
 /* tusb driver calls this when it changes the chip's clocking */
 int tusb6010_platform_retime(unsigned is_refclk)
 {
        static const char       error[] =
                KERN_ERR "tusb6010 %s retime error %d\n";
 
-       unsigned        fclk_ps = gpmc_get_fclk_period();
        unsigned        sysclk_ps;
        int             status;
 
-       if (!refclk_psec || fclk_ps == 0)
+       if (!refclk_psec)
                return -ENODEV;
 
        sysclk_ps = is_refclk ? refclk_psec : TUSB6010_OSCCLK_60;
 
-       status = tusb_set_async_mode(sysclk_ps, fclk_ps);
+       status = tusb_set_async_mode(sysclk_ps);
        if (status < 0) {
                printk(error, "async", status);
                goto done;
        }
-       status = tusb_set_sync_mode(sysclk_ps, fclk_ps);
+       status = tusb_set_sync_mode(sysclk_ps);
        if (status < 0)
                printk(error, "sync", status);
 done:
@@ -284,7 +192,6 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
                        | GPMC_CONFIG1_READTYPE_SYNC
                        | GPMC_CONFIG1_WRITEMULTIPLE_SUPP
                        | GPMC_CONFIG1_WRITETYPE_SYNC
-                       | GPMC_CONFIG1_CLKACTIVATIONTIME(1)
                        | GPMC_CONFIG1_PAGE_LEN(2)
                        | GPMC_CONFIG1_WAIT_READ_MON
                        | GPMC_CONFIG1_WAIT_WRITE_MON
index c34d4efd0d5c46987775b47c1393349760d60c27..0a3f30df1eb8cb9c45d375b465fe2a94ef8df6aa 100644 (file)
@@ -33,8 +33,6 @@ BIAS(in_nopull, PIN_INPUT_NOPULL);
 BIAS(in_nopull_slpm_nowkup, PIN_INPUT_NOPULL|PIN_SLPM_WAKEUP_DISABLE);
 BIAS(in_pu, PIN_INPUT_PULLUP);
 BIAS(in_pd, PIN_INPUT_PULLDOWN);
-BIAS(in_pd_slpm_in_pu, PIN_INPUT_PULLDOWN|PIN_SLPM_INPUT_PULLUP);
-BIAS(in_pu_slpm_out_lo, PIN_INPUT_PULLUP|PIN_SLPM_OUTPUT_LOW);
 BIAS(out_hi, PIN_OUTPUT_HIGH);
 BIAS(out_lo, PIN_OUTPUT_LOW);
 BIAS(out_lo_slpm_nowkup, PIN_OUTPUT_LOW|PIN_SLPM_WAKEUP_DISABLE);
@@ -46,14 +44,34 @@ BIAS(gpio_in_pd_slpm_gpio_nopull, PIN_INPUT_PULLDOWN|PIN_GPIOMODE_ENABLED|PIN_SL
 BIAS(gpio_out_hi, PIN_OUTPUT_HIGH|PIN_GPIOMODE_ENABLED);
 BIAS(gpio_out_lo, PIN_OUTPUT_LOW|PIN_GPIOMODE_ENABLED);
 /* Sleep modes */
-BIAS(slpm_in_wkup_pdis, PIN_SLEEPMODE_ENABLED|PIN_SLPM_DIR_INPUT|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
-BIAS(slpm_in_nopull_wkup, PIN_SLEEPMODE_ENABLED|PIN_SLPM_DIR_INPUT|PIN_SLPM_PULL_NONE|PIN_SLPM_WAKEUP_ENABLE);
-BIAS(slpm_wkup_pdis, PIN_SLEEPMODE_ENABLED|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
-BIAS(slpm_out_hi_wkup_pdis, PIN_SLEEPMODE_ENABLED|PIN_SLPM_OUTPUT_HIGH|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
-BIAS(slpm_out_wkup_pdis, PIN_SLEEPMODE_ENABLED|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
-BIAS(slpm_out_lo_wkup, PIN_SLEEPMODE_ENABLED|PIN_SLPM_OUTPUT_LOW|PIN_SLPM_WAKEUP_ENABLE);
-BIAS(slpm_out_lo_wkup_pdis, PIN_SLEEPMODE_ENABLED|PIN_SLPM_OUTPUT_LOW|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
-BIAS(slpm_in_nopull_wkup_pdis, PIN_SLEEPMODE_ENABLED|PIN_SLPM_INPUT_NOPULL|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
+BIAS(slpm_in_nopull_wkup, PIN_SLEEPMODE_ENABLED|
+       PIN_SLPM_DIR_INPUT|PIN_SLPM_PULL_NONE|PIN_SLPM_WAKEUP_ENABLE);
+BIAS(slpm_in_wkup_pdis, PIN_SLEEPMODE_ENABLED|
+       PIN_SLPM_DIR_INPUT|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
+BIAS(slpm_wkup_pdis, PIN_SLEEPMODE_ENABLED|
+       PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
+BIAS(slpm_out_lo_pdis, PIN_SLEEPMODE_ENABLED|
+       PIN_SLPM_OUTPUT_LOW|PIN_SLPM_WAKEUP_DISABLE|PIN_SLPM_PDIS_DISABLED);
+BIAS(slpm_out_lo_wkup, PIN_SLEEPMODE_ENABLED|
+       PIN_SLPM_OUTPUT_LOW|PIN_SLPM_WAKEUP_ENABLE);
+BIAS(slpm_out_lo_wkup_pdis, PIN_SLEEPMODE_ENABLED|
+       PIN_SLPM_OUTPUT_LOW|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
+BIAS(slpm_out_hi_wkup_pdis, PIN_SLEEPMODE_ENABLED|PIN_SLPM_OUTPUT_HIGH|
+       PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
+BIAS(slpm_in_nopull_wkup_pdis, PIN_SLEEPMODE_ENABLED|
+       PIN_SLPM_INPUT_NOPULL|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
+BIAS(slpm_in_pu_wkup_pdis_en, PIN_SLEEPMODE_ENABLED|PIN_SLPM_INPUT_PULLUP|
+       PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_ENABLED);
+BIAS(slpm_out_wkup_pdis, PIN_SLEEPMODE_ENABLED|
+       PIN_SLPM_DIR_OUTPUT|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
+BIAS(out_lo_wkup_pdis, PIN_SLPM_OUTPUT_LOW|
+       PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
+BIAS(in_wkup_pdis_en, PIN_SLPM_DIR_INPUT|PIN_SLPM_WAKEUP_ENABLE|
+       PIN_SLPM_PDIS_ENABLED);
+BIAS(in_wkup_pdis, PIN_SLPM_DIR_INPUT|PIN_SLPM_WAKEUP_ENABLE|
+       PIN_SLPM_PDIS_DISABLED);
+BIAS(out_wkup_pdis, PIN_SLPM_DIR_OUTPUT|PIN_SLPM_WAKEUP_ENABLE|
+       PIN_SLPM_PDIS_DISABLED);
 
 /* We use these to define hog settings that are always done on boot */
 #define DB8500_MUX_HOG(group,func) \
@@ -69,13 +87,16 @@ BIAS(slpm_in_nopull_wkup_pdis, PIN_SLEEPMODE_ENABLED|PIN_SLPM_INPUT_NOPULL|PIN_S
        PIN_MAP_MUX_GROUP_DEFAULT(dev, "pinctrl-db8500", group, func)
 #define DB8500_PIN(pin,conf,dev) \
        PIN_MAP_CONFIGS_PIN_DEFAULT(dev, "pinctrl-db8500", pin, conf)
-#define DB8500_PIN_SLEEP(pin, conf, dev) \
-       PIN_MAP_CONFIGS_PIN(dev, PINCTRL_STATE_SLEEP, "pinctrl-db8500", \
+#define DB8500_PIN_IDLE(pin, conf, dev) \
+       PIN_MAP_CONFIGS_PIN(dev, PINCTRL_STATE_IDLE, "pinctrl-db8500",  \
                            pin, conf)
-
-#define DB8500_PIN_SLEEP(pin,conf,dev) \
+#define DB8500_PIN_SLEEP(pin, conf, dev) \
        PIN_MAP_CONFIGS_PIN(dev, PINCTRL_STATE_SLEEP, "pinctrl-db8500", \
                            pin, conf)
+#define DB8500_MUX_STATE(group, func, dev, state) \
+       PIN_MAP_MUX_GROUP(dev, state, "pinctrl-db8500", group, func)
+#define DB8500_PIN_STATE(pin, conf, dev, state) \
+       PIN_MAP_CONFIGS_PIN(dev, state, "pinctrl-db8500", pin, conf)
 
 /* Pin control settings */
 static struct pinctrl_map __initdata mop500_family_pinmap[] = {
@@ -112,7 +133,7 @@ static struct pinctrl_map __initdata mop500_family_pinmap[] = {
         * UART0, we do not mux in u0 here.
         * uart-0 pins gpio configuration should be kept intact to prevent
         * a glitch in tx line when the tty dev is opened. Later these pins
-        * are configured to uart mop500_pins_uart0
+        * are configured by uart driver
         */
        DB8500_PIN_HOG("GPIO0_AJ5", in_pu), /* CTS */
        DB8500_PIN_HOG("GPIO1_AJ3", out_hi), /* RTS */
@@ -123,12 +144,13 @@ static struct pinctrl_map __initdata mop500_family_pinmap[] = {
         * TODO: is this used on U8500 variants and Snowball really?
         * The setting on GPIO31 conflicts with magnetometer use on hrefv60
         */
-       DB8500_MUX_HOG("u2rxtx_c_1", "u2"),
-       DB8500_MUX_HOG("u2ctsrts_c_1", "u2"),
-       DB8500_PIN_HOG("GPIO29_W2", in_pu), /* RXD */
-       DB8500_PIN_HOG("GPIO30_W3", out_hi), /* TXD */
-       DB8500_PIN_HOG("GPIO31_V3", in_pu), /* CTS */
-       DB8500_PIN_HOG("GPIO32_V2", out_hi), /* RTS */
+       /* default state for UART2 */
+       DB8500_MUX("u2rxtx_c_1", "u2", "uart2"),
+       DB8500_PIN("GPIO29_W2", in_pu, "uart2"), /* RXD */
+       DB8500_PIN("GPIO30_W3", out_hi, "uart2"), /* TXD */
+       /* Sleep state for UART2 */
+       DB8500_PIN_SLEEP("GPIO29_W2", in_wkup_pdis, "uart2"),
+       DB8500_PIN_SLEEP("GPIO30_W3", out_wkup_pdis, "uart2"),
        /*
         * The following pin sets were known as "runtime pins" before being
         * converted to the pinctrl model. Here we model them as "default"
@@ -140,11 +162,18 @@ static struct pinctrl_map __initdata mop500_family_pinmap[] = {
        DB8500_PIN("GPIO1_AJ3", out_hi, "uart0"), /* RTS */
        DB8500_PIN("GPIO2_AH4", in_pu, "uart0"), /* RXD */
        DB8500_PIN("GPIO3_AH3", out_hi, "uart0"), /* TXD */
-       /* UART0 sleep state */
+       /* Sleep state for UART0 */
        DB8500_PIN_SLEEP("GPIO0_AJ5", slpm_in_wkup_pdis, "uart0"),
        DB8500_PIN_SLEEP("GPIO1_AJ3", slpm_out_hi_wkup_pdis, "uart0"),
        DB8500_PIN_SLEEP("GPIO2_AH4", slpm_in_wkup_pdis, "uart0"),
        DB8500_PIN_SLEEP("GPIO3_AH3", slpm_out_wkup_pdis, "uart0"),
+       /* Mux in UART1 after initialization */
+       DB8500_MUX("u1rxtx_a_1", "u1", "uart1"),
+       DB8500_PIN("GPIO4_AH6", in_pu, "uart1"), /* RXD */
+       DB8500_PIN("GPIO5_AG6", out_hi, "uart1"), /* TXD */
+       /* Sleep state for UART1 */
+       DB8500_PIN_SLEEP("GPIO4_AH6", slpm_in_wkup_pdis, "uart1"),
+       DB8500_PIN_SLEEP("GPIO5_AG6", slpm_out_wkup_pdis, "uart1"),
        /* MSP1 for ALSA codec */
        DB8500_MUX("msp1txrx_a_1", "msp1", "ux500-msp-i2s.1"),
        DB8500_MUX("msp1_a_1", "msp1", "ux500-msp-i2s.1"),
@@ -161,7 +190,10 @@ static struct pinctrl_map __initdata mop500_family_pinmap[] = {
        DB8500_MUX("lcd_d8_d11_a_1", "lcd", "mcde-tvout"),
        DB8500_MUX("lcdaclk_b_1", "lcda", "mcde-tvout"),
        /* Mux in LCD VSI1 and pull it up for MCDE HDMI output */
-       DB8500_MUX("lcdvsi1_a_1", "lcd", "av8100-hdmi"),
+       DB8500_MUX("lcdvsi1_a_1", "lcd", "0-0070"),
+       DB8500_PIN("GPIO69_E2", in_pu, "0-0070"),
+       /* LCD VSI1 sleep state */
+       DB8500_PIN_SLEEP("GPIO69_E2", slpm_in_wkup_pdis, "0-0070"),
        /* Mux in i2c0 block, default state */
        DB8500_MUX("i2c0_a_1", "i2c0", "nmk-i2c.0"),
        /* i2c0 sleep state */
@@ -194,6 +226,18 @@ static struct pinctrl_map __initdata mop500_family_pinmap[] = {
        DB8500_PIN("GPIO26_Y2", in_pu, "sdi0"), /* DAT1 */
        DB8500_PIN("GPIO27_AA2", in_pu, "sdi0"), /* DAT2 */
        DB8500_PIN("GPIO28_AA1", in_pu, "sdi0"), /* DAT3 */
+       /* SDI0 sleep state */
+       DB8500_PIN_SLEEP("GPIO18_AC2", slpm_out_hi_wkup_pdis, "sdi0"),
+       DB8500_PIN_SLEEP("GPIO19_AC1", slpm_out_hi_wkup_pdis, "sdi0"),
+       DB8500_PIN_SLEEP("GPIO20_AB4", slpm_out_hi_wkup_pdis, "sdi0"),
+       DB8500_PIN_SLEEP("GPIO22_AA3", slpm_in_wkup_pdis, "sdi0"),
+       DB8500_PIN_SLEEP("GPIO23_AA4", slpm_out_lo_wkup_pdis, "sdi0"),
+       DB8500_PIN_SLEEP("GPIO24_AB2", slpm_in_wkup_pdis, "sdi0"),
+       DB8500_PIN_SLEEP("GPIO25_Y4", slpm_in_wkup_pdis, "sdi0"),
+       DB8500_PIN_SLEEP("GPIO26_Y2", slpm_in_wkup_pdis, "sdi0"),
+       DB8500_PIN_SLEEP("GPIO27_AA2", slpm_in_wkup_pdis, "sdi0"),
+       DB8500_PIN_SLEEP("GPIO28_AA1", slpm_in_wkup_pdis, "sdi0"),
+
        /* Mux in SDI1 (here called MC1) used for SDIO for CW1200 WLAN */
        DB8500_MUX("mc1_a_1", "mc1", "sdi1"),
        DB8500_PIN("GPIO208_AH16", out_lo, "sdi1"), /* CLK */
@@ -203,6 +247,15 @@ static struct pinctrl_map __initdata mop500_family_pinmap[] = {
        DB8500_PIN("GPIO212_AF13", in_pu, "sdi1"), /* DAT1 */
        DB8500_PIN("GPIO213_AG13", in_pu, "sdi1"), /* DAT2 */
        DB8500_PIN("GPIO214_AH15", in_pu, "sdi1"), /* DAT3 */
+       /* SDI1 sleep state */
+       DB8500_PIN_SLEEP("GPIO208_AH16", slpm_out_lo_wkup_pdis, "sdi1"), /* CLK */
+       DB8500_PIN_SLEEP("GPIO209_AG15", slpm_in_wkup_pdis, "sdi1"), /* FBCLK */
+       DB8500_PIN_SLEEP("GPIO210_AJ15", slpm_in_wkup_pdis, "sdi1"), /* CMD */
+       DB8500_PIN_SLEEP("GPIO211_AG14", slpm_in_wkup_pdis, "sdi1"), /* DAT0 */
+       DB8500_PIN_SLEEP("GPIO212_AF13", slpm_in_wkup_pdis, "sdi1"), /* DAT1 */
+       DB8500_PIN_SLEEP("GPIO213_AG13", slpm_in_wkup_pdis, "sdi1"), /* DAT2 */
+       DB8500_PIN_SLEEP("GPIO214_AH15", slpm_in_wkup_pdis, "sdi1"), /* DAT3 */
+
        /* Mux in SDI2 (here called MC2) used for for PoP eMMC */
        DB8500_MUX("mc2_a_1", "mc2", "sdi2"),
        DB8500_PIN("GPIO128_A5", out_lo, "sdi2"), /* CLK */
@@ -216,6 +269,19 @@ static struct pinctrl_map __initdata mop500_family_pinmap[] = {
        DB8500_PIN("GPIO136_C7", in_pu, "sdi2"), /* DAT5 */
        DB8500_PIN("GPIO137_A7", in_pu, "sdi2"), /* DAT6 */
        DB8500_PIN("GPIO138_C5", in_pu, "sdi2"), /* DAT7 */
+       /* SDI2 sleep state */
+       DB8500_PIN_SLEEP("GPIO128_A5", out_lo_wkup_pdis, "sdi2"), /* CLK */
+       DB8500_PIN_SLEEP("GPIO129_B4", in_wkup_pdis_en, "sdi2"), /* CMD */
+       DB8500_PIN_SLEEP("GPIO130_C8", in_wkup_pdis_en, "sdi2"), /* FBCLK */
+       DB8500_PIN_SLEEP("GPIO131_A12", in_wkup_pdis, "sdi2"), /* DAT0 */
+       DB8500_PIN_SLEEP("GPIO132_C10", in_wkup_pdis, "sdi2"), /* DAT1 */
+       DB8500_PIN_SLEEP("GPIO133_B10", in_wkup_pdis, "sdi2"), /* DAT2 */
+       DB8500_PIN_SLEEP("GPIO134_B9", in_wkup_pdis, "sdi2"), /* DAT3 */
+       DB8500_PIN_SLEEP("GPIO135_A9", in_wkup_pdis, "sdi2"), /* DAT4 */
+       DB8500_PIN_SLEEP("GPIO136_C7", in_wkup_pdis, "sdi2"), /* DAT5 */
+       DB8500_PIN_SLEEP("GPIO137_A7", in_wkup_pdis, "sdi2"), /* DAT6 */
+       DB8500_PIN_SLEEP("GPIO138_C5", in_wkup_pdis, "sdi2"), /* DAT7 */
+
        /* Mux in SDI4 (here called MC4) used for for PCB-mounted eMMC */
        DB8500_MUX("mc4_a_1", "mc4", "sdi4"),
        DB8500_PIN("GPIO197_AH24", in_pu, "sdi4"), /* DAT3 */
@@ -229,6 +295,19 @@ static struct pinctrl_map __initdata mop500_family_pinmap[] = {
        DB8500_PIN("GPIO205_AG23", in_pu, "sdi4"), /* DAT6 */
        DB8500_PIN("GPIO206_AG24", in_pu, "sdi4"), /* DAT5 */
        DB8500_PIN("GPIO207_AJ23", in_pu, "sdi4"), /* DAT4 */
+       /*SDI4 sleep state */
+       DB8500_PIN_SLEEP("GPIO197_AH24", slpm_in_wkup_pdis, "sdi4"), /* DAT3 */
+       DB8500_PIN_SLEEP("GPIO198_AG25", slpm_in_wkup_pdis, "sdi4"), /* DAT2 */
+       DB8500_PIN_SLEEP("GPIO199_AH23", slpm_in_wkup_pdis, "sdi4"), /* DAT1 */
+       DB8500_PIN_SLEEP("GPIO200_AH26", slpm_in_wkup_pdis, "sdi4"), /* DAT0 */
+       DB8500_PIN_SLEEP("GPIO201_AF24", slpm_in_wkup_pdis, "sdi4"), /* CMD */
+       DB8500_PIN_SLEEP("GPIO202_AF25", slpm_in_wkup_pdis, "sdi4"), /* FBCLK */
+       DB8500_PIN_SLEEP("GPIO203_AE23", slpm_out_lo_wkup_pdis, "sdi4"), /* CLK */
+       DB8500_PIN_SLEEP("GPIO204_AF23", slpm_in_wkup_pdis, "sdi4"), /* DAT7 */
+       DB8500_PIN_SLEEP("GPIO205_AG23", slpm_in_wkup_pdis, "sdi4"), /* DAT6 */
+       DB8500_PIN_SLEEP("GPIO206_AG24", slpm_in_wkup_pdis, "sdi4"), /* DAT5 */
+       DB8500_PIN_SLEEP("GPIO207_AJ23", slpm_in_wkup_pdis, "sdi4"), /* DAT4 */
+
        /* Mux in USB pins, drive STP high */
        DB8500_MUX("usb_a_1", "usb", "musb-ux500.0"),
        DB8500_PIN("GPIO257_AE29", out_hi, "musb-ux500.0"), /* STP */
@@ -238,10 +317,232 @@ static struct pinctrl_map __initdata mop500_family_pinmap[] = {
        DB8500_PIN("GPIO218_AH11", in_pd, "spi2"), /* RXD */
        DB8500_PIN("GPIO215_AH13", out_lo, "spi2"), /* TXD */
        DB8500_PIN("GPIO217_AH12", out_lo, "spi2"), /* CLK */
+       /* SPI2 idle state */
+       DB8500_PIN_SLEEP("GPIO218_AH11", slpm_in_wkup_pdis, "spi2"), /* RXD */
+       DB8500_PIN_SLEEP("GPIO215_AH13", slpm_out_lo_wkup_pdis, "spi2"), /* TXD */
+       DB8500_PIN_SLEEP("GPIO217_AH12", slpm_wkup_pdis, "spi2"), /* CLK */
        /* SPI2 sleep state */
+       DB8500_PIN_SLEEP("GPIO216_AG12", slpm_in_wkup_pdis, "spi2"), /* FRM */
        DB8500_PIN_SLEEP("GPIO218_AH11", slpm_in_wkup_pdis, "spi2"), /* RXD */
        DB8500_PIN_SLEEP("GPIO215_AH13", slpm_out_lo_wkup_pdis, "spi2"), /* TXD */
        DB8500_PIN_SLEEP("GPIO217_AH12", slpm_wkup_pdis, "spi2"), /* CLK */
+
+       /* ske default state */
+       DB8500_MUX("kp_a_2", "kp", "nmk-ske-keypad"),
+       DB8500_PIN("GPIO153_B17", in_pd, "nmk-ske-keypad"), /* I7 */
+       DB8500_PIN("GPIO154_C16", in_pd, "nmk-ske-keypad"), /* I6 */
+       DB8500_PIN("GPIO155_C19", in_pd, "nmk-ske-keypad"), /* I5 */
+       DB8500_PIN("GPIO156_C17", in_pd, "nmk-ske-keypad"), /* I4 */
+       DB8500_PIN("GPIO161_D21", in_pd, "nmk-ske-keypad"), /* I3 */
+       DB8500_PIN("GPIO162_D20", in_pd, "nmk-ske-keypad"), /* I2 */
+       DB8500_PIN("GPIO163_C20", in_pd, "nmk-ske-keypad"), /* I1 */
+       DB8500_PIN("GPIO164_B21", in_pd, "nmk-ske-keypad"), /* I0 */
+       DB8500_PIN("GPIO157_A18", out_lo, "nmk-ske-keypad"), /* O7 */
+       DB8500_PIN("GPIO158_C18", out_lo, "nmk-ske-keypad"), /* O6 */
+       DB8500_PIN("GPIO159_B19", out_lo, "nmk-ske-keypad"), /* O5 */
+       DB8500_PIN("GPIO160_B20", out_lo, "nmk-ske-keypad"), /* O4 */
+       DB8500_PIN("GPIO165_C21", out_lo, "nmk-ske-keypad"), /* O3 */
+       DB8500_PIN("GPIO166_A22", out_lo, "nmk-ske-keypad"), /* O2 */
+       DB8500_PIN("GPIO167_B24", out_lo, "nmk-ske-keypad"), /* O1 */
+       DB8500_PIN("GPIO168_C22", out_lo, "nmk-ske-keypad"), /* O0 */
+       /* ske sleep state */
+       DB8500_PIN_SLEEP("GPIO153_B17", slpm_in_pu_wkup_pdis_en, "nmk-ske-keypad"), /* I7 */
+       DB8500_PIN_SLEEP("GPIO154_C16", slpm_in_pu_wkup_pdis_en, "nmk-ske-keypad"), /* I6 */
+       DB8500_PIN_SLEEP("GPIO155_C19", slpm_in_pu_wkup_pdis_en, "nmk-ske-keypad"), /* I5 */
+       DB8500_PIN_SLEEP("GPIO156_C17", slpm_in_pu_wkup_pdis_en, "nmk-ske-keypad"), /* I4 */
+       DB8500_PIN_SLEEP("GPIO161_D21", slpm_in_pu_wkup_pdis_en, "nmk-ske-keypad"), /* I3 */
+       DB8500_PIN_SLEEP("GPIO162_D20", slpm_in_pu_wkup_pdis_en, "nmk-ske-keypad"), /* I2 */
+       DB8500_PIN_SLEEP("GPIO163_C20", slpm_in_pu_wkup_pdis_en, "nmk-ske-keypad"), /* I1 */
+       DB8500_PIN_SLEEP("GPIO164_B21", slpm_in_pu_wkup_pdis_en, "nmk-ske-keypad"), /* I0 */
+       DB8500_PIN_SLEEP("GPIO157_A18", slpm_out_lo_pdis, "nmk-ske-keypad"), /* O7 */
+       DB8500_PIN_SLEEP("GPIO158_C18", slpm_out_lo_pdis, "nmk-ske-keypad"), /* O6 */
+       DB8500_PIN_SLEEP("GPIO159_B19", slpm_out_lo_pdis, "nmk-ske-keypad"), /* O5 */
+       DB8500_PIN_SLEEP("GPIO160_B20", slpm_out_lo_pdis, "nmk-ske-keypad"), /* O4 */
+       DB8500_PIN_SLEEP("GPIO165_C21", slpm_out_lo_pdis, "nmk-ske-keypad"), /* O3 */
+       DB8500_PIN_SLEEP("GPIO166_A22", slpm_out_lo_pdis, "nmk-ske-keypad"), /* O2 */
+       DB8500_PIN_SLEEP("GPIO167_B24", slpm_out_lo_pdis, "nmk-ske-keypad"), /* O1 */
+       DB8500_PIN_SLEEP("GPIO168_C22", slpm_out_lo_pdis, "nmk-ske-keypad"), /* O0 */
+
+       /* STM APE pins states */
+       DB8500_MUX_STATE("stmape_c_1", "stmape",
+               "stm", "ape_mipi34"),
+       DB8500_PIN_STATE("GPIO70_G5", in_nopull,
+               "stm", "ape_mipi34"), /* clk */
+       DB8500_PIN_STATE("GPIO71_G4", in_nopull,
+               "stm", "ape_mipi34"), /* dat3 */
+       DB8500_PIN_STATE("GPIO72_H4", in_nopull,
+               "stm", "ape_mipi34"), /* dat2 */
+       DB8500_PIN_STATE("GPIO73_H3", in_nopull,
+               "stm", "ape_mipi34"), /* dat1 */
+       DB8500_PIN_STATE("GPIO74_J3", in_nopull,
+               "stm", "ape_mipi34"), /* dat0 */
+
+       DB8500_PIN_STATE("GPIO70_G5", slpm_out_lo_pdis,
+               "stm", "ape_mipi34_sleep"), /* clk */
+       DB8500_PIN_STATE("GPIO71_G4", slpm_out_lo_pdis,
+               "stm", "ape_mipi34_sleep"), /* dat3 */
+       DB8500_PIN_STATE("GPIO72_H4", slpm_out_lo_pdis,
+               "stm", "ape_mipi34_sleep"), /* dat2 */
+       DB8500_PIN_STATE("GPIO73_H3", slpm_out_lo_pdis,
+               "stm", "ape_mipi34_sleep"), /* dat1 */
+       DB8500_PIN_STATE("GPIO74_J3", slpm_out_lo_pdis,
+               "stm", "ape_mipi34_sleep"), /* dat0 */
+
+       DB8500_MUX_STATE("stmape_oc1_1", "stmape",
+               "stm", "ape_microsd"),
+       DB8500_PIN_STATE("GPIO23_AA4", in_nopull,
+               "stm", "ape_microsd"), /* clk */
+       DB8500_PIN_STATE("GPIO25_Y4", in_nopull,
+               "stm", "ape_microsd"), /* dat0 */
+       DB8500_PIN_STATE("GPIO26_Y2", in_nopull,
+               "stm", "ape_microsd"), /* dat1 */
+       DB8500_PIN_STATE("GPIO27_AA2", in_nopull,
+               "stm", "ape_microsd"), /* dat2 */
+       DB8500_PIN_STATE("GPIO28_AA1", in_nopull,
+               "stm", "ape_microsd"), /* dat3 */
+
+       DB8500_PIN_STATE("GPIO23_AA4", slpm_out_lo_wkup_pdis,
+               "stm", "ape_microsd_sleep"), /* clk */
+       DB8500_PIN_STATE("GPIO25_Y4", slpm_in_wkup_pdis,
+               "stm", "ape_microsd_sleep"), /* dat0 */
+       DB8500_PIN_STATE("GPIO26_Y2", slpm_in_wkup_pdis,
+               "stm", "ape_microsd_sleep"), /* dat1 */
+       DB8500_PIN_STATE("GPIO27_AA2", slpm_in_wkup_pdis,
+               "stm", "ape_microsd_sleep"), /* dat2 */
+       DB8500_PIN_STATE("GPIO28_AA1", slpm_in_wkup_pdis,
+               "stm", "ape_microsd_sleep"), /* dat3 */
+
+       /*  STM Modem pins states */
+       DB8500_MUX_STATE("stmmod_oc3_2", "stmmod",
+               "stm", "mod_mipi34"),
+       DB8500_MUX_STATE("uartmodrx_oc3_1", "uartmod",
+               "stm", "mod_mipi34"),
+       DB8500_MUX_STATE("uartmodtx_oc3_1", "uartmod",
+               "stm", "mod_mipi34"),
+       DB8500_PIN_STATE("GPIO70_G5", in_nopull,
+               "stm", "mod_mipi34"), /* clk */
+       DB8500_PIN_STATE("GPIO71_G4", in_nopull,
+               "stm", "mod_mipi34"), /* dat3 */
+       DB8500_PIN_STATE("GPIO72_H4", in_nopull,
+               "stm", "mod_mipi34"), /* dat2 */
+       DB8500_PIN_STATE("GPIO73_H3", in_nopull,
+               "stm", "mod_mipi34"), /* dat1 */
+       DB8500_PIN_STATE("GPIO74_J3", in_nopull,
+               "stm", "mod_mipi34"), /* dat0 */
+       DB8500_PIN_STATE("GPIO75_H2", in_pu,
+               "stm", "mod_mipi34"), /* uartmod rx */
+       DB8500_PIN_STATE("GPIO76_J2", out_lo,
+               "stm", "mod_mipi34"), /* uartmod tx */
+
+       DB8500_PIN_STATE("GPIO70_G5", slpm_out_lo_pdis,
+               "stm", "mod_mipi34_sleep"), /* clk */
+       DB8500_PIN_STATE("GPIO71_G4", slpm_out_lo_pdis,
+               "stm", "mod_mipi34_sleep"), /* dat3 */
+       DB8500_PIN_STATE("GPIO72_H4", slpm_out_lo_pdis,
+               "stm", "mod_mipi34_sleep"), /* dat2 */
+       DB8500_PIN_STATE("GPIO73_H3", slpm_out_lo_pdis,
+               "stm", "mod_mipi34_sleep"), /* dat1 */
+       DB8500_PIN_STATE("GPIO74_J3", slpm_out_lo_pdis,
+               "stm", "mod_mipi34_sleep"), /* dat0 */
+       DB8500_PIN_STATE("GPIO75_H2", slpm_in_wkup_pdis,
+               "stm", "mod_mipi34_sleep"), /* uartmod rx */
+       DB8500_PIN_STATE("GPIO76_J2", slpm_out_lo_wkup_pdis,
+               "stm", "mod_mipi34_sleep"), /* uartmod tx */
+
+       DB8500_MUX_STATE("stmmod_b_1", "stmmod",
+               "stm", "mod_microsd"),
+       DB8500_MUX_STATE("uartmodrx_oc3_1", "uartmod",
+               "stm", "mod_microsd"),
+       DB8500_MUX_STATE("uartmodtx_oc3_1", "uartmod",
+               "stm", "mod_microsd"),
+       DB8500_PIN_STATE("GPIO23_AA4", in_nopull,
+               "stm", "mod_microsd"), /* clk */
+       DB8500_PIN_STATE("GPIO25_Y4", in_nopull,
+               "stm", "mod_microsd"), /* dat0 */
+       DB8500_PIN_STATE("GPIO26_Y2", in_nopull,
+               "stm", "mod_microsd"), /* dat1 */
+       DB8500_PIN_STATE("GPIO27_AA2", in_nopull,
+               "stm", "mod_microsd"), /* dat2 */
+       DB8500_PIN_STATE("GPIO28_AA1", in_nopull,
+               "stm", "mod_microsd"), /* dat3 */
+       DB8500_PIN_STATE("GPIO75_H2", in_pu,
+               "stm", "mod_microsd"), /* uartmod rx */
+       DB8500_PIN_STATE("GPIO76_J2", out_lo,
+               "stm", "mod_microsd"), /* uartmod tx */
+
+       DB8500_PIN_STATE("GPIO23_AA4", slpm_out_lo_wkup_pdis,
+               "stm", "mod_microsd_sleep"), /* clk */
+       DB8500_PIN_STATE("GPIO25_Y4", slpm_in_wkup_pdis,
+               "stm", "mod_microsd_sleep"), /* dat0 */
+       DB8500_PIN_STATE("GPIO26_Y2", slpm_in_wkup_pdis,
+               "stm", "mod_microsd_sleep"), /* dat1 */
+       DB8500_PIN_STATE("GPIO27_AA2", slpm_in_wkup_pdis,
+               "stm", "mod_microsd_sleep"), /* dat2 */
+       DB8500_PIN_STATE("GPIO28_AA1", slpm_in_wkup_pdis,
+               "stm", "mod_microsd_sleep"), /* dat3 */
+       DB8500_PIN_STATE("GPIO75_H2", slpm_in_wkup_pdis,
+               "stm", "mod_microsd_sleep"), /* uartmod rx */
+       DB8500_PIN_STATE("GPIO76_J2", slpm_out_lo_wkup_pdis,
+               "stm", "mod_microsd_sleep"), /* uartmod tx */
+
+       /*  STM dual Modem/APE pins state */
+       DB8500_MUX_STATE("stmmod_oc3_2", "stmmod",
+               "stm", "mod_mipi34_ape_mipi60"),
+       DB8500_MUX_STATE("stmape_c_2", "stmape",
+               "stm", "mod_mipi34_ape_mipi60"),
+       DB8500_MUX_STATE("uartmodrx_oc3_1", "uartmod",
+               "stm", "mod_mipi34_ape_mipi60"),
+       DB8500_MUX_STATE("uartmodtx_oc3_1", "uartmod",
+               "stm", "mod_mipi34_ape_mipi60"),
+       DB8500_PIN_STATE("GPIO70_G5", in_nopull,
+               "stm", "mod_mipi34_ape_mipi60"), /* clk */
+       DB8500_PIN_STATE("GPIO71_G4", in_nopull,
+               "stm", "mod_mipi34_ape_mipi60"), /* dat3 */
+       DB8500_PIN_STATE("GPIO72_H4", in_nopull,
+               "stm", "mod_mipi34_ape_mipi60"), /* dat2 */
+       DB8500_PIN_STATE("GPIO73_H3", in_nopull,
+               "stm", "mod_mipi34_ape_mipi60"), /* dat1 */
+       DB8500_PIN_STATE("GPIO74_J3", in_nopull,
+               "stm", "mod_mipi34_ape_mipi60"), /* dat0 */
+       DB8500_PIN_STATE("GPIO75_H2", in_pu,
+               "stm", "mod_mipi34_ape_mipi60"), /* uartmod rx */
+       DB8500_PIN_STATE("GPIO76_J2", out_lo,
+               "stm", "mod_mipi34_ape_mipi60"), /* uartmod tx */
+       DB8500_PIN_STATE("GPIO155_C19", in_nopull,
+               "stm", "mod_mipi34_ape_mipi60"), /* clk */
+       DB8500_PIN_STATE("GPIO156_C17", in_nopull,
+               "stm", "mod_mipi34_ape_mipi60"), /* dat3 */
+       DB8500_PIN_STATE("GPIO157_A18", in_nopull,
+               "stm", "mod_mipi34_ape_mipi60"), /* dat2 */
+       DB8500_PIN_STATE("GPIO158_C18", in_nopull,
+               "stm", "mod_mipi34_ape_mipi60"), /* dat1 */
+       DB8500_PIN_STATE("GPIO159_B19", in_nopull,
+               "stm", "mod_mipi34_ape_mipi60"), /* dat0 */
+
+       DB8500_PIN_STATE("GPIO70_G5", slpm_out_lo_pdis,
+               "stm", "mod_mipi34_ape_mipi60_sleep"), /* clk */
+       DB8500_PIN_STATE("GPIO71_G4", slpm_out_lo_pdis,
+               "stm", "mod_mipi34_ape_mipi60_sleep"), /* dat3 */
+       DB8500_PIN_STATE("GPIO72_H4", slpm_out_lo_pdis,
+               "stm", "mod_mipi34_ape_mipi60_sleep"), /* dat2 */
+       DB8500_PIN_STATE("GPIO73_H3", slpm_out_lo_pdis,
+               "stm", "mod_mipi34_ape_mipi60_sleep"), /* dat1 */
+       DB8500_PIN_STATE("GPIO74_J3", slpm_out_lo_pdis,
+               "stm", "mod_mipi34_ape_mipi60_sleep"), /* dat0 */
+       DB8500_PIN_STATE("GPIO75_H2", slpm_in_wkup_pdis,
+               "stm", "mod_mipi34_ape_mipi60_sleep"), /* uartmod rx */
+       DB8500_PIN_STATE("GPIO76_J2", slpm_out_lo_wkup_pdis,
+               "stm", "mod_mipi34_ape_mipi60_sleep"), /* uartmod tx */
+       DB8500_PIN_STATE("GPIO155_C19", slpm_in_wkup_pdis,
+               "stm", "mod_mipi34_ape_mipi60_sleep"), /* clk */
+       DB8500_PIN_STATE("GPIO156_C17", slpm_in_wkup_pdis,
+               "stm", "mod_mipi34_ape_mipi60_sleep"), /* dat3 */
+       DB8500_PIN_STATE("GPIO157_A18", slpm_in_wkup_pdis,
+               "stm", "mod_mipi34_ape_mipi60_sleep"), /* dat2 */
+       DB8500_PIN_STATE("GPIO158_C18", slpm_in_wkup_pdis,
+               "stm", "mod_mipi34_ape_mipi60_sleep"), /* dat1 */
+       DB8500_PIN_STATE("GPIO159_B19", slpm_in_wkup_pdis,
+               "stm", "mod_mipi34_ape_mipi60_sleep"), /* dat0 */
 };
 
 /*
@@ -267,32 +568,48 @@ static struct pinctrl_map __initdata mop500_pinmap[] = {
        DB8500_PIN_HOG("GPIO217_AH12", gpio_in_pu),
        /* Mux in UART1 and set the pull-ups */
        DB8500_MUX_HOG("u1rxtx_a_1", "u1"),
-       DB8500_MUX_HOG("u1ctsrts_a_1", "u1"),
        DB8500_PIN_HOG("GPIO4_AH6", in_pu), /* RXD */
        DB8500_PIN_HOG("GPIO5_AG6", out_hi), /* TXD */
-       DB8500_PIN_HOG("GPIO6_AF6", in_pu), /* CTS */
-       DB8500_PIN_HOG("GPIO7_AG5", out_hi), /* RTS */
        /*
         * Runtime stuff: make it possible to mux in the SKE keypad
         * and bias the pins
         */
-       DB8500_MUX("kp_a_2", "kp", "ske"),
-       DB8500_PIN("GPIO153_B17", in_pd_slpm_in_pu, "ske"), /* I7 */
-       DB8500_PIN("GPIO154_C16", in_pd_slpm_in_pu, "ske"), /* I6 */
-       DB8500_PIN("GPIO155_C19", in_pd_slpm_in_pu, "ske"), /* I5 */
-       DB8500_PIN("GPIO156_C17", in_pd_slpm_in_pu, "ske"), /* I4 */
-       DB8500_PIN("GPIO161_D21", in_pd_slpm_in_pu, "ske"), /* I3 */
-       DB8500_PIN("GPIO162_D20", in_pd_slpm_in_pu, "ske"), /* I2 */
-       DB8500_PIN("GPIO163_C20", in_pd_slpm_in_pu, "ske"), /* I1 */
-       DB8500_PIN("GPIO164_B21", in_pd_slpm_in_pu, "ske"), /* I0 */
-       DB8500_PIN("GPIO157_A18", in_pu_slpm_out_lo, "ske"), /* O7 */
-       DB8500_PIN("GPIO158_C18", in_pu_slpm_out_lo, "ske"), /* O6 */
-       DB8500_PIN("GPIO159_B19", in_pu_slpm_out_lo, "ske"), /* O5 */
-       DB8500_PIN("GPIO160_B20", in_pu_slpm_out_lo, "ske"), /* O4 */
-       DB8500_PIN("GPIO165_C21", in_pu_slpm_out_lo, "ske"), /* O3 */
-       DB8500_PIN("GPIO166_A22", in_pu_slpm_out_lo, "ske"), /* O2 */
-       DB8500_PIN("GPIO167_B24", in_pu_slpm_out_lo, "ske"), /* O1 */
-       DB8500_PIN("GPIO168_C22", in_pu_slpm_out_lo, "ske"), /* O0 */
+       /* ske default state */
+       DB8500_MUX("kp_a_2", "kp", "nmk-ske-keypad"),
+       DB8500_PIN("GPIO153_B17", in_pu, "nmk-ske-keypad"), /* I7 */
+       DB8500_PIN("GPIO154_C16", in_pu, "nmk-ske-keypad"), /* I6 */
+       DB8500_PIN("GPIO155_C19", in_pu, "nmk-ske-keypad"), /* I5 */
+       DB8500_PIN("GPIO156_C17", in_pu, "nmk-ske-keypad"), /* I4 */
+       DB8500_PIN("GPIO161_D21", in_pu, "nmk-ske-keypad"), /* I3 */
+       DB8500_PIN("GPIO162_D20", in_pu, "nmk-ske-keypad"), /* I2 */
+       DB8500_PIN("GPIO163_C20", in_pu, "nmk-ske-keypad"), /* I1 */
+       DB8500_PIN("GPIO164_B21", in_pu, "nmk-ske-keypad"), /* I0 */
+       DB8500_PIN("GPIO157_A18", out_lo, "nmk-ske-keypad"), /* O7 */
+       DB8500_PIN("GPIO158_C18", out_lo, "nmk-ske-keypad"), /* O6 */
+       DB8500_PIN("GPIO159_B19", out_lo, "nmk-ske-keypad"), /* O5 */
+       DB8500_PIN("GPIO160_B20", out_lo, "nmk-ske-keypad"), /* O4 */
+       DB8500_PIN("GPIO165_C21", out_lo, "nmk-ske-keypad"), /* O3 */
+       DB8500_PIN("GPIO166_A22", out_lo, "nmk-ske-keypad"), /* O2 */
+       DB8500_PIN("GPIO167_B24", out_lo, "nmk-ske-keypad"), /* O1 */
+       DB8500_PIN("GPIO168_C22", out_lo, "nmk-ske-keypad"), /* O0 */
+       /* ske sleep state */
+       DB8500_PIN_SLEEP("GPIO153_B17", slpm_in_pu_wkup_pdis_en, "nmk-ske-keypad"), /* I7 */
+       DB8500_PIN_SLEEP("GPIO154_C16", slpm_in_pu_wkup_pdis_en, "nmk-ske-keypad"), /* I6 */
+       DB8500_PIN_SLEEP("GPIO155_C19", slpm_in_pu_wkup_pdis_en, "nmk-ske-keypad"), /* I5 */
+       DB8500_PIN_SLEEP("GPIO156_C17", slpm_in_pu_wkup_pdis_en, "nmk-ske-keypad"), /* I4 */
+       DB8500_PIN_SLEEP("GPIO161_D21", slpm_in_pu_wkup_pdis_en, "nmk-ske-keypad"), /* I3 */
+       DB8500_PIN_SLEEP("GPIO162_D20", slpm_in_pu_wkup_pdis_en, "nmk-ske-keypad"), /* I2 */
+       DB8500_PIN_SLEEP("GPIO163_C20", slpm_in_pu_wkup_pdis_en, "nmk-ske-keypad"), /* I1 */
+       DB8500_PIN_SLEEP("GPIO164_B21", slpm_in_pu_wkup_pdis_en, "nmk-ske-keypad"), /* I0 */
+       DB8500_PIN_SLEEP("GPIO157_A18", slpm_out_lo_pdis, "nmk-ske-keypad"), /* O7 */
+       DB8500_PIN_SLEEP("GPIO158_C18", slpm_out_lo_pdis, "nmk-ske-keypad"), /* O6 */
+       DB8500_PIN_SLEEP("GPIO159_B19", slpm_out_lo_pdis, "nmk-ske-keypad"), /* O5 */
+       DB8500_PIN_SLEEP("GPIO160_B20", slpm_out_lo_pdis, "nmk-ske-keypad"), /* O4 */
+       DB8500_PIN_SLEEP("GPIO165_C21", slpm_out_lo_pdis, "nmk-ske-keypad"), /* O3 */
+       DB8500_PIN_SLEEP("GPIO166_A22", slpm_out_lo_pdis, "nmk-ske-keypad"), /* O2 */
+       DB8500_PIN_SLEEP("GPIO167_B24", slpm_out_lo_pdis, "nmk-ske-keypad"), /* O1 */
+       DB8500_PIN_SLEEP("GPIO168_C22", slpm_out_lo_pdis, "nmk-ske-keypad"), /* O0 */
+
        /* Mux in and drive the SDI0 DAT31DIR line high at runtime */
        DB8500_MUX("mc0dat31dir_a_1", "mc0", "sdi0"),
        DB8500_PIN("GPIO21_AB3", out_hi, "sdi0"),
@@ -395,28 +712,6 @@ static struct pinctrl_map __initdata hrefv60_pinmap[] = {
        DB8500_PIN("GPIO217_AH12", gpio_in_pu_slpm_gpio_nopull, "gpio-keys.0"),
        DB8500_PIN("GPIO145_C13", gpio_in_pd_slpm_gpio_nopull, "gpio-keys.0"),
        DB8500_PIN("GPIO139_C9", gpio_in_pu_slpm_gpio_nopull, "gpio-keys.0"),
-       /*
-        * Make it possible to mux in the SKE keypad and bias the pins
-        * FIXME: what's the point with this on HREFv60? KP/SKE is already
-        * muxed in at another place! Enabling this will bork.
-        */
-       DB8500_MUX("kp_a_2", "kp", "ske"),
-       DB8500_PIN("GPIO153_B17", in_pd_slpm_in_pu, "ske"), /* I7 */
-       DB8500_PIN("GPIO154_C16", in_pd_slpm_in_pu, "ske"), /* I6 */
-       DB8500_PIN("GPIO155_C19", in_pd_slpm_in_pu, "ske"), /* I5 */
-       DB8500_PIN("GPIO156_C17", in_pd_slpm_in_pu, "ske"), /* I4 */
-       DB8500_PIN("GPIO161_D21", in_pd_slpm_in_pu, "ske"), /* I3 */
-       DB8500_PIN("GPIO162_D20", in_pd_slpm_in_pu, "ske"), /* I2 */
-       DB8500_PIN("GPIO163_C20", in_pd_slpm_in_pu, "ske"), /* I1 */
-       DB8500_PIN("GPIO164_B21", in_pd_slpm_in_pu, "ske"), /* I0 */
-       DB8500_PIN("GPIO157_A18", in_pu_slpm_out_lo, "ske"), /* O7 */
-       DB8500_PIN("GPIO158_C18", in_pu_slpm_out_lo, "ske"), /* O6 */
-       DB8500_PIN("GPIO159_B19", in_pu_slpm_out_lo, "ske"), /* O5 */
-       DB8500_PIN("GPIO160_B20", in_pu_slpm_out_lo, "ske"), /* O4 */
-       DB8500_PIN("GPIO165_C21", in_pu_slpm_out_lo, "ske"), /* O3 */
-       DB8500_PIN("GPIO166_A22", in_pu_slpm_out_lo, "ske"), /* O2 */
-       DB8500_PIN("GPIO167_B24", in_pu_slpm_out_lo, "ske"), /* O1 */
-       DB8500_PIN("GPIO168_C22", in_pu_slpm_out_lo, "ske"), /* O0 */
 };
 
 static struct pinctrl_map __initdata u9500_pinmap[] = {
diff --git a/arch/arm/mach-vexpress/reset.c b/arch/arm/mach-vexpress/reset.c
new file mode 100644 (file)
index 0000000..465923a
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * Copyright (C) 2012 ARM Limited
+ */
+
+#include <linux/jiffies.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/stat.h>
+#include <linux/vexpress.h>
+
+static void vexpress_reset_do(struct device *dev, const char *what)
+{
+       int err = -ENOENT;
+       struct vexpress_config_func *func =
+                       vexpress_config_func_get_by_dev(dev);
+
+       if (func) {
+               unsigned long timeout;
+
+               err = vexpress_config_write(func, 0, 0);
+
+               timeout = jiffies + HZ;
+               while (time_before(jiffies, timeout))
+                       cpu_relax();
+       }
+
+       dev_emerg(dev, "Unable to %s (%d)\n", what, err);
+}
+
+static struct device *vexpress_power_off_device;
+
+void vexpress_power_off(void)
+{
+       vexpress_reset_do(vexpress_power_off_device, "power off");
+}
+
+static struct device *vexpress_restart_device;
+
+void vexpress_restart(char str, const char *cmd)
+{
+       vexpress_reset_do(vexpress_restart_device, "restart");
+}
+
+static ssize_t vexpress_reset_active_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", vexpress_restart_device == dev);
+}
+
+static ssize_t vexpress_reset_active_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       long value;
+       int err = kstrtol(buf, 0, &value);
+
+       if (!err && value)
+               vexpress_restart_device = dev;
+
+       return err ? err : count;
+}
+
+DEVICE_ATTR(active, S_IRUGO | S_IWUSR, vexpress_reset_active_show,
+               vexpress_reset_active_store);
+
+
+enum vexpress_reset_func { FUNC_RESET, FUNC_SHUTDOWN, FUNC_REBOOT };
+
+static struct of_device_id vexpress_reset_of_match[] = {
+       {
+               .compatible = "arm,vexpress-reset",
+               .data = (void *)FUNC_RESET,
+       }, {
+               .compatible = "arm,vexpress-shutdown",
+               .data = (void *)FUNC_SHUTDOWN
+       }, {
+               .compatible = "arm,vexpress-reboot",
+               .data = (void *)FUNC_REBOOT
+       },
+       {}
+};
+
+static int vexpress_reset_probe(struct platform_device *pdev)
+{
+       enum vexpress_reset_func func;
+       const struct of_device_id *match =
+                       of_match_device(vexpress_reset_of_match, &pdev->dev);
+
+       if (match)
+               func = (enum vexpress_reset_func)match->data;
+       else
+               func = pdev->id_entry->driver_data;
+
+       switch (func) {
+       case FUNC_SHUTDOWN:
+               vexpress_power_off_device = &pdev->dev;
+               break;
+       case FUNC_RESET:
+               if (!vexpress_restart_device)
+                       vexpress_restart_device = &pdev->dev;
+               device_create_file(&pdev->dev, &dev_attr_active);
+               break;
+       case FUNC_REBOOT:
+               vexpress_restart_device = &pdev->dev;
+               device_create_file(&pdev->dev, &dev_attr_active);
+               break;
+       };
+
+       return 0;
+}
+
+static const struct platform_device_id vexpress_reset_id_table[] = {
+       { .name = "vexpress-reset", .driver_data = FUNC_RESET, },
+       { .name = "vexpress-shutdown", .driver_data = FUNC_SHUTDOWN, },
+       { .name = "vexpress-reboot", .driver_data = FUNC_REBOOT, },
+       {}
+};
+
+static struct platform_driver vexpress_reset_driver = {
+       .probe = vexpress_reset_probe,
+       .driver = {
+               .name = "vexpress-reset",
+               .of_match_table = vexpress_reset_of_match,
+       },
+       .id_table = vexpress_reset_id_table,
+};
+
+static int __init vexpress_reset_init(void)
+{
+       return platform_driver_register(&vexpress_reset_driver);
+}
+device_initcall(vexpress_reset_init);
index 1fe6917f6a2a75e9f36cce7c28f46ef13228f113..dfd8b7af8c7ac93db4bf6d3d28371a072793c1d9 100644 (file)
@@ -48,6 +48,7 @@ struct samsung_gpio_cfg;
  * @config: special function and pull-resistor control information.
  * @lock: Lock for exclusive access to this gpio bank.
  * @pm_save: Save information for suspend/resume support.
+ * @bitmap_gpio_int: Bitmap for representing GPIO interrupt or not.
  *
  * This wrapper provides the necessary information for the Samsung
  * specific gpios being registered with gpiolib.
@@ -71,6 +72,7 @@ struct samsung_gpio_chip {
 #ifdef CONFIG_PM
        u32                     pm_save[4];
 #endif
+       u32                     bitmap_gpio_int;
 };
 
 static inline struct samsung_gpio_chip *to_samsung_gpio(struct gpio_chip *gpc)
index 23557d30e44ceb9e6124f4cb19b9851325db67ea..bae56131a50a44e7dc7fff38beef9cc8e9d7cbe2 100644 (file)
@@ -185,7 +185,7 @@ int __init s5p_register_gpio_interrupt(int pin)
 
        /* check if the group has been already registered */
        if (my_chip->irq_base)
-               return my_chip->irq_base + offset;
+               goto success;
 
        /* register gpio group */
        ret = s5p_gpioint_add(my_chip);
@@ -193,9 +193,13 @@ int __init s5p_register_gpio_interrupt(int pin)
                my_chip->chip.to_irq = samsung_gpiolib_to_irq;
                printk(KERN_INFO "Registered interrupt support for gpio group %d.\n",
                       group);
-               return my_chip->irq_base + offset;
+               goto success;
        }
        return ret;
+success:
+       my_chip->bitmap_gpio_int |= BIT(offset);
+
+       return my_chip->irq_base + offset;
 }
 
 int __init s5p_register_gpioint_bank(int chain_irq, int start, int nr_groups)
index 88f41e51565bdb6391d3dcd89768df9c1f8f5b92..01f7fe955590c1b79a64cd088431858b7d9caea8 100644 (file)
 #include <plat/gpio-fns.h>
 #include <plat/pm.h>
 
-#ifndef DEBUG_GPIO
-#define gpio_dbg(x...) do { } while (0)
-#else
-#define gpio_dbg(x...) printk(KERN_DEBUG x)
-#endif
-
 int samsung_gpio_setpull_updown(struct samsung_gpio_chip *chip,
                                unsigned int off, samsung_gpio_pull_t pull)
 {
@@ -596,10 +590,13 @@ static int samsung_gpiolib_4bit_input(struct gpio_chip *chip,
        unsigned long con;
 
        con = __raw_readl(base + GPIOCON_OFF);
-       con &= ~(0xf << con_4bit_shift(offset));
+       if (ourchip->bitmap_gpio_int & BIT(offset))
+               con |= 0xf << con_4bit_shift(offset);
+       else
+               con &= ~(0xf << con_4bit_shift(offset));
        __raw_writel(con, base + GPIOCON_OFF);
 
-       gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con);
+       pr_debug("%s: %p: CON now %08lx\n", __func__, base, con);
 
        return 0;
 }
@@ -627,7 +624,7 @@ static int samsung_gpiolib_4bit_output(struct gpio_chip *chip,
        __raw_writel(con, base + GPIOCON_OFF);
        __raw_writel(dat, base + GPIODAT_OFF);
 
-       gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
+       pr_debug("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
 
        return 0;
 }
@@ -671,7 +668,7 @@ static int samsung_gpiolib_4bit2_input(struct gpio_chip *chip,
        con &= ~(0xf << con_4bit_shift(offset));
        __raw_writel(con, regcon);
 
-       gpio_dbg("%s: %p: CON %08lx\n", __func__, base, con);
+       pr_debug("%s: %p: CON %08lx\n", __func__, base, con);
 
        return 0;
 }
@@ -706,7 +703,7 @@ static int samsung_gpiolib_4bit2_output(struct gpio_chip *chip,
        __raw_writel(con, regcon);
        __raw_writel(dat, base + GPIODAT_OFF);
 
-       gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
+       pr_debug("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
 
        return 0;
 }
@@ -926,10 +923,10 @@ static void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip)
 #ifdef CONFIG_PM
        if (chip->pm != NULL) {
                if (!chip->pm->save || !chip->pm->resume)
-                       printk(KERN_ERR "gpio: %s has missing PM functions\n",
+                       pr_err("gpio: %s has missing PM functions\n",
                               gc->label);
        } else
-               printk(KERN_ERR "gpio: %s has no PM function\n", gc->label);
+               pr_err("gpio: %s has no PM function\n", gc->label);
 #endif
 
        /* gpiochip_add() prints own failure message on error. */
@@ -1081,6 +1078,8 @@ static void __init samsung_gpiolib_add_4bit_chips(struct samsung_gpio_chip *chip
                if ((base != NULL) && (chip->base == NULL))
                        chip->base = base + ((i) * 0x20);
 
+               chip->bitmap_gpio_int = 0;
+
                samsung_gpiolib_add(chip);
        }
 }
index 4800d4c2a7b7fc8c7634039dfbd52ee5c4232ae5..32f238f3caea852ad116fa9eab465c945fa0d6e3 100644 (file)
@@ -1208,6 +1208,14 @@ config SENSORS_TWL4030_MADC
        This driver can also be built as a module. If so it will be called
        twl4030-madc-hwmon.
 
+config SENSORS_VEXPRESS
+       tristate "Versatile Express"
+       depends on VEXPRESS_CONFIG
+       help
+         This driver provides support for hardware sensors available on
+         the ARM Ltd's Versatile Express platform. It can provide wide
+         range of information like temperature, power, energy.
+
 config SENSORS_VIA_CPUTEMP
        tristate "VIA CPU temperature sensor"
        depends on X86
index a930f0997d25a7fe4c69ad5fa10bc1a9c42ca5cb..5da287443f6c3d007ae96b4e7a9d5d912fe3d3d7 100644 (file)
@@ -122,6 +122,7 @@ obj-$(CONFIG_SENSORS_TMP102)        += tmp102.o
 obj-$(CONFIG_SENSORS_TMP401)   += tmp401.o
 obj-$(CONFIG_SENSORS_TMP421)   += tmp421.o
 obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o
+obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress.o
 obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
 obj-$(CONFIG_SENSORS_VIA686A)  += via686a.o
 obj-$(CONFIG_SENSORS_VT1211)   += vt1211.o
diff --git a/drivers/hwmon/vexpress.c b/drivers/hwmon/vexpress.c
new file mode 100644 (file)
index 0000000..59fd126
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * Copyright (C) 2012 ARM Limited
+ */
+
+#define DRVNAME "vexpress-hwmon"
+#define pr_fmt(fmt) DRVNAME ": " fmt
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/vexpress.h>
+
+struct vexpress_hwmon_data {
+       struct device *hwmon_dev;
+       struct vexpress_config_func *func;
+};
+
+static ssize_t vexpress_hwmon_name_show(struct device *dev,
+               struct device_attribute *dev_attr, char *buffer)
+{
+       const char *compatible = of_get_property(dev->of_node, "compatible",
+                       NULL);
+
+       return sprintf(buffer, "%s\n", compatible);
+}
+
+static ssize_t vexpress_hwmon_label_show(struct device *dev,
+               struct device_attribute *dev_attr, char *buffer)
+{
+       const char *label = of_get_property(dev->of_node, "label", NULL);
+
+       if (!label)
+               return -ENOENT;
+
+       return snprintf(buffer, PAGE_SIZE, "%s\n", label);
+}
+
+static ssize_t vexpress_hwmon_u32_show(struct device *dev,
+               struct device_attribute *dev_attr, char *buffer)
+{
+       struct vexpress_hwmon_data *data = dev_get_drvdata(dev);
+       int err;
+       u32 value;
+
+       err = vexpress_config_read(data->func, 0, &value);
+       if (err)
+               return err;
+
+       return snprintf(buffer, PAGE_SIZE, "%u\n", value /
+                       to_sensor_dev_attr(dev_attr)->index);
+}
+
+static ssize_t vexpress_hwmon_u64_show(struct device *dev,
+               struct device_attribute *dev_attr, char *buffer)
+{
+       struct vexpress_hwmon_data *data = dev_get_drvdata(dev);
+       int err;
+       u32 value_hi, value_lo;
+
+       err = vexpress_config_read(data->func, 0, &value_lo);
+       if (err)
+               return err;
+
+       err = vexpress_config_read(data->func, 1, &value_hi);
+       if (err)
+               return err;
+
+       return snprintf(buffer, PAGE_SIZE, "%llu\n",
+                       div_u64(((u64)value_hi << 32) | value_lo,
+                       to_sensor_dev_attr(dev_attr)->index));
+}
+
+static DEVICE_ATTR(name, S_IRUGO, vexpress_hwmon_name_show, NULL);
+
+#define VEXPRESS_HWMON_ATTRS(_name, _label_attr, _input_attr)  \
+struct attribute *vexpress_hwmon_attrs_##_name[] = {           \
+       &dev_attr_name.attr,                                    \
+       &dev_attr_##_label_attr.attr,                           \
+       &sensor_dev_attr_##_input_attr.dev_attr.attr,           \
+       NULL                                                    \
+}
+
+#if !defined(CONFIG_REGULATOR_VEXPRESS)
+static DEVICE_ATTR(in1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, vexpress_hwmon_u32_show,
+               NULL, 1000);
+static VEXPRESS_HWMON_ATTRS(volt, in1_label, in1_input);
+static struct attribute_group vexpress_hwmon_group_volt = {
+       .attrs = vexpress_hwmon_attrs_volt,
+};
+#endif
+
+static DEVICE_ATTR(curr1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, vexpress_hwmon_u32_show,
+               NULL, 1000);
+static VEXPRESS_HWMON_ATTRS(amp, curr1_label, curr1_input);
+static struct attribute_group vexpress_hwmon_group_amp = {
+       .attrs = vexpress_hwmon_attrs_amp,
+};
+
+static DEVICE_ATTR(temp1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, vexpress_hwmon_u32_show,
+               NULL, 1000);
+static VEXPRESS_HWMON_ATTRS(temp, temp1_label, temp1_input);
+static struct attribute_group vexpress_hwmon_group_temp = {
+       .attrs = vexpress_hwmon_attrs_temp,
+};
+
+static DEVICE_ATTR(power1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, vexpress_hwmon_u32_show,
+               NULL, 1);
+static VEXPRESS_HWMON_ATTRS(power, power1_label, power1_input);
+static struct attribute_group vexpress_hwmon_group_power = {
+       .attrs = vexpress_hwmon_attrs_power,
+};
+
+static DEVICE_ATTR(energy1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
+static SENSOR_DEVICE_ATTR(energy1_input, S_IRUGO, vexpress_hwmon_u64_show,
+               NULL, 1);
+static VEXPRESS_HWMON_ATTRS(energy, energy1_label, energy1_input);
+static struct attribute_group vexpress_hwmon_group_energy = {
+       .attrs = vexpress_hwmon_attrs_energy,
+};
+
+static struct of_device_id vexpress_hwmon_of_match[] = {
+#if !defined(CONFIG_REGULATOR_VEXPRESS)
+       {
+               .compatible = "arm,vexpress-volt",
+               .data = &vexpress_hwmon_group_volt,
+       },
+#endif
+       {
+               .compatible = "arm,vexpress-amp",
+               .data = &vexpress_hwmon_group_amp,
+       }, {
+               .compatible = "arm,vexpress-temp",
+               .data = &vexpress_hwmon_group_temp,
+       }, {
+               .compatible = "arm,vexpress-power",
+               .data = &vexpress_hwmon_group_power,
+       }, {
+               .compatible = "arm,vexpress-energy",
+               .data = &vexpress_hwmon_group_energy,
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(of, vexpress_hwmon_of_match);
+
+static int vexpress_hwmon_probe(struct platform_device *pdev)
+{
+       int err;
+       const struct of_device_id *match;
+       struct vexpress_hwmon_data *data;
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, data);
+
+       match = of_match_device(vexpress_hwmon_of_match, &pdev->dev);
+       if (!match)
+               return -ENODEV;
+
+       data->func = vexpress_config_func_get_by_dev(&pdev->dev);
+       if (!data->func)
+               return -ENODEV;
+
+       err = sysfs_create_group(&pdev->dev.kobj, match->data);
+       if (err)
+               goto error;
+
+       data->hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto error;
+       }
+
+       return 0;
+
+error:
+       sysfs_remove_group(&pdev->dev.kobj, match->data);
+       vexpress_config_func_put(data->func);
+       return err;
+}
+
+static int __devexit vexpress_hwmon_remove(struct platform_device *pdev)
+{
+       struct vexpress_hwmon_data *data = platform_get_drvdata(pdev);
+       const struct of_device_id *match;
+
+       hwmon_device_unregister(data->hwmon_dev);
+
+       match = of_match_device(vexpress_hwmon_of_match, &pdev->dev);
+       sysfs_remove_group(&pdev->dev.kobj, match->data);
+
+       vexpress_config_func_put(data->func);
+
+       return 0;
+}
+
+static struct platform_driver vexpress_hwmon_driver = {
+       .probe = vexpress_hwmon_probe,
+       .remove = __devexit_p(vexpress_hwmon_remove),
+       .driver = {
+               .name = DRVNAME,
+               .owner = THIS_MODULE,
+               .of_match_table = vexpress_hwmon_of_match,
+       },
+};
+
+module_platform_driver(vexpress_hwmon_driver);
+
+MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>");
+MODULE_DESCRIPTION("Versatile Express hwmon sensors driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:vexpress-hwmon");