Переглянути джерело

Merge branch 'kirkwood/drivers' of git://git.infradead.org/users/jcooper/linux into late/kirkwood

From Jason Cooper:

New drivers:
 - pinctrl (dove, kirkwood, mvebu)
 - gpio (mvebu)

* 'kirkwood/drivers' of git://git.infradead.org/users/jcooper/linux:
  arm: mvebu: add gpio support in defconfig
  arm: mvebu: add DT information for GPIO banks on Armada 370 and XP
  arm: mvebu: use GPIO support now that a driver is available
  Documentation: add description of DT binding for the gpio-mvebu driver
  gpio: introduce gpio-mvebu driver for Marvell SoCs
  arm: mvebu: select the pinctrl drivers for Armada 370 and Armada XP platforms
  arm: mvebu: split Kconfig options for Armada 370 and XP
  ARM: mvebu: adjust Armada XP evaluation board DTS
  ARM: mvebu: Add pinctrl support to Armada 370 SoC
  ARM: mvebu: Add pinctrl support to Armada XP SoCs
  pinctrl: mvebu: add pinctrl driver for Armada XP
  pinctrl: mvebu: add pinctrl driver for Armada 370
  pinctrl: mvebu: kirkwood pinctrl driver
  pinctrl: mvebu: dove pinctrl driver
  pinctrl: mvebu: pinctrl driver core

Signed-off-by: Olof Johansson <olof@lixom.net>
Olof Johansson 13 роки тому
батько
коміт
c740ae7404

+ 53 - 0
Documentation/devicetree/bindings/gpio/gpio-mvebu.txt

@@ -0,0 +1,53 @@
+* Marvell EBU GPIO controller
+
+Required properties:
+
+- compatible : Should be "marvell,orion-gpio", "marvell,mv78200-gpio"
+  or "marvell,armadaxp-gpio". "marvell,orion-gpio" should be used for
+  Orion, Kirkwood, Dove, Discovery (except MV78200) and Armada
+  370. "marvell,mv78200-gpio" should be used for the Discovery
+  MV78200. "marvel,armadaxp-gpio" should be used for all Armada XP
+  SoCs (MV78230, MV78260, MV78460).
+
+- reg: Address and length of the register set for the device. Only one
+  entry is expected, except for the "marvell,armadaxp-gpio" variant
+  for which two entries are expected: one for the general registers,
+  one for the per-cpu registers.
+
+- interrupts: The list of interrupts that are used for all the pins
+  managed by this GPIO bank. There can be more than one interrupt
+  (example: 1 interrupt per 8 pins on Armada XP, which means 4
+  interrupts per bank of 32 GPIOs).
+
+- interrupt-controller: identifies the node as an interrupt controller
+
+- #interrupt-cells: specifies the number of cells needed to encode an
+  interrupt source. Should be two.
+  The first cell is the GPIO number.
+  The second cell is used to specify flags:
+    bits[3:0] trigger type and level flags:
+      1 = low-to-high edge triggered.
+      2 = high-to-low edge triggered.
+      4 = active high level-sensitive.
+      8 = active low level-sensitive.
+
+- gpio-controller: marks the device node as a gpio controller
+
+- ngpios: number of GPIOs this controller has
+
+- #gpio-cells: Should be two. The first cell is the pin number. The
+  second cell is reserved for flags, unused at the moment.
+
+Example:
+
+		gpio0: gpio@d0018100 {
+			compatible = "marvell,armadaxp-gpio";
+			reg = <0xd0018100 0x40>,
+			    <0xd0018800 0x30>;
+			ngpios = <32>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			interrupts = <16>, <17>, <18>, <19>;
+		};

+ 95 - 0
Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt

@@ -0,0 +1,95 @@
+* Marvell Armada 370 SoC pinctrl driver for mpp
+
+Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding
+part and usage.
+
+Required properties:
+- compatible: "marvell,88f6710-pinctrl"
+
+Available mpp pins/groups and functions:
+Note: brackets (x) are not part of the mpp name for marvell,function and given
+only for more detailed description in this document.
+
+name          pins     functions
+================================================================================
+mpp0          0        gpio, uart0(rxd)
+mpp1          1        gpo, uart0(txd)
+mpp2          2        gpio, i2c0(sck), uart0(txd)
+mpp3          3        gpio, i2c0(sda), uart0(rxd)
+mpp4          4        gpio, cpu_pd(vdd)
+mpp5          5        gpo, ge0(txclko), uart1(txd), spi1(clk), audio(mclk)
+mpp6          6        gpio, ge0(txd0), sata0(prsnt), tdm(rst), audio(sdo)
+mpp7          7        gpo, ge0(txd1), tdm(tdx), audio(lrclk)
+mpp8          8        gpio, ge0(txd2), uart0(rts), tdm(drx), audio(bclk)
+mpp9          9        gpo, ge0(txd3), uart1(txd), sd0(clk), audio(spdifo)
+mpp10         10       gpio, ge0(txctl), uart0(cts), tdm(fsync), audio(sdi)
+mpp11         11       gpio, ge0(rxd0), uart1(rxd), sd0(cmd), spi0(cs1),
+                       sata1(prsnt), spi1(cs1)
+mpp12         12       gpio, ge0(rxd1), i2c1(sda), sd0(d0), spi1(cs0),
+                       audio(spdifi)
+mpp13         13       gpio, ge0(rxd2), i2c1(sck), sd0(d1), tdm(pclk),
+                       audio(rmclk)
+mpp14         14       gpio, ge0(rxd3), pcie(clkreq0), sd0(d2), spi1(mosi),
+                       spi0(cs2)
+mpp15         15       gpio, ge0(rxctl), pcie(clkreq1), sd0(d3), spi1(miso),
+                       spi0(cs3)
+mpp16         16       gpio, ge0(rxclk), uart1(rxd), tdm(int), audio(extclk)
+mpp17         17       gpo, ge(mdc)
+mpp18         18       gpio, ge(mdio)
+mpp19         19       gpio, ge0(txclk), ge1(txclkout), tdm(pclk)
+mpp20         20       gpo, ge0(txd4), ge1(txd0)
+mpp21         21       gpo, ge0(txd5), ge1(txd1), uart1(txd)
+mpp22         22       gpo, ge0(txd6), ge1(txd2), uart0(rts)
+mpp23         23       gpo, ge0(txd7), ge1(txd3), spi1(mosi)
+mpp24         24       gpio, ge0(col), ge1(txctl), spi1(cs0)
+mpp25         25       gpio, ge0(rxerr), ge1(rxd0), uart1(rxd)
+mpp26         26       gpio, ge0(crs), ge1(rxd1), spi1(miso)
+mpp27         27       gpio, ge0(rxd4), ge1(rxd2), uart0(cts)
+mpp28         28       gpio, ge0(rxd5), ge1(rxd3)
+mpp29         29       gpio, ge0(rxd6), ge1(rxctl), i2c1(sda)
+mpp30         30       gpio, ge0(rxd7), ge1(rxclk), i2c1(sck)
+mpp31         31       gpio, tclk, ge0(txerr)
+mpp32         32       gpio, spi0(cs0)
+mpp33         33       gpio, dev(bootcs), spi0(cs0)
+mpp34         34       gpo, dev(wen0), spi0(mosi)
+mpp35         35       gpo, dev(oen), spi0(sck)
+mpp36         36       gpo, dev(a1), spi0(miso)
+mpp37         37       gpo, dev(a0), sata0(prsnt)
+mpp38         38       gpio, dev(ready), uart1(cts), uart0(cts)
+mpp39         39       gpo, dev(ad0), audio(spdifo)
+mpp40         40       gpio, dev(ad1), uart1(rts), uart0(rts)
+mpp41         41       gpio, dev(ad2), uart1(rxd)
+mpp42         42       gpo, dev(ad3), uart1(txd)
+mpp43         43       gpo, dev(ad4), audio(bclk)
+mpp44         44       gpo, dev(ad5), audio(mclk)
+mpp45         45       gpo, dev(ad6), audio(lrclk)
+mpp46         46       gpo, dev(ad7), audio(sdo)
+mpp47         47       gpo, dev(ad8), sd0(clk), audio(spdifo)
+mpp48         48       gpio, dev(ad9), uart0(rts), sd0(cmd), sata1(prsnt),
+                       spi0(cs1)
+mpp49         49       gpio, dev(ad10), pcie(clkreq1), sd0(d0), spi1(cs0),
+                       audio(spdifi)
+mpp50         50       gpio, dev(ad11), uart0(cts), sd0(d1), spi1(miso),
+                       audio(rmclk)
+mpp51         51       gpio, dev(ad12), i2c1(sda), sd0(d2), spi1(mosi)
+mpp52         52       gpio, dev(ad13), i2c1(sck), sd0(d3), spi1(sck)
+mpp53         53       gpio, dev(ad14), sd0(clk), tdm(pclk), spi0(cs2),
+                       pcie(clkreq1)
+mpp54         54       gpo, dev(ad15), tdm(dtx)
+mpp55         55       gpio, dev(cs1), uart1(txd), tdm(rst), sata1(prsnt),
+                       sata0(prsnt)
+mpp56         56       gpio, dev(cs2), uart1(cts), uart0(cts), spi0(cs3),
+                       pcie(clkreq0), spi1(cs1)
+mpp57         57       gpio, dev(cs3), uart1(rxd), tdm(fsync), sata0(prsnt),
+                       audio(sdo)
+mpp58         58       gpio, dev(cs0), uart1(rts), tdm(int), audio(extclk),
+                       uart0(rts)
+mpp59         59       gpo, dev(ale0), uart1(rts), uart0(rts), audio(bclk)
+mpp60         60       gpio, dev(ale1), uart1(rxd), sata0(prsnt), pcie(rst-out),
+                       audio(sdi)
+mpp61         61       gpo, dev(wen1), uart1(txd), audio(rclk)
+mpp62         62       gpio, dev(a2), uart1(cts), tdm(drx), pcie(clkreq0),
+                       audio(mclk), uart0(cts)
+mpp63         63       gpo, spi0(sck), tclk
+mpp64         64       gpio, spi0(miso), spi0-1(cs1)
+mpp65         65       gpio, spi0(mosi), spi0-1(cs2)

+ 100 - 0
Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt

@@ -0,0 +1,100 @@
+* Marvell Armada XP SoC pinctrl driver for mpp
+
+Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding
+part and usage.
+
+Required properties:
+- compatible: "marvell,mv78230-pinctrl", "marvell,mv78260-pinctrl",
+              "marvell,mv78460-pinctrl"
+
+This driver supports all Armada XP variants, i.e. mv78230, mv78260, and mv78460.
+
+Available mpp pins/groups and functions:
+Note: brackets (x) are not part of the mpp name for marvell,function and given
+only for more detailed description in this document.
+
+* Marvell Armada XP (all variants)
+
+name          pins     functions
+================================================================================
+mpp0          0        gpio, ge0(txclko), lcd(d0)
+mpp1          1        gpio, ge0(txd0), lcd(d1)
+mpp2          2        gpio, ge0(txd1), lcd(d2)
+mpp3          3        gpio, ge0(txd2), lcd(d3)
+mpp4          4        gpio, ge0(txd3), lcd(d4)
+mpp5          5        gpio, ge0(txctl), lcd(d5)
+mpp6          6        gpio, ge0(rxd0), lcd(d6)
+mpp7          7        gpio, ge0(rxd1), lcd(d7)
+mpp8          8        gpio, ge0(rxd2), lcd(d8)
+mpp9          9        gpio, ge0(rxd3), lcd(d9)
+mpp10         10       gpio, ge0(rxctl), lcd(d10)
+mpp11         11       gpio, ge0(rxclk), lcd(d11)
+mpp12         12       gpio, ge0(txd4), ge1(txd0), lcd(d12)
+mpp13         13       gpio, ge0(txd5), ge1(txd1), lcd(d13)
+mpp14         14       gpio, ge0(txd6), ge1(txd2), lcd(d15)
+mpp15         15       gpio, ge0(txd7), ge1(txd3), lcd(d16)
+mpp16         16       gpio, ge0(txd7), ge1(txd3), lcd(d16)
+mpp17         17       gpio, ge0(col), ge1(txctl), lcd(d17)
+mpp18         18       gpio, ge0(rxerr), ge1(rxd0), lcd(d18), ptp(trig)
+mpp19         19       gpio, ge0(crs), ge1(rxd1), lcd(d19), ptp(evreq)
+mpp20         20       gpio, ge0(rxd4), ge1(rxd2), lcd(d20), ptp(clk)
+mpp21         21       gpio, ge0(rxd5), ge1(rxd3), lcd(d21), mem(bat)
+mpp22         22       gpio, ge0(rxd6), ge1(rxctl), lcd(d22), sata0(prsnt)
+mpp23         23       gpio, ge0(rxd7), ge1(rxclk), lcd(d23), sata1(prsnt)
+mpp24         24       gpio, lcd(hsync), sata1(prsnt), nf(bootcs-re), tdm(rst)
+mpp25         25       gpio, lcd(vsync), sata0(prsnt), nf(bootcs-we), tdm(pclk)
+mpp26         26       gpio, lcd(clk), tdm(fsync), vdd(cpu1-pd)
+mpp27         27       gpio, lcd(e), tdm(dtx), ptp(trig)
+mpp28         28       gpio, lcd(pwm), tdm(drx), ptp(evreq)
+mpp29         29       gpio, lcd(ref-clk), tdm(int0), ptp(clk), vdd(cpu0-pd)
+mpp30         30       gpio, tdm(int1), sd0(clk)
+mpp31         31       gpio, tdm(int2), sd0(cmd), vdd(cpu0-pd)
+mpp32         32       gpio, tdm(int3), sd0(d0), vdd(cpu1-pd)
+mpp33         33       gpio, tdm(int4), sd0(d1), mem(bat)
+mpp34         34       gpio, tdm(int5), sd0(d2), sata0(prsnt)
+mpp35         35       gpio, tdm(int6), sd0(d3), sata1(prsnt)
+mpp36         36       gpio, spi(mosi)
+mpp37         37       gpio, spi(miso)
+mpp38         38       gpio, spi(sck)
+mpp39         39       gpio, spi(cs0)
+mpp40         40       gpio, spi(cs1), uart2(cts), lcd(vga-hsync), vdd(cpu1-pd),
+                       pcie(clkreq0)
+mpp41         41       gpio, spi(cs2), uart2(rts), lcd(vga-vsync), sata1(prsnt),
+                       pcie(clkreq1)
+mpp42         42       gpio, uart2(rxd), uart0(cts), tdm(int7), tdm-1(timer),
+                       vdd(cpu0-pd)
+mpp43         43       gpio, uart2(txd), uart0(rts), spi(cs3), pcie(rstout),
+                       vdd(cpu2-3-pd){1}
+mpp44         44       gpio, uart2(cts), uart3(rxd), spi(cs4), pcie(clkreq2),
+                       mem(bat)
+mpp45         45       gpio, uart2(rts), uart3(txd), spi(cs5), sata1(prsnt)
+mpp46         46       gpio, uart3(rts), uart1(rts), spi(cs6), sata0(prsnt)
+mpp47         47       gpio, uart3(cts), uart1(cts), spi(cs7), pcie(clkreq3),
+                       ref(clkout)
+mpp48         48       gpio, tclk, dev(burst/last)
+
+* Marvell Armada XP (mv78260 and mv78460 only)
+
+name          pins     functions
+================================================================================
+mpp49         49       gpio, dev(we3)
+mpp50         50       gpio, dev(we2)
+mpp51         51       gpio, dev(ad16)
+mpp52         52       gpio, dev(ad17)
+mpp53         53       gpio, dev(ad18)
+mpp54         54       gpio, dev(ad19)
+mpp55         55       gpio, dev(ad20), vdd(cpu0-pd)
+mpp56         56       gpio, dev(ad21), vdd(cpu1-pd)
+mpp57         57       gpio, dev(ad22), vdd(cpu2-3-pd){1}
+mpp58         58       gpio, dev(ad23)
+mpp59         59       gpio, dev(ad24)
+mpp60         60       gpio, dev(ad25)
+mpp61         61       gpio, dev(ad26)
+mpp62         62       gpio, dev(ad27)
+mpp63         63       gpio, dev(ad28)
+mpp64         64       gpio, dev(ad29)
+mpp65         65       gpio, dev(ad30)
+mpp66         66       gpio, dev(ad31)
+
+Notes:
+* {1} vdd(cpu2-3-pd) only available on mv78460.

+ 72 - 0
Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt

@@ -0,0 +1,72 @@
+* Marvell Dove SoC pinctrl driver for mpp
+
+Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding
+part and usage.
+
+Required properties:
+- compatible: "marvell,dove-pinctrl"
+- clocks: (optional) phandle of pdma clock
+
+Available mpp pins/groups and functions:
+Note: brackets (x) are not part of the mpp name for marvell,function and given
+only for more detailed description in this document.
+
+name          pins     functions
+================================================================================
+mpp0          0        gpio, pmu, uart2(rts), sdio0(cd), lcd0(pwm)
+mpp1          1        gpio, pmu, uart2(cts), sdio0(wp), lcd1(pwm)
+mpp2          2        gpio, pmu, uart2(txd), sdio0(buspwr), sata(prsnt),
+                       uart1(rts)
+mpp3          3        gpio, pmu, uart2(rxd), sdio0(ledctrl), sata(act),
+                       uart1(cts), lcd-spi(cs1)
+mpp4          4        gpio, pmu, uart3(rts), sdio1(cd), spi1(miso)
+mpp5          5        gpio, pmu, uart3(cts), sdio1(wp), spi1(cs)
+mpp6          6        gpio, pmu, uart3(txd), sdio1(buspwr), spi1(mosi)
+mpp7          7        gpio, pmu, uart3(rxd), sdio1(ledctrl), spi1(sck)
+mpp8          8        gpio, pmu, watchdog(rstout)
+mpp9          9        gpio, pmu, pex1(clkreq)
+mpp10         10       gpio, pmu, ssp(sclk)
+mpp11         11       gpio, pmu, sata(prsnt), sata-1(act), sdio0(ledctrl),
+                       sdio1(ledctrl), pex0(clkreq)
+mpp12         12       gpio, pmu, uart2(rts), audio0(extclk), sdio1(cd), sata(act)
+mpp13         13       gpio, pmu, uart2(cts), audio1(extclk), sdio1(wp),
+                       ssp(extclk)
+mpp14         14       gpio, pmu, uart2(txd), sdio1(buspwr), ssp(rxd)
+mpp15         15       gpio, pmu, uart2(rxd), sdio1(ledctrl), ssp(sfrm)
+mpp16         16       gpio, uart3(rts), sdio0(cd), ac97(sdi1), lcd-spi(cs1)
+mpp17         17       gpio, uart3(cts), sdio0(wp), ac97(sdi2), twsi(sda),
+                       ac97-1(sysclko)
+mpp18         18       gpio, uart3(txd), sdio0(buspwr), ac97(sdi3), lcd0(pwm)
+mpp19         19       gpio, uart3(rxd), sdio0(ledctrl), twsi(sck)
+mpp20         20       gpio, sdio0(cd), sdio1(cd), spi1(miso), lcd-spi(miso),
+                       ac97(sysclko)
+mpp21         21       gpio, sdio0(wp), sdio1(wp), spi1(cs), lcd-spi(cs0),
+                       uart1(cts), ssp(sfrm)
+mpp22         22       gpio, sdio0(buspwr), sdio1(buspwr), spi1(mosi),
+                       lcd-spi(mosi), uart1(cts), ssp(txd)
+mpp23         23       gpio, sdio0(ledctrl), sdio1(ledctrl), spi1(sck),
+                       lcd-spi(sck), ssp(sclk)
+mpp_camera    24-39    gpio, camera
+mpp_sdio0     40-45    gpio, sdio0
+mpp_sdio1     46-51    gpio, sdio1
+mpp_audio1    52-57    gpio, i2s1/spdifo, i2s1, spdifo, twsi, ssp/spdifo, ssp,
+                       ssp/twsi
+mpp_spi0      58-61    gpio, spi0
+mpp_uart1     62-63    gpio, uart1
+mpp_nand      64-71    gpo, nand
+audio0        -        i2s, ac97
+twsi          -        none, opt1, opt2, opt3
+
+Notes:
+* group "mpp_audio1" allows the following functions and gpio pins:
+  - gpio          : gpio on pins 52-57
+  - i2s1/spdifo   : audio1 i2s on pins 52-55 and spdifo on 57, no gpios
+  - i2s1          : audio1 i2s on pins 52-55, gpio on pins 56,57
+  - spdifo        : spdifo on pin 57, gpio on pins 52-55
+  - twsi          : twsi on pins 56,57, gpio on pins 52-55
+  - ssp/spdifo    : ssp on pins 52-55, spdifo on pin 57, no gpios
+  - ssp           : ssp on pins 52-55, gpio on pins 56,57
+  - ssp/twsi      : ssp on pins 52-55, twsi on pins 56,57, no gpios
+* group "audio0" internally muxes i2s0 or ac97 controller to the dedicated
+  audio0 pins.
+* group "twsi" internally muxes twsi controller to the dedicated or option pins.

+ 279 - 0
Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt

@@ -0,0 +1,279 @@
+* Marvell Kirkwood SoC pinctrl driver for mpp
+
+Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding
+part and usage.
+
+Required properties:
+- compatible: "marvell,88f6180-pinctrl",
+              "marvell,88f6190-pinctrl", "marvell,88f6192-pinctrl",
+              "marvell,88f6281-pinctrl", "marvell,88f6282-pinctrl"
+
+This driver supports all kirkwood variants, i.e. 88f6180, 88f619x, and 88f628x.
+
+Available mpp pins/groups and functions:
+Note: brackets (x) are not part of the mpp name for marvell,function and given
+only for more detailed description in this document.
+
+* Marvell Kirkwood 88f6180
+
+name          pins     functions
+================================================================================
+mpp0          0        gpio, nand(io2), spi(cs)
+mpp1          1        gpo, nand(io3), spi(mosi)
+mpp2          2        gpo, nand(io4), spi(sck)
+mpp3          3        gpo, nand(io5), spi(miso)
+mpp4          4        gpio, nand(io6), uart0(rxd), ptp(clk)
+mpp5          5        gpo, nand(io7), uart0(txd), ptp(trig)
+mpp6          6        sysrst(out), spi(mosi), ptp(trig)
+mpp7          7        gpo, pex(rsto), spi(cs), ptp(trig)
+mpp8          8        gpio, twsi0(sda), uart0(rts), uart1(rts), ptp(clk),
+                       mii(col)
+mpp9          9        gpio, twsi(sck), uart0(cts), uart1(cts), ptp(evreq),
+                       mii(crs)
+mpp10         10       gpo, spi(sck), uart0(txd), ptp(trig)
+mpp11         11       gpio, spi(miso), uart0(rxd), ptp(clk), ptp-1(evreq),
+                       ptp-2(trig)
+mpp12         12       gpo, sdio(clk)
+mpp13         13       gpio, sdio(cmd), uart1(txd)
+mpp14         14       gpio, sdio(d0), uart1(rxd), mii(col)
+mpp15         15       gpio, sdio(d1), uart0(rts), uart1(txd)
+mpp16         16       gpio, sdio(d2), uart0(cts), uart1(rxd), mii(crs)
+mpp17         17       gpio, sdio(d3)
+mpp18         18       gpo, nand(io0)
+mpp19         19       gpo, nand(io1)
+mpp20         20       gpio, mii(rxerr)
+mpp21         21       gpio, audio(spdifi)
+mpp22         22       gpio, audio(spdifo)
+mpp23         23       gpio, audio(rmclk)
+mpp24         24       gpio, audio(bclk)
+mpp25         25       gpio, audio(sdo)
+mpp26         26       gpio, audio(lrclk)
+mpp27         27       gpio, audio(mclk)
+mpp28         28       gpio, audio(sdi)
+mpp29         29       gpio, audio(extclk)
+
+* Marvell Kirkwood 88f6190
+
+name          pins     functions
+================================================================================
+mpp0          0        gpio, nand(io2), spi(cs)
+mpp1          1        gpo, nand(io3), spi(mosi)
+mpp2          2        gpo, nand(io4), spi(sck)
+mpp3          3        gpo, nand(io5), spi(miso)
+mpp4          4        gpio, nand(io6), uart0(rxd), ptp(clk)
+mpp5          5        gpo, nand(io7), uart0(txd), ptp(trig), sata0(act)
+mpp6          6        sysrst(out), spi(mosi), ptp(trig)
+mpp7          7        gpo, pex(rsto), spi(cs), ptp(trig)
+mpp8          8        gpio, twsi0(sda), uart0(rts), uart1(rts), ptp(clk),
+                       mii(col), mii-1(rxerr)
+mpp9          9        gpio, twsi(sck), uart0(cts), uart1(cts), ptp(evreq),
+                       mii(crs), sata0(prsnt)
+mpp10         10       gpo, spi(sck), uart0(txd), ptp(trig)
+mpp11         11       gpio, spi(miso), uart0(rxd), ptp(clk), ptp-1(evreq),
+                       ptp-2(trig), sata0(act)
+mpp12         12       gpo, sdio(clk)
+mpp13         13       gpio, sdio(cmd), uart1(txd)
+mpp14         14       gpio, sdio(d0), uart1(rxd), mii(col)
+mpp15         15       gpio, sdio(d1), uart0(rts), uart1(txd), sata0(act)
+mpp16         16       gpio, sdio(d2), uart0(cts), uart1(rxd), mii(crs)
+mpp17         17       gpio, sdio(d3), sata0(prsnt)
+mpp18         18       gpo, nand(io0)
+mpp19         19       gpo, nand(io1)
+mpp20         20       gpio, ge1(txd0)
+mpp21         21       gpio, ge1(txd1), sata0(act)
+mpp22         22       gpio, ge1(txd2)
+mpp23         23       gpio, ge1(txd3), sata0(prsnt)
+mpp24         24       gpio, ge1(rxd0)
+mpp25         25       gpio, ge1(rxd1)
+mpp26         26       gpio, ge1(rxd2)
+mpp27         27       gpio, ge1(rxd3)
+mpp28         28       gpio, ge1(col)
+mpp29         29       gpio, ge1(txclk)
+mpp30         30       gpio, ge1(rxclk)
+mpp31         31       gpio, ge1(rxclk)
+mpp32         32       gpio, ge1(txclko)
+mpp33         33       gpo, ge1(txclk)
+mpp34         34       gpio, ge1(txen)
+mpp35         35       gpio, ge1(rxerr), sata0(act), mii(rxerr)
+
+* Marvell Kirkwood 88f6192
+
+name          pins     functions
+================================================================================
+mpp0          0        gpio, nand(io2), spi(cs)
+mpp1          1        gpo, nand(io3), spi(mosi)
+mpp2          2        gpo, nand(io4), spi(sck)
+mpp3          3        gpo, nand(io5), spi(miso)
+mpp4          4        gpio, nand(io6), uart0(rxd), ptp(clk), sata1(act)
+mpp5          5        gpo, nand(io7), uart0(txd), ptp(trig), sata0(act)
+mpp6          6        sysrst(out), spi(mosi), ptp(trig)
+mpp7          7        gpo, pex(rsto), spi(cs), ptp(trig)
+mpp8          8        gpio, twsi0(sda), uart0(rts), uart1(rts), ptp(clk),
+                       mii(col), mii-1(rxerr), sata1(prsnt)
+mpp9          9        gpio, twsi(sck), uart0(cts), uart1(cts), ptp(evreq),
+                       mii(crs), sata0(prsnt)
+mpp10         10       gpo, spi(sck), uart0(txd), ptp(trig), sata1(act)
+mpp11         11       gpio, spi(miso), uart0(rxd), ptp(clk), ptp-1(evreq),
+                       ptp-2(trig), sata0(act)
+mpp12         12       gpo, sdio(clk)
+mpp13         13       gpio, sdio(cmd), uart1(txd)
+mpp14         14       gpio, sdio(d0), uart1(rxd), mii(col), sata1(prsnt)
+mpp15         15       gpio, sdio(d1), uart0(rts), uart1(txd), sata0(act)
+mpp16         16       gpio, sdio(d2), uart0(cts), uart1(rxd), mii(crs),
+                       sata1(act)
+mpp17         17       gpio, sdio(d3), sata0(prsnt)
+mpp18         18       gpo, nand(io0)
+mpp19         19       gpo, nand(io1)
+mpp20         20       gpio, ge1(txd0), ts(mp0), tdm(tx0ql), audio(spdifi),
+                       sata1(act)
+mpp21         21       gpio, ge1(txd1), sata0(act), ts(mp1), tdm(rx0ql),
+                       audio(spdifo)
+mpp22         22       gpio, ge1(txd2), ts(mp2), tdm(tx2ql), audio(rmclk),
+                       sata1(prsnt)
+mpp23         23       gpio, ge1(txd3), sata0(prsnt), ts(mp3), tdm(rx2ql),
+                       audio(bclk)
+mpp24         24       gpio, ge1(rxd0), ts(mp4), tdm(spi-cs0), audio(sdo)
+mpp25         25       gpio, ge1(rxd1), ts(mp5), tdm(spi-sck), audio(lrclk)
+mpp26         26       gpio, ge1(rxd2), ts(mp6), tdm(spi-miso), audio(mclk)
+mpp27         27       gpio, ge1(rxd3), ts(mp7), tdm(spi-mosi), audio(sdi)
+mpp28         28       gpio, ge1(col), ts(mp8), tdm(int), audio(extclk)
+mpp29         29       gpio, ge1(txclk), ts(mp9), tdm(rst)
+mpp30         30       gpio, ge1(rxclk), ts(mp10), tdm(pclk)
+mpp31         31       gpio, ge1(rxclk), ts(mp11), tdm(fs)
+mpp32         32       gpio, ge1(txclko), ts(mp12), tdm(drx)
+mpp33         33       gpo, ge1(txclk), tdm(drx)
+mpp34         34       gpio, ge1(txen), tdm(spi-cs1)
+mpp35         35       gpio, ge1(rxerr), sata0(act), mii(rxerr), tdm(tx0ql)
+
+* Marvell Kirkwood 88f6281
+
+name          pins     functions
+================================================================================
+mpp0          0        gpio, nand(io2), spi(cs)
+mpp1          1        gpo, nand(io3), spi(mosi)
+mpp2          2        gpo, nand(io4), spi(sck)
+mpp3          3        gpo, nand(io5), spi(miso)
+mpp4          4        gpio, nand(io6), uart0(rxd), ptp(clk), sata1(act)
+mpp5          5        gpo, nand(io7), uart0(txd), ptp(trig), sata0(act)
+mpp6          6        sysrst(out), spi(mosi), ptp(trig)
+mpp7          7        gpo, pex(rsto), spi(cs), ptp(trig)
+mpp8          8        gpio, twsi0(sda), uart0(rts), uart1(rts), ptp(clk),
+                       mii(col), mii-1(rxerr), sata1(prsnt)
+mpp9          9        gpio, twsi(sck), uart0(cts), uart1(cts), ptp(evreq),
+                       mii(crs), sata0(prsnt)
+mpp10         10       gpo, spi(sck), uart0(txd), ptp(trig), sata1(act)
+mpp11         11       gpio, spi(miso), uart0(rxd), ptp(clk), ptp-1(evreq),
+                       ptp-2(trig), sata0(act)
+mpp12         12       gpio, sdio(clk)
+mpp13         13       gpio, sdio(cmd), uart1(txd)
+mpp14         14       gpio, sdio(d0), uart1(rxd), mii(col), sata1(prsnt)
+mpp15         15       gpio, sdio(d1), uart0(rts), uart1(txd), sata0(act)
+mpp16         16       gpio, sdio(d2), uart0(cts), uart1(rxd), mii(crs),
+                       sata1(act)
+mpp17         17       gpio, sdio(d3), sata0(prsnt)
+mpp18         18       gpo, nand(io0)
+mpp19         19       gpo, nand(io1)
+mpp20         20       gpio, ge1(txd0), ts(mp0), tdm(tx0ql), audio(spdifi),
+                       sata1(act)
+mpp21         21       gpio, ge1(txd1), sata0(act), ts(mp1), tdm(rx0ql),
+                       audio(spdifo)
+mpp22         22       gpio, ge1(txd2), ts(mp2), tdm(tx2ql), audio(rmclk),
+                       sata1(prsnt)
+mpp23         23       gpio, ge1(txd3), sata0(prsnt), ts(mp3), tdm(rx2ql),
+                       audio(bclk)
+mpp24         24       gpio, ge1(rxd0), ts(mp4), tdm(spi-cs0), audio(sdo)
+mpp25         25       gpio, ge1(rxd1), ts(mp5), tdm(spi-sck), audio(lrclk)
+mpp26         26       gpio, ge1(rxd2), ts(mp6), tdm(spi-miso), audio(mclk)
+mpp27         27       gpio, ge1(rxd3), ts(mp7), tdm(spi-mosi), audio(sdi)
+mpp28         28       gpio, ge1(col), ts(mp8), tdm(int), audio(extclk)
+mpp29         29       gpio, ge1(txclk), ts(mp9), tdm(rst)
+mpp30         30       gpio, ge1(rxclk), ts(mp10), tdm(pclk)
+mpp31         31       gpio, ge1(rxclk), ts(mp11), tdm(fs)
+mpp32         32       gpio, ge1(txclko), ts(mp12), tdm(drx)
+mpp33         33       gpo, ge1(txclk), tdm(drx)
+mpp34         34       gpio, ge1(txen), tdm(spi-cs1), sata1(act)
+mpp35         35       gpio, ge1(rxerr), sata0(act), mii(rxerr), tdm(tx0ql)
+mpp36         36       gpio, ts(mp0), tdm(spi-cs1), audio(spdifi)
+mpp37         37       gpio, ts(mp1), tdm(tx2ql), audio(spdifo)
+mpp38         38       gpio, ts(mp2), tdm(rx2ql), audio(rmclk)
+mpp39         39       gpio, ts(mp3), tdm(spi-cs0), audio(bclk)
+mpp40         40       gpio, ts(mp4), tdm(spi-sck), audio(sdo)
+mpp41         41       gpio, ts(mp5), tdm(spi-miso), audio(lrclk)
+mpp42         42       gpio, ts(mp6), tdm(spi-mosi), audio(mclk)
+mpp43         43       gpio, ts(mp7), tdm(int), audio(sdi)
+mpp44         44       gpio, ts(mp8), tdm(rst), audio(extclk)
+mpp45         45       gpio, ts(mp9), tdm(pclk)
+mpp46         46       gpio, ts(mp10), tdm(fs)
+mpp47         47       gpio, ts(mp11), tdm(drx)
+mpp48         48       gpio, ts(mp12), tdm(dtx)
+mpp49         49       gpio, ts(mp9), tdm(rx0ql), ptp(clk)
+
+* Marvell Kirkwood 88f6282
+
+name          pins     functions
+================================================================================
+mpp0          0        gpio, nand(io2), spi(cs)
+mpp1          1        gpo, nand(io3), spi(mosi)
+mpp2          2        gpo, nand(io4), spi(sck)
+mpp3          3        gpo, nand(io5), spi(miso)
+mpp4          4        gpio, nand(io6), uart0(rxd), sata1(act), lcd(hsync)
+mpp5          5        gpo, nand(io7), uart0(txd), sata0(act), lcd(vsync)
+mpp6          6        sysrst(out), spi(mosi)
+mpp7          7        gpo, spi(cs), lcd(pwm)
+mpp8          8        gpio, twsi0(sda), uart0(rts), uart1(rts), mii(col),
+                       mii-1(rxerr), sata1(prsnt)
+mpp9          9        gpio, twsi(sck), uart0(cts), uart1(cts), mii(crs),
+                       sata0(prsnt)
+mpp10         10       gpo, spi(sck), uart0(txd), sata1(act)
+mpp11         11       gpio, spi(miso), uart0(rxd), sata0(act)
+mpp12         12       gpo, sdio(clk), audio(spdifo), spi(mosi), twsi(sda)
+mpp13         13       gpio, sdio(cmd), uart1(txd), audio(rmclk), lcd(pwm)
+mpp14         14       gpio, sdio(d0), uart1(rxd), mii(col), sata1(prsnt),
+                       audio(spdifi), audio-1(sdi)
+mpp15         15       gpio, sdio(d1), uart0(rts), uart1(txd), sata0(act),
+                       spi(cs)
+mpp16         16       gpio, sdio(d2), uart0(cts), uart1(rxd), mii(crs),
+                       sata1(act), lcd(extclk)
+mpp17         17       gpio, sdio(d3), sata0(prsnt), sata1(act), twsi1(sck)
+mpp18         18       gpo, nand(io0), pex(clkreq)
+mpp19         19       gpo, nand(io1)
+mpp20         20       gpio, ge1(txd0), ts(mp0), tdm(tx0ql), audio(spdifi),
+                       sata1(act), lcd(d0)
+mpp21         21       gpio, ge1(txd1), sata0(act), ts(mp1), tdm(rx0ql),
+                       audio(spdifo), lcd(d1)
+mpp22         22       gpio, ge1(txd2), ts(mp2), tdm(tx2ql), audio(rmclk),
+                       sata1(prsnt), lcd(d2)
+mpp23         23       gpio, ge1(txd3), sata0(prsnt), ts(mp3), tdm(rx2ql),
+                       audio(bclk), lcd(d3)
+mpp24         24       gpio, ge1(rxd0), ts(mp4), tdm(spi-cs0), audio(sdo),
+                       lcd(d4)
+mpp25         25       gpio, ge1(rxd1), ts(mp5), tdm(spi-sck), audio(lrclk),
+                       lcd(d5)
+mpp26         26       gpio, ge1(rxd2), ts(mp6), tdm(spi-miso), audio(mclk),
+                       lcd(d6)
+mpp27         27       gpio, ge1(rxd3), ts(mp7), tdm(spi-mosi), audio(sdi),
+                       lcd(d7)
+mpp28         28       gpio, ge1(col), ts(mp8), tdm(int), audio(extclk),
+                       lcd(d8)
+mpp29         29       gpio, ge1(txclk), ts(mp9), tdm(rst), lcd(d9)
+mpp30         30       gpio, ge1(rxclk), ts(mp10), tdm(pclk), lcd(d10)
+mpp31         31       gpio, ge1(rxclk), ts(mp11), tdm(fs), lcd(d11)
+mpp32         32       gpio, ge1(txclko), ts(mp12), tdm(drx), lcd(d12)
+mpp33         33       gpo, ge1(txclk), tdm(drx), lcd(d13)
+mpp34         34       gpio, ge1(txen), tdm(spi-cs1), sata1(act), lcd(d14)
+mpp35         35       gpio, ge1(rxerr), sata0(act), mii(rxerr), tdm(tx0ql),
+                       lcd(d15)
+mpp36         36       gpio, ts(mp0), tdm(spi-cs1), audio(spdifi), twsi1(sda)
+mpp37         37       gpio, ts(mp1), tdm(tx2ql), audio(spdifo), twsi1(sck)
+mpp38         38       gpio, ts(mp2), tdm(rx2ql), audio(rmclk), lcd(d18)
+mpp39         39       gpio, ts(mp3), tdm(spi-cs0), audio(bclk), lcd(d19)
+mpp40         40       gpio, ts(mp4), tdm(spi-sck), audio(sdo), lcd(d20)
+mpp41         41       gpio, ts(mp5), tdm(spi-miso), audio(lrclk), lcd(d21)
+mpp42         42       gpio, ts(mp6), tdm(spi-mosi), audio(mclk), lcd(d22)
+mpp43         43       gpio, ts(mp7), tdm(int), audio(sdi), lcd(d23)
+mpp44         44       gpio, ts(mp8), tdm(rst), audio(extclk), lcd(clk)
+mpp45         45       gpio, ts(mp9), tdm(pclk), lcd(e)
+mpp46         46       gpio, ts(mp10), tdm(fs), lcd(hsync)
+mpp47         47       gpio, ts(mp11), tdm(drx), lcd(vsync)
+mpp48         48       gpio, ts(mp12), tdm(dtx), lcd(d16)
+mpp49         49       gpo, tdm(rx0ql), pex(clkreq), lcd(d17)

+ 46 - 0
Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt

@@ -0,0 +1,46 @@
+* Marvell SoC pinctrl core driver for mpp
+
+The pinctrl driver enables Marvell SoCs to configure the multi-purpose pins
+(mpp) to a specific function. For each SoC family there is a SoC specific
+driver using this core driver.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+A Marvell SoC pin configuration node is a node of a group of pins which can
+be used for a specific device or function. Each node requires one or more
+mpp pins or group of pins and a mpp function common to all pins.
+
+Required properties for pinctrl driver:
+- compatible: "marvell,<soc>-pinctrl"
+  Please refer to each marvell,<soc>-pinctrl.txt binding doc for supported SoCs.
+
+Required properties for pin configuration node:
+- marvell,pins: string array of mpp pins or group of pins to be muxed.
+- marvell,function: string representing a function to mux to for all
+    marvell,pins given in this pin configuration node. The function has to be
+    common for all marvell,pins. Please refer to marvell,<soc>-pinctrl.txt for
+    valid pin/pin group names and available function names for each SoC.
+
+Examples:
+
+uart1: serial@12100 {
+	compatible = "ns16550a";
+	reg = <0x12100 0x100>;
+	reg-shift = <2>;
+	interrupts = <7>;
+
+	pinctrl-0 = <&pmx_uart1_sw>;
+	pinctrl-names = "default";
+};
+
+pinctrl: pinctrl@d0200 {
+	compatible = "marvell,dove-pinctrl";
+	reg = <0xd0200 0x20>;
+
+	pmx_uart1_sw: pmx-uart1-sw {
+		marvell,pins = "mpp_uart1";
+		marvell,function = "uart1";
+	};
+};

+ 44 - 0
arch/arm/boot/dts/armada-370.dtsi

@@ -21,6 +21,12 @@
 	model = "Marvell Armada 370 family SoC";
 	model = "Marvell Armada 370 family SoC";
 	compatible = "marvell,armada370", "marvell,armada-370-xp";
 	compatible = "marvell,armada370", "marvell,armada-370-xp";
 
 
+	aliases {
+		gpio0 = &gpio0;
+		gpio1 = &gpio1;
+		gpio2 = &gpio2;
+	};
+
 	mpic: interrupt-controller@d0020000 {
 	mpic: interrupt-controller@d0020000 {
 	      reg = <0xd0020a00 0x1d0>,
 	      reg = <0xd0020a00 0x1d0>,
 		    <0xd0021870 0x58>;
 		    <0xd0021870 0x58>;
@@ -31,5 +37,43 @@
 				compatible = "marvell,armada-370-xp-system-controller";
 				compatible = "marvell,armada-370-xp-system-controller";
 				reg = <0xd0018200 0x100>;
 				reg = <0xd0018200 0x100>;
 		};
 		};
+
+		pinctrl {
+			compatible = "marvell,mv88f6710-pinctrl";
+			reg = <0xd0018000 0x38>;
+	        };
+
+		gpio0: gpio@d0018100 {
+			compatible = "marvell,orion-gpio";
+			reg = <0xd0018100 0x40>;
+			ngpios = <32>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupts-cells = <2>;
+			interrupts = <82>, <83>, <84>, <85>;
+		};
+
+		gpio1: gpio@d0018140 {
+			compatible = "marvell,orion-gpio";
+			reg = <0xd0018140 0x40>;
+			ngpios = <32>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupts-cells = <2>;
+			interrupts = <87>, <88>, <89>, <90>;
+		};
+
+		gpio2: gpio@d0018180 {
+			compatible = "marvell,orion-gpio";
+			reg = <0xd0018180 0x40>;
+			ngpios = <2>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupts-cells = <2>;
+			interrupts = <91>;
+		};
 	};
 	};
 };
 };

+ 2 - 2
arch/arm/boot/dts/armada-xp-db.dts

@@ -14,11 +14,11 @@
  */
  */
 
 
 /dts-v1/;
 /dts-v1/;
-/include/ "armada-xp.dtsi"
+/include/ "armada-xp-mv78460.dtsi"
 
 
 / {
 / {
 	model = "Marvell Armada XP Evaluation Board";
 	model = "Marvell Armada XP Evaluation Board";
-	compatible = "marvell,axp-db", "marvell,armadaxp", "marvell,armada-370-xp";
+	compatible = "marvell,axp-db", "marvell,armadaxp-mv78460", "marvell,armadaxp", "marvell,armada-370-xp";
 
 
 	chosen {
 	chosen {
 		bootargs = "console=ttyS0,115200 earlyprintk";
 		bootargs = "console=ttyS0,115200 earlyprintk";

+ 57 - 0
arch/arm/boot/dts/armada-xp-mv78230.dtsi

@@ -0,0 +1,57 @@
+/*
+ * Device Tree Include file for Marvell Armada XP family SoC
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * Contains definitions specific to the Armada XP MV78230 SoC that are not
+ * common to all Armada XP SoCs.
+ */
+
+/include/ "armada-xp.dtsi"
+
+/ {
+	model = "Marvell Armada XP MV78230 SoC";
+	compatible = "marvell,armadaxp-mv78230", "marvell,armadaxp", "marvell,armada-370-xp";
+
+	aliases {
+		gpio0 = &gpio0;
+		gpio1 = &gpio1;
+	};
+
+	soc {
+		pinctrl {
+			compatible = "marvell,mv78230-pinctrl";
+			reg = <0xd0018000 0x38>;
+		};
+
+		gpio0: gpio@d0018100 {
+			compatible = "marvell,armadaxp-gpio";
+			reg = <0xd0018100 0x40>,
+			    <0xd0018800 0x30>;
+			ngpios = <32>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupts-cells = <2>;
+			interrupts = <16>, <17>, <18>, <19>;
+		};
+
+		gpio1: gpio@d0018140 {
+			compatible = "marvell,armadaxp-gpio";
+			reg = <0xd0018140 0x40>,
+			    <0xd0018840 0x30>;
+			ngpios = <17>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupts-cells = <2>;
+			interrupts = <20>, <21>, <22>;
+		};
+	};
+};

+ 70 - 0
arch/arm/boot/dts/armada-xp-mv78260.dtsi

@@ -0,0 +1,70 @@
+/*
+ * Device Tree Include file for Marvell Armada XP family SoC
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * Contains definitions specific to the Armada XP MV78260 SoC that are not
+ * common to all Armada XP SoCs.
+ */
+
+/include/ "armada-xp.dtsi"
+
+/ {
+	model = "Marvell Armada XP MV78260 SoC";
+	compatible = "marvell,armadaxp-mv78260", "marvell,armadaxp", "marvell,armada-370-xp";
+
+	aliases {
+		gpio0 = &gpio0;
+		gpio1 = &gpio1;
+		gpio2 = &gpio2;
+	};
+
+	soc {
+		pinctrl {
+			compatible = "marvell,mv78260-pinctrl";
+			reg = <0xd0018000 0x38>;
+		};
+
+		gpio0: gpio@d0018100 {
+			compatible = "marvell,armadaxp-gpio";
+			reg = <0xd0018100 0x40>,
+			    <0xd0018800 0x30>;
+			ngpios = <32>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupts-cells = <2>;
+			interrupts = <16>, <17>, <18>, <19>;
+		};
+
+		gpio1: gpio@d0018140 {
+			compatible = "marvell,armadaxp-gpio";
+			reg = <0xd0018140 0x40>,
+			    <0xd0018840 0x30>;
+			ngpios = <32>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupts-cells = <2>;
+			interrupts = <20>, <21>, <22>, <23>;
+		};
+
+		gpio2: gpio@d0018180 {
+			compatible = "marvell,armadaxp-gpio";
+			reg = <0xd0018180 0x40>,
+			    <0xd0018870 0x30>;
+			ngpios = <3>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupts-cells = <2>;
+			interrupts = <24>;
+		};
+	};
+};

+ 70 - 0
arch/arm/boot/dts/armada-xp-mv78460.dtsi

@@ -0,0 +1,70 @@
+/*
+ * Device Tree Include file for Marvell Armada XP family SoC
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * Contains definitions specific to the Armada XP MV78460 SoC that are not
+ * common to all Armada XP SoCs.
+ */
+
+/include/ "armada-xp.dtsi"
+
+/ {
+	model = "Marvell Armada XP MV78460 SoC";
+	compatible = "marvell,armadaxp-mv78460", "marvell,armadaxp", "marvell,armada-370-xp";
+
+	aliases {
+		gpio0 = &gpio0;
+		gpio1 = &gpio1;
+		gpio2 = &gpio2;
+	};
+
+	soc {
+		pinctrl {
+			compatible = "marvell,mv78460-pinctrl";
+			reg = <0xd0018000 0x38>;
+		};
+
+		gpio0: gpio@d0018100 {
+			compatible = "marvell,armadaxp-gpio";
+			reg = <0xd0018100 0x40>,
+			    <0xd0018800 0x30>;
+			ngpios = <32>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupts-cells = <2>;
+			interrupts = <16>, <17>, <18>, <19>;
+		};
+
+		gpio1: gpio@d0018140 {
+			compatible = "marvell,armadaxp-gpio";
+			reg = <0xd0018140 0x40>,
+			    <0xd0018840 0x30>;
+			ngpios = <32>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupts-cells = <2>;
+			interrupts = <20>, <21>, <22>, <23>;
+		};
+
+		gpio2: gpio@d0018180 {
+			compatible = "marvell,armadaxp-gpio";
+			reg = <0xd0018180 0x40>,
+			    <0xd0018870 0x30>;
+			ngpios = <3>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupts-cells = <2>;
+			interrupts = <24>;
+		};
+	};
+ };

+ 2 - 0
arch/arm/configs/mvebu_defconfig

@@ -21,6 +21,8 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
 # CONFIG_EXT3_FS_XATTR is not set

+ 15 - 3
arch/arm/mach-mvebu/Kconfig

@@ -13,13 +13,25 @@ if ARCH_MVEBU
 menu "Marvell SOC with device tree"
 menu "Marvell SOC with device tree"
 
 
 config MACH_ARMADA_370_XP
 config MACH_ARMADA_370_XP
-	bool "Marvell Armada 370 and Aramada XP boards"
+	bool
 	select ARMADA_370_XP_TIMER
 	select ARMADA_370_XP_TIMER
 	select CPU_V7
 	select CPU_V7
+
+config MACH_ARMADA_370
+	bool "Marvell Armada 370 boards"
+	select MACH_ARMADA_370_XP
+	select PINCTRL_ARMADA_370
 	help
 	help
+	  Say 'Y' here if you want your kernel to support boards based
+	  on the Marvell Armada 370 SoC with device tree.
 
 
-	  Say 'Y' here if you want your kernel to support boards based on
-	  Marvell Armada 370 or Armada XP with device tree.
+config MACH_ARMADA_XP
+	bool "Marvell Armada XP boards"
+	select MACH_ARMADA_370_XP
+	select PINCTRL_ARMADA_XP
+	help
+	  Say 'Y' here if you want your kernel to support boards based
+	  on the Marvell Armada XP SoC with device tree.
 
 
 endmenu
 endmenu
 
 

+ 1 - 0
arch/arm/mach-mvebu/include/mach/gpio.h

@@ -0,0 +1 @@
+/* empty */

+ 6 - 0
drivers/gpio/Kconfig

@@ -150,6 +150,12 @@ config GPIO_MSM_V2
 	  Qualcomm MSM chips.  Most of the pins on the MSM can be
 	  Qualcomm MSM chips.  Most of the pins on the MSM can be
 	  selected for GPIO, and are controlled by this driver.
 	  selected for GPIO, and are controlled by this driver.
 
 
+config GPIO_MVEBU
+	def_bool y
+	depends on ARCH_MVEBU
+	select GPIO_GENERIC
+	select GENERIC_IRQ_CHIP
+
 config GPIO_MXC
 config GPIO_MXC
 	def_bool y
 	def_bool y
 	depends on ARCH_MXC
 	depends on ARCH_MXC

+ 1 - 0
drivers/gpio/Makefile

@@ -41,6 +41,7 @@ obj-$(CONFIG_GPIO_MPC8XXX)	+= gpio-mpc8xxx.o
 obj-$(CONFIG_GPIO_MSIC)		+= gpio-msic.o
 obj-$(CONFIG_GPIO_MSIC)		+= gpio-msic.o
 obj-$(CONFIG_GPIO_MSM_V1)	+= gpio-msm-v1.o
 obj-$(CONFIG_GPIO_MSM_V1)	+= gpio-msm-v1.o
 obj-$(CONFIG_GPIO_MSM_V2)	+= gpio-msm-v2.o
 obj-$(CONFIG_GPIO_MSM_V2)	+= gpio-msm-v2.o
+obj-$(CONFIG_GPIO_MVEBU)        += gpio-mvebu.o
 obj-$(CONFIG_GPIO_MXC)		+= gpio-mxc.o
 obj-$(CONFIG_GPIO_MXC)		+= gpio-mxc.o
 obj-$(CONFIG_GPIO_MXS)		+= gpio-mxs.o
 obj-$(CONFIG_GPIO_MXS)		+= gpio-mxs.o
 obj-$(CONFIG_ARCH_OMAP)		+= gpio-omap.o
 obj-$(CONFIG_ARCH_OMAP)		+= gpio-omap.o

+ 679 - 0
drivers/gpio/gpio-mvebu.c

@@ -0,0 +1,679 @@
+/*
+ * GPIO driver for Marvell SoCs
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ * Andrew Lunn <andrew@lunn.ch>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * This driver is a fairly straightforward GPIO driver for the
+ * complete family of Marvell EBU SoC platforms (Orion, Dove,
+ * Kirkwood, Discovery, Armada 370/XP). The only complexity of this
+ * driver is the different register layout that exists between the
+ * non-SMP platforms (Orion, Dove, Kirkwood, Armada 370) and the SMP
+ * platforms (MV78200 from the Discovery family and the Armada
+ * XP). Therefore, this driver handles three variants of the GPIO
+ * block:
+ * - the basic variant, called "orion-gpio", with the simplest
+ *   register set. Used on Orion, Dove, Kirkwoord, Armada 370 and
+ *   non-SMP Discovery systems
+ * - the mv78200 variant for MV78200 Discovery systems. This variant
+ *   turns the edge mask and level mask registers into CPU0 edge
+ *   mask/level mask registers, and adds CPU1 edge mask/level mask
+ *   registers.
+ * - the armadaxp variant for Armada XP systems. This variant keeps
+ *   the normal cause/edge mask/level mask registers when the global
+ *   interrupts are used, but adds per-CPU cause/edge mask/level mask
+ *   registers n a separate memory area for the per-CPU GPIO
+ *   interrupts.
+ */
+
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
+
+/*
+ * GPIO unit register offsets.
+ */
+#define GPIO_OUT_OFF		0x0000
+#define GPIO_IO_CONF_OFF	0x0004
+#define GPIO_BLINK_EN_OFF	0x0008
+#define GPIO_IN_POL_OFF		0x000c
+#define GPIO_DATA_IN_OFF	0x0010
+#define GPIO_EDGE_CAUSE_OFF	0x0014
+#define GPIO_EDGE_MASK_OFF	0x0018
+#define GPIO_LEVEL_MASK_OFF	0x001c
+
+/* The MV78200 has per-CPU registers for edge mask and level mask */
+#define GPIO_EDGE_MASK_MV78200_OFF(cpu)   ((cpu) ? 0x30 : 0x18)
+#define GPIO_LEVEL_MASK_MV78200_OFF(cpu)  ((cpu) ? 0x34 : 0x1C)
+
+/* The Armada XP has per-CPU registers for interrupt cause, interrupt
+ * mask and interrupt level mask. Those are relative to the
+ * percpu_membase. */
+#define GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu) ((cpu) * 0x4)
+#define GPIO_EDGE_MASK_ARMADAXP_OFF(cpu)  (0x10 + (cpu) * 0x4)
+#define GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu) (0x20 + (cpu) * 0x4)
+
+#define MVEBU_GPIO_SOC_VARIANT_ORION    0x1
+#define MVEBU_GPIO_SOC_VARIANT_MV78200  0x2
+#define MVEBU_GPIO_SOC_VARIANT_ARMADAXP 0x3
+
+#define MVEBU_MAX_GPIO_PER_BANK         32
+
+struct mvebu_gpio_chip {
+	struct gpio_chip   chip;
+	spinlock_t	   lock;
+	void __iomem	  *membase;
+	void __iomem	  *percpu_membase;
+	unsigned int       irqbase;
+	struct irq_domain *domain;
+	int                soc_variant;
+};
+
+/*
+ * Functions returning addresses of individual registers for a given
+ * GPIO controller.
+ */
+static inline void __iomem *mvebu_gpioreg_out(struct mvebu_gpio_chip *mvchip)
+{
+	return mvchip->membase + GPIO_OUT_OFF;
+}
+
+static inline void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip)
+{
+	return mvchip->membase + GPIO_IO_CONF_OFF;
+}
+
+static inline void __iomem *mvebu_gpioreg_in_pol(struct mvebu_gpio_chip *mvchip)
+{
+	return mvchip->membase + GPIO_IN_POL_OFF;
+}
+
+static inline void __iomem *mvebu_gpioreg_data_in(struct mvebu_gpio_chip *mvchip)
+{
+	return mvchip->membase + GPIO_DATA_IN_OFF;
+}
+
+static inline void __iomem *mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip)
+{
+	int cpu;
+
+	switch(mvchip->soc_variant) {
+	case MVEBU_GPIO_SOC_VARIANT_ORION:
+	case MVEBU_GPIO_SOC_VARIANT_MV78200:
+		return mvchip->membase + GPIO_EDGE_CAUSE_OFF;
+	case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
+		cpu = smp_processor_id();
+		return mvchip->percpu_membase + GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu);
+	default:
+		BUG();
+	}
+}
+
+static inline void __iomem *mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip)
+{
+	int cpu;
+
+	switch(mvchip->soc_variant) {
+	case MVEBU_GPIO_SOC_VARIANT_ORION:
+		return mvchip->membase + GPIO_EDGE_MASK_OFF;
+	case MVEBU_GPIO_SOC_VARIANT_MV78200:
+		cpu = smp_processor_id();
+		return mvchip->membase + GPIO_EDGE_MASK_MV78200_OFF(cpu);
+	case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
+		cpu = smp_processor_id();
+		return mvchip->percpu_membase + GPIO_EDGE_MASK_ARMADAXP_OFF(cpu);
+	default:
+		BUG();
+	}
+}
+
+static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip)
+{
+	int cpu;
+
+	switch(mvchip->soc_variant) {
+	case MVEBU_GPIO_SOC_VARIANT_ORION:
+		return mvchip->membase + GPIO_LEVEL_MASK_OFF;
+	case MVEBU_GPIO_SOC_VARIANT_MV78200:
+		cpu = smp_processor_id();
+		return mvchip->membase + GPIO_LEVEL_MASK_MV78200_OFF(cpu);
+	case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
+		cpu = smp_processor_id();
+		return mvchip->percpu_membase + GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu);
+	default:
+		BUG();
+	}
+}
+
+/*
+ * Functions implementing the gpio_chip methods
+ */
+
+int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin)
+{
+	return pinctrl_request_gpio(chip->base + pin);
+}
+
+void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin)
+{
+	pinctrl_free_gpio(chip->base + pin);
+}
+
+static void mvebu_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
+{
+	struct mvebu_gpio_chip *mvchip =
+		container_of(chip, struct mvebu_gpio_chip, chip);
+	unsigned long flags;
+	u32 u;
+
+	spin_lock_irqsave(&mvchip->lock, flags);
+	u = readl_relaxed(mvebu_gpioreg_out(mvchip));
+	if (value)
+		u |= 1 << pin;
+	else
+		u &= ~(1 << pin);
+	writel_relaxed(u, mvebu_gpioreg_out(mvchip));
+	spin_unlock_irqrestore(&mvchip->lock, flags);
+}
+
+static int mvebu_gpio_get(struct gpio_chip *chip, unsigned pin)
+{
+	struct mvebu_gpio_chip *mvchip =
+		container_of(chip, struct mvebu_gpio_chip, chip);
+	u32 u;
+
+	if (readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & (1 << pin)) {
+		u = readl_relaxed(mvebu_gpioreg_data_in(mvchip)) ^
+			readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
+	} else {
+		u = readl_relaxed(mvebu_gpioreg_out(mvchip));
+	}
+
+	return (u >> pin) & 1;
+}
+
+static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
+{
+	struct mvebu_gpio_chip *mvchip =
+		container_of(chip, struct mvebu_gpio_chip, chip);
+	unsigned long flags;
+	int ret;
+	u32 u;
+
+	/* Check with the pinctrl driver whether this pin is usable as
+	 * an input GPIO */
+	ret = pinctrl_gpio_direction_input(chip->base + pin);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&mvchip->lock, flags);
+	u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip));
+	u |= 1 << pin;
+	writel_relaxed(u, mvebu_gpioreg_io_conf(mvchip));
+	spin_unlock_irqrestore(&mvchip->lock, flags);
+
+	return 0;
+}
+
+static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin,
+				       int value)
+{
+	struct mvebu_gpio_chip *mvchip =
+		container_of(chip, struct mvebu_gpio_chip, chip);
+	unsigned long flags;
+	int ret;
+	u32 u;
+
+	/* Check with the pinctrl driver whether this pin is usable as
+	 * an output GPIO */
+	ret = pinctrl_gpio_direction_output(chip->base + pin);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&mvchip->lock, flags);
+	u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip));
+	u &= ~(1 << pin);
+	writel_relaxed(u, mvebu_gpioreg_io_conf(mvchip));
+	spin_unlock_irqrestore(&mvchip->lock, flags);
+
+	return 0;
+}
+
+static int mvebu_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
+{
+	struct mvebu_gpio_chip *mvchip =
+		container_of(chip, struct mvebu_gpio_chip, chip);
+	return irq_create_mapping(mvchip->domain, pin);
+}
+
+/*
+ * Functions implementing the irq_chip methods
+ */
+static void mvebu_gpio_irq_ack(struct irq_data *d)
+{
+	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+	struct mvebu_gpio_chip *mvchip = gc->private;
+	u32 mask = ~(1 << (d->irq - gc->irq_base));
+
+	irq_gc_lock(gc);
+	writel_relaxed(mask, mvebu_gpioreg_edge_cause(mvchip));
+	irq_gc_unlock(gc);
+}
+
+static void mvebu_gpio_edge_irq_mask(struct irq_data *d)
+{
+	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+	struct mvebu_gpio_chip *mvchip = gc->private;
+	u32 mask = 1 << (d->irq - gc->irq_base);
+
+	irq_gc_lock(gc);
+	gc->mask_cache &= ~mask;
+	writel_relaxed(gc->mask_cache, mvebu_gpioreg_edge_mask(mvchip));
+	irq_gc_unlock(gc);
+}
+
+static void mvebu_gpio_edge_irq_unmask(struct irq_data *d)
+{
+	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+	struct mvebu_gpio_chip *mvchip = gc->private;
+	u32 mask = 1 << (d->irq - gc->irq_base);
+
+	irq_gc_lock(gc);
+	gc->mask_cache |= mask;
+	writel_relaxed(gc->mask_cache, mvebu_gpioreg_edge_mask(mvchip));
+	irq_gc_unlock(gc);
+}
+
+static void mvebu_gpio_level_irq_mask(struct irq_data *d)
+{
+	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+	struct mvebu_gpio_chip *mvchip = gc->private;
+	u32 mask = 1 << (d->irq - gc->irq_base);
+
+	irq_gc_lock(gc);
+	gc->mask_cache &= ~mask;
+	writel_relaxed(gc->mask_cache, mvebu_gpioreg_level_mask(mvchip));
+	irq_gc_unlock(gc);
+}
+
+static void mvebu_gpio_level_irq_unmask(struct irq_data *d)
+{
+	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+	struct mvebu_gpio_chip *mvchip = gc->private;
+	u32 mask = 1 << (d->irq - gc->irq_base);
+
+	irq_gc_lock(gc);
+	gc->mask_cache |= mask;
+	writel_relaxed(gc->mask_cache, mvebu_gpioreg_level_mask(mvchip));
+	irq_gc_unlock(gc);
+}
+
+/*****************************************************************************
+ * MVEBU GPIO IRQ
+ *
+ * GPIO_IN_POL register controls whether GPIO_DATA_IN will hold the same
+ * value of the line or the opposite value.
+ *
+ * Level IRQ handlers: DATA_IN is used directly as cause register.
+ *                     Interrupt are masked by LEVEL_MASK registers.
+ * Edge IRQ handlers:  Change in DATA_IN are latched in EDGE_CAUSE.
+ *                     Interrupt are masked by EDGE_MASK registers.
+ * Both-edge handlers: Similar to regular Edge handlers, but also swaps
+ *                     the polarity to catch the next line transaction.
+ *                     This is a race condition that might not perfectly
+ *                     work on some use cases.
+ *
+ * Every eight GPIO lines are grouped (OR'ed) before going up to main
+ * cause register.
+ *
+ *                    EDGE  cause    mask
+ *        data-in   /--------| |-----| |----\
+ *     -----| |-----                         ---- to main cause reg
+ *           X      \----------------| |----/
+ *        polarity    LEVEL          mask
+ *
+ ****************************************************************************/
+
+static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+	struct irq_chip_type *ct = irq_data_get_chip_type(d);
+	struct mvebu_gpio_chip *mvchip = gc->private;
+	int pin;
+	u32 u;
+
+	pin = d->hwirq;
+
+	u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & (1 << pin);
+	if (!u) {
+		return -EINVAL;
+	}
+
+	type &= IRQ_TYPE_SENSE_MASK;
+	if (type == IRQ_TYPE_NONE)
+		return -EINVAL;
+
+	/* Check if we need to change chip and handler */
+	if (!(ct->type & type))
+		if (irq_setup_alt_chip(d, type))
+			return -EINVAL;
+
+	/*
+	 * Configure interrupt polarity.
+	 */
+	switch(type) {
+	case IRQ_TYPE_EDGE_RISING:
+	case IRQ_TYPE_LEVEL_HIGH:
+		u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
+		u &= ~(1 << pin);
+		writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip));
+	case IRQ_TYPE_EDGE_FALLING:
+	case IRQ_TYPE_LEVEL_LOW:
+		u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
+		u |= 1 << pin;
+		writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip));
+	case IRQ_TYPE_EDGE_BOTH: {
+		u32 v;
+
+		v = readl_relaxed(mvebu_gpioreg_in_pol(mvchip)) ^
+			readl_relaxed(mvebu_gpioreg_data_in(mvchip));
+
+		/*
+		 * set initial polarity based on current input level
+		 */
+		u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
+		if (v & (1 << pin))
+			u |= 1 << pin;		/* falling */
+		else
+			u &= ~(1 << pin);	/* rising */
+		writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip));
+	}
+	}
+	return 0;
+}
+
+static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct mvebu_gpio_chip *mvchip = irq_get_handler_data(irq);
+	u32 cause, type;
+	int i;
+
+	if (mvchip == NULL)
+		return;
+
+	cause = readl_relaxed(mvebu_gpioreg_data_in(mvchip)) &
+		readl_relaxed(mvebu_gpioreg_level_mask(mvchip));
+	cause |= readl_relaxed(mvebu_gpioreg_edge_cause(mvchip)) &
+		readl_relaxed(mvebu_gpioreg_edge_mask(mvchip));
+
+	for (i = 0; i < mvchip->chip.ngpio; i++) {
+		int irq;
+
+		irq = mvchip->irqbase + i;
+
+		if (!(cause & (1 << i)))
+			continue;
+
+		type = irqd_get_trigger_type(irq_get_irq_data(irq));
+		if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
+			/* Swap polarity (race with GPIO line) */
+			u32 polarity;
+
+			polarity = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
+			polarity ^= 1 << i;
+			writel_relaxed(polarity, mvebu_gpioreg_in_pol(mvchip));
+		}
+		generic_handle_irq(irq);
+	}
+}
+
+static struct platform_device_id mvebu_gpio_ids[] = {
+	{
+		.name = "orion-gpio",
+	}, {
+		.name = "mv78200-gpio",
+	}, {
+		.name = "armadaxp-gpio",
+	}, {
+		/* sentinel */
+	},
+};
+MODULE_DEVICE_TABLE(platform, mvebu_gpio_ids);
+
+static struct of_device_id mvebu_gpio_of_match[] __devinitdata = {
+	{
+		.compatible = "marvell,orion-gpio",
+		.data       = (void*) MVEBU_GPIO_SOC_VARIANT_ORION,
+	},
+	{
+		.compatible = "marvell,mv78200-gpio",
+		.data       = (void*) MVEBU_GPIO_SOC_VARIANT_MV78200,
+	},
+	{
+		.compatible = "marvell,armadaxp-gpio",
+		.data       = (void*) MVEBU_GPIO_SOC_VARIANT_ARMADAXP,
+	},
+	{
+		/* sentinel */
+	},
+};
+MODULE_DEVICE_TABLE(of, mvebu_gpio_of_match);
+
+static int __devinit mvebu_gpio_probe(struct platform_device *pdev)
+{
+	struct mvebu_gpio_chip *mvchip;
+	const struct of_device_id *match;
+	struct device_node *np = pdev->dev.of_node;
+	struct resource *res;
+	struct irq_chip_generic *gc;
+	struct irq_chip_type *ct;
+	unsigned int ngpios;
+	int soc_variant;
+	int i, cpu, id;
+
+	match = of_match_device(mvebu_gpio_of_match, &pdev->dev);
+	if (match)
+		soc_variant = (int) match->data;
+	else
+		soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (! res) {
+		dev_err(&pdev->dev, "Cannot get memory resource\n");
+		return -ENODEV;
+	}
+
+	mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), GFP_KERNEL);
+	if (! mvchip){
+		dev_err(&pdev->dev, "Cannot allocate memory\n");
+		return -ENOMEM;
+	}
+
+	if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) {
+		dev_err(&pdev->dev, "Missing ngpios OF property\n");
+		return -ENODEV;
+	}
+
+	id = of_alias_get_id(pdev->dev.of_node, "gpio");
+	if (id < 0) {
+		dev_err(&pdev->dev, "Couldn't get OF id\n");
+		return id;
+	}
+
+	mvchip->soc_variant = soc_variant;
+	mvchip->chip.label = dev_name(&pdev->dev);
+	mvchip->chip.dev = &pdev->dev;
+	mvchip->chip.request = mvebu_gpio_request;
+	mvchip->chip.direction_input = mvebu_gpio_direction_input;
+	mvchip->chip.get = mvebu_gpio_get;
+	mvchip->chip.direction_output = mvebu_gpio_direction_output;
+	mvchip->chip.set = mvebu_gpio_set;
+	mvchip->chip.to_irq = mvebu_gpio_to_irq;
+	mvchip->chip.base = id * MVEBU_MAX_GPIO_PER_BANK;
+	mvchip->chip.ngpio = ngpios;
+	mvchip->chip.can_sleep = 0;
+#ifdef CONFIG_OF
+	mvchip->chip.of_node = np;
+#endif
+
+	spin_lock_init(&mvchip->lock);
+	mvchip->membase = devm_request_and_ioremap(&pdev->dev, res);
+	if (! mvchip->membase) {
+		dev_err(&pdev->dev, "Cannot ioremap\n");
+		kfree(mvchip->chip.label);
+		return -ENOMEM;
+	}
+
+	/* The Armada XP has a second range of registers for the
+	 * per-CPU registers */
+	if (soc_variant == MVEBU_GPIO_SOC_VARIANT_ARMADAXP) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		if (! res) {
+			dev_err(&pdev->dev, "Cannot get memory resource\n");
+			kfree(mvchip->chip.label);
+			return -ENODEV;
+		}
+
+		mvchip->percpu_membase = devm_request_and_ioremap(&pdev->dev, res);
+		if (! mvchip->percpu_membase) {
+			dev_err(&pdev->dev, "Cannot ioremap\n");
+			kfree(mvchip->chip.label);
+			return -ENOMEM;
+		}
+	}
+
+	/*
+	 * Mask and clear GPIO interrupts.
+	 */
+	switch(soc_variant) {
+	case MVEBU_GPIO_SOC_VARIANT_ORION:
+		writel_relaxed(0, mvchip->membase + GPIO_EDGE_CAUSE_OFF);
+		writel_relaxed(0, mvchip->membase + GPIO_EDGE_MASK_OFF);
+		writel_relaxed(0, mvchip->membase + GPIO_LEVEL_MASK_OFF);
+		break;
+	case MVEBU_GPIO_SOC_VARIANT_MV78200:
+		writel_relaxed(0, mvchip->membase + GPIO_EDGE_CAUSE_OFF);
+		for (cpu = 0; cpu < 2; cpu++) {
+			writel_relaxed(0, mvchip->membase +
+				       GPIO_EDGE_MASK_MV78200_OFF(cpu));
+			writel_relaxed(0, mvchip->membase +
+				       GPIO_LEVEL_MASK_MV78200_OFF(cpu));
+		}
+		break;
+	case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
+		writel_relaxed(0, mvchip->membase + GPIO_EDGE_CAUSE_OFF);
+		writel_relaxed(0, mvchip->membase + GPIO_EDGE_MASK_OFF);
+		writel_relaxed(0, mvchip->membase + GPIO_LEVEL_MASK_OFF);
+		for (cpu = 0; cpu < 4; cpu++) {
+			writel_relaxed(0, mvchip->percpu_membase +
+				       GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu));
+			writel_relaxed(0, mvchip->percpu_membase +
+				       GPIO_EDGE_MASK_ARMADAXP_OFF(cpu));
+			writel_relaxed(0, mvchip->percpu_membase +
+				       GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu));
+		}
+		break;
+	default:
+		BUG();
+	}
+
+	gpiochip_add(&mvchip->chip);
+
+	/* Some gpio controllers do not provide irq support */
+	if (!of_irq_count(np))
+		return 0;
+
+	/* Setup the interrupt handlers. Each chip can have up to 4
+	 * interrupt handlers, with each handler dealing with 8 GPIO
+	 * pins. */
+	for (i = 0; i < 4; i++) {
+		int irq;
+		irq = platform_get_irq(pdev, i);
+		if (irq < 0)
+			continue;
+		irq_set_handler_data(irq, mvchip);
+		irq_set_chained_handler(irq, mvebu_gpio_irq_handler);
+	}
+
+	mvchip->irqbase = irq_alloc_descs(-1, 0, ngpios, -1);
+	if (mvchip->irqbase < 0) {
+		dev_err(&pdev->dev, "no irqs\n");
+		kfree(mvchip->chip.label);
+		return -ENOMEM;
+	}
+
+	gc = irq_alloc_generic_chip("mvebu_gpio_irq", 2, mvchip->irqbase,
+				    mvchip->membase, handle_level_irq);
+	if (! gc) {
+		dev_err(&pdev->dev, "Cannot allocate generic irq_chip\n");
+		kfree(mvchip->chip.label);
+		return -ENOMEM;
+	}
+
+	gc->private = mvchip;
+	ct = &gc->chip_types[0];
+	ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
+	ct->chip.irq_mask = mvebu_gpio_level_irq_mask;
+	ct->chip.irq_unmask = mvebu_gpio_level_irq_unmask;
+	ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
+	ct->chip.name = mvchip->chip.label;
+
+	ct = &gc->chip_types[1];
+	ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+	ct->chip.irq_ack = mvebu_gpio_irq_ack;
+	ct->chip.irq_mask = mvebu_gpio_edge_irq_mask;
+	ct->chip.irq_unmask = mvebu_gpio_edge_irq_unmask;
+	ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
+	ct->handler = handle_edge_irq;
+	ct->chip.name = mvchip->chip.label;
+
+	irq_setup_generic_chip(gc, IRQ_MSK(ngpios), IRQ_GC_INIT_MASK_CACHE,
+			       IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
+
+	/* Setup irq domain on top of the generic chip. */
+	mvchip->domain = irq_domain_add_legacy(np, mvchip->chip.ngpio,
+					       mvchip->irqbase, 0,
+					       &irq_domain_simple_ops,
+					       mvchip);
+	if (!mvchip->domain) {
+		dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n",
+			mvchip->chip.label);
+		irq_remove_generic_chip(gc, IRQ_MSK(ngpios), IRQ_NOREQUEST,
+					IRQ_LEVEL | IRQ_NOPROBE);
+		kfree(gc);
+		kfree(mvchip->chip.label);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static struct platform_driver mvebu_gpio_driver = {
+	.driver		= {
+		.name	        = "mvebu-gpio",
+		.owner	        = THIS_MODULE,
+		.of_match_table = mvebu_gpio_of_match,
+	},
+	.probe		= mvebu_gpio_probe,
+	.id_table	= mvebu_gpio_ids,
+};
+
+static int __init mvebu_gpio_init(void)
+{
+	return platform_driver_register(&mvebu_gpio_driver);
+}
+postcore_initcall(mvebu_gpio_init);

+ 22 - 0
drivers/pinctrl/Kconfig

@@ -145,6 +145,28 @@ config PINCTRL_COH901
 	  COH 901 335 and COH 901 571/3. They contain 3, 5 or 7
 	  COH 901 335 and COH 901 571/3. They contain 3, 5 or 7
 	  ports of 8 GPIO pins each.
 	  ports of 8 GPIO pins each.
 
 
+config PINCTRL_MVEBU
+	bool
+	depends on ARCH_MVEBU
+	select PINMUX
+	select PINCONF
+
+config PINCTRL_DOVE
+	bool
+	select PINCTRL_MVEBU
+
+config PINCTRL_KIRKWOOD
+	bool
+	select PINCTRL_MVEBU
+
+config PINCTRL_ARMADA_370
+	bool
+	select PINCTRL_MVEBU
+
+config PINCTRL_ARMADA_XP
+	bool
+	select PINCTRL_MVEBU
+
 source "drivers/pinctrl/spear/Kconfig"
 source "drivers/pinctrl/spear/Kconfig"
 
 
 endmenu
 endmenu

+ 5 - 0
drivers/pinctrl/Makefile

@@ -29,5 +29,10 @@ obj-$(CONFIG_PINCTRL_TEGRA20)	+= pinctrl-tegra20.o
 obj-$(CONFIG_PINCTRL_TEGRA30)	+= pinctrl-tegra30.o
 obj-$(CONFIG_PINCTRL_TEGRA30)	+= pinctrl-tegra30.o
 obj-$(CONFIG_PINCTRL_U300)	+= pinctrl-u300.o
 obj-$(CONFIG_PINCTRL_U300)	+= pinctrl-u300.o
 obj-$(CONFIG_PINCTRL_COH901)	+= pinctrl-coh901.o
 obj-$(CONFIG_PINCTRL_COH901)	+= pinctrl-coh901.o
+obj-$(CONFIG_PINCTRL_MVEBU)	+= pinctrl-mvebu.o
+obj-$(CONFIG_PINCTRL_DOVE)	+= pinctrl-dove.o
+obj-$(CONFIG_PINCTRL_KIRKWOOD)	+= pinctrl-kirkwood.o
+obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o
+obj-$(CONFIG_PINCTRL_ARMADA_XP)  += pinctrl-armada-xp.o
 
 
 obj-$(CONFIG_PLAT_SPEAR)	+= spear/
 obj-$(CONFIG_PLAT_SPEAR)	+= spear/

+ 421 - 0
drivers/pinctrl/pinctrl-armada-370.c

@@ -0,0 +1,421 @@
+/*
+ * Marvell Armada 370 pinctrl driver based on mvebu pinctrl core
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-mvebu.h"
+
+static struct mvebu_mpp_mode mv88f6710_mpp_modes[] = {
+	MPP_MODE(0,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "uart0", "rxd")),
+	MPP_MODE(1,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "uart0", "txd")),
+	MPP_MODE(2,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "i2c0", "sck"),
+	   MPP_FUNCTION(0x2, "uart0", "txd")),
+	MPP_MODE(3,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "i2c0", "sda"),
+	   MPP_FUNCTION(0x2, "uart0", "rxd")),
+	MPP_MODE(4,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "cpu_pd", "vdd")),
+	MPP_MODE(5,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "txclko"),
+	   MPP_FUNCTION(0x2, "uart1", "txd"),
+	   MPP_FUNCTION(0x4, "spi1", "clk"),
+	   MPP_FUNCTION(0x5, "audio", "mclk")),
+	MPP_MODE(6,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "txd0"),
+	   MPP_FUNCTION(0x2, "sata0", "prsnt"),
+	   MPP_FUNCTION(0x4, "tdm", "rst"),
+	   MPP_FUNCTION(0x5, "audio", "sdo")),
+	MPP_MODE(7,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "txd1"),
+	   MPP_FUNCTION(0x4, "tdm", "tdx"),
+	   MPP_FUNCTION(0x5, "audio", "lrclk")),
+	MPP_MODE(8,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "txd2"),
+	   MPP_FUNCTION(0x2, "uart0", "rts"),
+	   MPP_FUNCTION(0x4, "tdm", "drx"),
+	   MPP_FUNCTION(0x5, "audio", "bclk")),
+	MPP_MODE(9,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "txd3"),
+	   MPP_FUNCTION(0x2, "uart1", "txd"),
+	   MPP_FUNCTION(0x3, "sd0", "clk"),
+	   MPP_FUNCTION(0x5, "audio", "spdifo")),
+	MPP_MODE(10,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "txctl"),
+	   MPP_FUNCTION(0x2, "uart0", "cts"),
+	   MPP_FUNCTION(0x4, "tdm", "fsync"),
+	   MPP_FUNCTION(0x5, "audio", "sdi")),
+	MPP_MODE(11,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "rxd0"),
+	   MPP_FUNCTION(0x2, "uart1", "rxd"),
+	   MPP_FUNCTION(0x3, "sd0", "cmd"),
+	   MPP_FUNCTION(0x4, "spi0", "cs1"),
+	   MPP_FUNCTION(0x5, "sata1", "prsnt"),
+	   MPP_FUNCTION(0x6, "spi1", "cs1")),
+	MPP_MODE(12,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "rxd1"),
+	   MPP_FUNCTION(0x2, "i2c1", "sda"),
+	   MPP_FUNCTION(0x3, "sd0", "d0"),
+	   MPP_FUNCTION(0x4, "spi1", "cs0"),
+	   MPP_FUNCTION(0x5, "audio", "spdifi")),
+	MPP_MODE(13,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "rxd2"),
+	   MPP_FUNCTION(0x2, "i2c1", "sck"),
+	   MPP_FUNCTION(0x3, "sd0", "d1"),
+	   MPP_FUNCTION(0x4, "tdm", "pclk"),
+	   MPP_FUNCTION(0x5, "audio", "rmclk")),
+	MPP_MODE(14,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "rxd3"),
+	   MPP_FUNCTION(0x2, "pcie", "clkreq0"),
+	   MPP_FUNCTION(0x3, "sd0", "d2"),
+	   MPP_FUNCTION(0x4, "spi1", "mosi"),
+	   MPP_FUNCTION(0x5, "spi0", "cs2")),
+	MPP_MODE(15,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "rxctl"),
+	   MPP_FUNCTION(0x2, "pcie", "clkreq1"),
+	   MPP_FUNCTION(0x3, "sd0", "d3"),
+	   MPP_FUNCTION(0x4, "spi1", "miso"),
+	   MPP_FUNCTION(0x5, "spi0", "cs3")),
+	MPP_MODE(16,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "rxclk"),
+	   MPP_FUNCTION(0x2, "uart1", "rxd"),
+	   MPP_FUNCTION(0x4, "tdm", "int"),
+	   MPP_FUNCTION(0x5, "audio", "extclk")),
+	MPP_MODE(17,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "ge", "mdc")),
+	MPP_MODE(18,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge", "mdio")),
+	MPP_MODE(19,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "txclk"),
+	   MPP_FUNCTION(0x2, "ge1", "txclkout"),
+	   MPP_FUNCTION(0x4, "tdm", "pclk")),
+	MPP_MODE(20,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "txd4"),
+	   MPP_FUNCTION(0x2, "ge1", "txd0")),
+	MPP_MODE(21,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "txd5"),
+	   MPP_FUNCTION(0x2, "ge1", "txd1"),
+	   MPP_FUNCTION(0x4, "uart1", "txd")),
+	MPP_MODE(22,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "txd6"),
+	   MPP_FUNCTION(0x2, "ge1", "txd2"),
+	   MPP_FUNCTION(0x4, "uart0", "rts")),
+	MPP_MODE(23,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "txd7"),
+	   MPP_FUNCTION(0x2, "ge1", "txd3"),
+	   MPP_FUNCTION(0x4, "spi1", "mosi")),
+	MPP_MODE(24,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "col"),
+	   MPP_FUNCTION(0x2, "ge1", "txctl"),
+	   MPP_FUNCTION(0x4, "spi1", "cs0")),
+	MPP_MODE(25,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "rxerr"),
+	   MPP_FUNCTION(0x2, "ge1", "rxd0"),
+	   MPP_FUNCTION(0x4, "uart1", "rxd")),
+	MPP_MODE(26,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "crs"),
+	   MPP_FUNCTION(0x2, "ge1", "rxd1"),
+	   MPP_FUNCTION(0x4, "spi1", "miso")),
+	MPP_MODE(27,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "rxd4"),
+	   MPP_FUNCTION(0x2, "ge1", "rxd2"),
+	   MPP_FUNCTION(0x4, "uart0", "cts")),
+	MPP_MODE(28,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "rxd5"),
+	   MPP_FUNCTION(0x2, "ge1", "rxd3")),
+	MPP_MODE(29,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "rxd6"),
+	   MPP_FUNCTION(0x2, "ge1", "rxctl"),
+	   MPP_FUNCTION(0x4, "i2c1", "sda")),
+	MPP_MODE(30,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "ge0", "rxd7"),
+	   MPP_FUNCTION(0x2, "ge1", "rxclk"),
+	   MPP_FUNCTION(0x4, "i2c1", "sck")),
+	MPP_MODE(31,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x3, "tclk", NULL),
+	   MPP_FUNCTION(0x4, "ge0", "txerr")),
+	MPP_MODE(32,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "spi0", "cs0")),
+	MPP_MODE(33,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "dev", "bootcs"),
+	   MPP_FUNCTION(0x2, "spi0", "cs0")),
+	MPP_MODE(34,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "dev", "wen0"),
+	   MPP_FUNCTION(0x2, "spi0", "mosi")),
+	MPP_MODE(35,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "dev", "oen"),
+	   MPP_FUNCTION(0x2, "spi0", "sck")),
+	MPP_MODE(36,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "dev", "a1"),
+	   MPP_FUNCTION(0x2, "spi0", "miso")),
+	MPP_MODE(37,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "dev", "a0"),
+	   MPP_FUNCTION(0x2, "sata0", "prsnt")),
+	MPP_MODE(38,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ready"),
+	   MPP_FUNCTION(0x2, "uart1", "cts"),
+	   MPP_FUNCTION(0x3, "uart0", "cts")),
+	MPP_MODE(39,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ad0"),
+	   MPP_FUNCTION(0x2, "audio", "spdifo")),
+	MPP_MODE(40,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ad1"),
+	   MPP_FUNCTION(0x2, "uart1", "rts"),
+	   MPP_FUNCTION(0x3, "uart0", "rts")),
+	MPP_MODE(41,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ad2"),
+	   MPP_FUNCTION(0x2, "uart1", "rxd")),
+	MPP_MODE(42,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ad3"),
+	   MPP_FUNCTION(0x2, "uart1", "txd")),
+	MPP_MODE(43,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ad4"),
+	   MPP_FUNCTION(0x2, "audio", "bclk")),
+	MPP_MODE(44,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ad5"),
+	   MPP_FUNCTION(0x2, "audio", "mclk")),
+	MPP_MODE(45,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ad6"),
+	   MPP_FUNCTION(0x2, "audio", "lrclk")),
+	MPP_MODE(46,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ad7"),
+	   MPP_FUNCTION(0x2, "audio", "sdo")),
+	MPP_MODE(47,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ad8"),
+	   MPP_FUNCTION(0x3, "sd0", "clk"),
+	   MPP_FUNCTION(0x5, "audio", "spdifo")),
+	MPP_MODE(48,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ad9"),
+	   MPP_FUNCTION(0x2, "uart0", "rts"),
+	   MPP_FUNCTION(0x3, "sd0", "cmd"),
+	   MPP_FUNCTION(0x4, "sata1", "prsnt"),
+	   MPP_FUNCTION(0x5, "spi0", "cs1")),
+	MPP_MODE(49,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ad10"),
+	   MPP_FUNCTION(0x2, "pcie", "clkreq1"),
+	   MPP_FUNCTION(0x3, "sd0", "d0"),
+	   MPP_FUNCTION(0x4, "spi1", "cs0"),
+	   MPP_FUNCTION(0x5, "audio", "spdifi")),
+	MPP_MODE(50,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ad11"),
+	   MPP_FUNCTION(0x2, "uart0", "cts"),
+	   MPP_FUNCTION(0x3, "sd0", "d1"),
+	   MPP_FUNCTION(0x4, "spi1", "miso"),
+	   MPP_FUNCTION(0x5, "audio", "rmclk")),
+	MPP_MODE(51,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ad12"),
+	   MPP_FUNCTION(0x2, "i2c1", "sda"),
+	   MPP_FUNCTION(0x3, "sd0", "d2"),
+	   MPP_FUNCTION(0x4, "spi1", "mosi")),
+	MPP_MODE(52,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ad13"),
+	   MPP_FUNCTION(0x2, "i2c1", "sck"),
+	   MPP_FUNCTION(0x3, "sd0", "d3"),
+	   MPP_FUNCTION(0x4, "spi1", "sck")),
+	MPP_MODE(53,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ad14"),
+	   MPP_FUNCTION(0x2, "sd0", "clk"),
+	   MPP_FUNCTION(0x3, "tdm", "pclk"),
+	   MPP_FUNCTION(0x4, "spi0", "cs2"),
+	   MPP_FUNCTION(0x5, "pcie", "clkreq1")),
+	MPP_MODE(54,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ad15"),
+	   MPP_FUNCTION(0x3, "tdm", "dtx")),
+	MPP_MODE(55,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "dev", "cs1"),
+	   MPP_FUNCTION(0x2, "uart1", "txd"),
+	   MPP_FUNCTION(0x3, "tdm", "rst"),
+	   MPP_FUNCTION(0x4, "sata1", "prsnt"),
+	   MPP_FUNCTION(0x5, "sata0", "prsnt")),
+	MPP_MODE(56,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "dev", "cs2"),
+	   MPP_FUNCTION(0x2, "uart1", "cts"),
+	   MPP_FUNCTION(0x3, "uart0", "cts"),
+	   MPP_FUNCTION(0x4, "spi0", "cs3"),
+	   MPP_FUNCTION(0x5, "pcie", "clkreq0"),
+	   MPP_FUNCTION(0x6, "spi1", "cs1")),
+	MPP_MODE(57,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "dev", "cs3"),
+	   MPP_FUNCTION(0x2, "uart1", "rxd"),
+	   MPP_FUNCTION(0x3, "tdm", "fsync"),
+	   MPP_FUNCTION(0x4, "sata0", "prsnt"),
+	   MPP_FUNCTION(0x5, "audio", "sdo")),
+	MPP_MODE(58,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "dev", "cs0"),
+	   MPP_FUNCTION(0x2, "uart1", "rts"),
+	   MPP_FUNCTION(0x3, "tdm", "int"),
+	   MPP_FUNCTION(0x5, "audio", "extclk"),
+	   MPP_FUNCTION(0x6, "uart0", "rts")),
+	MPP_MODE(59,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ale0"),
+	   MPP_FUNCTION(0x2, "uart1", "rts"),
+	   MPP_FUNCTION(0x3, "uart0", "rts"),
+	   MPP_FUNCTION(0x5, "audio", "bclk")),
+	MPP_MODE(60,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "dev", "ale1"),
+	   MPP_FUNCTION(0x2, "uart1", "rxd"),
+	   MPP_FUNCTION(0x3, "sata0", "prsnt"),
+	   MPP_FUNCTION(0x4, "pcie", "rst-out"),
+	   MPP_FUNCTION(0x5, "audio", "sdi")),
+	MPP_MODE(61,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "dev", "wen1"),
+	   MPP_FUNCTION(0x2, "uart1", "txd"),
+	   MPP_FUNCTION(0x5, "audio", "rclk")),
+	MPP_MODE(62,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "dev", "a2"),
+	   MPP_FUNCTION(0x2, "uart1", "cts"),
+	   MPP_FUNCTION(0x3, "tdm", "drx"),
+	   MPP_FUNCTION(0x4, "pcie", "clkreq0"),
+	   MPP_FUNCTION(0x5, "audio", "mclk"),
+	   MPP_FUNCTION(0x6, "uart0", "cts")),
+	MPP_MODE(63,
+	   MPP_FUNCTION(0x0, "gpo", NULL),
+	   MPP_FUNCTION(0x1, "spi0", "sck"),
+	   MPP_FUNCTION(0x2, "tclk", NULL)),
+	MPP_MODE(64,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "spi0", "miso"),
+	   MPP_FUNCTION(0x2, "spi0-1", "cs1")),
+	MPP_MODE(65,
+	   MPP_FUNCTION(0x0, "gpio", NULL),
+	   MPP_FUNCTION(0x1, "spi0", "mosi"),
+	   MPP_FUNCTION(0x2, "spi0-1", "cs2")),
+};
+
+static struct mvebu_pinctrl_soc_info armada_370_pinctrl_info;
+
+static struct of_device_id armada_370_pinctrl_of_match[] __devinitdata = {
+	{ .compatible = "marvell,mv88f6710-pinctrl" },
+	{ },
+};
+
+static struct mvebu_mpp_ctrl mv88f6710_mpp_controls[] = {
+	MPP_REG_CTRL(0, 65),
+};
+
+static struct pinctrl_gpio_range mv88f6710_mpp_gpio_ranges[] = {
+	MPP_GPIO_RANGE(0,   0,  0, 32),
+	MPP_GPIO_RANGE(1,  32, 32, 32),
+	MPP_GPIO_RANGE(2,  64, 64,  2),
+};
+
+static int __devinit armada_370_pinctrl_probe(struct platform_device *pdev)
+{
+	struct mvebu_pinctrl_soc_info *soc = &armada_370_pinctrl_info;
+
+	soc->variant = 0; /* no variants for Armada 370 */
+	soc->controls = mv88f6710_mpp_controls;
+	soc->ncontrols = ARRAY_SIZE(mv88f6710_mpp_controls);
+	soc->modes = mv88f6710_mpp_modes;
+	soc->nmodes = ARRAY_SIZE(mv88f6710_mpp_modes);
+	soc->gpioranges = mv88f6710_mpp_gpio_ranges;
+	soc->ngpioranges = ARRAY_SIZE(mv88f6710_mpp_gpio_ranges);
+
+	pdev->dev.platform_data = soc;
+
+	return mvebu_pinctrl_probe(pdev);
+}
+
+static int __devexit armada_370_pinctrl_remove(struct platform_device *pdev)
+{
+	return mvebu_pinctrl_remove(pdev);
+}
+
+static struct platform_driver armada_370_pinctrl_driver = {
+	.driver = {
+		.name = "armada-370-pinctrl",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(armada_370_pinctrl_of_match),
+	},
+	.probe = armada_370_pinctrl_probe,
+	.remove = __devexit_p(armada_370_pinctrl_remove),
+};
+
+module_platform_driver(armada_370_pinctrl_driver);
+
+MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
+MODULE_DESCRIPTION("Marvell Armada 370 pinctrl driver");
+MODULE_LICENSE("GPL v2");

+ 468 - 0
drivers/pinctrl/pinctrl-armada-xp.c

@@ -0,0 +1,468 @@
+/*
+ * Marvell Armada XP pinctrl driver based on mvebu pinctrl core
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This file supports the three variants of Armada XP SoCs that are
+ * available: mv78230, mv78260 and mv78460. From a pin muxing
+ * perspective, the mv78230 has 49 MPP pins. The mv78260 and mv78460
+ * both have 67 MPP pins (more GPIOs and address lines for the memory
+ * bus mainly). The only difference between the mv78260 and the
+ * mv78460 in terms of pin muxing is the addition of two functions on
+ * pins 43 and 56 to access the VDD of the CPU2 and 3 (mv78260 has two
+ * cores, mv78460 has four cores).
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/bitops.h>
+
+#include "pinctrl-mvebu.h"
+
+enum armada_xp_variant {
+	V_MV78230	= BIT(0),
+	V_MV78260	= BIT(1),
+	V_MV78460	= BIT(2),
+	V_MV78230_PLUS	= (V_MV78230 | V_MV78260 | V_MV78460),
+	V_MV78260_PLUS	= (V_MV78260 | V_MV78460),
+};
+
+static struct mvebu_mpp_mode armada_xp_mpp_modes[] = {
+	MPP_MODE(0,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "txclko",     V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d0",         V_MV78230_PLUS)),
+	MPP_MODE(1,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "txd0",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d1",         V_MV78230_PLUS)),
+	MPP_MODE(2,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "txd1",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d2",         V_MV78230_PLUS)),
+	MPP_MODE(3,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "txd2",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d3",         V_MV78230_PLUS)),
+	MPP_MODE(4,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "txd3",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d4",         V_MV78230_PLUS)),
+	MPP_MODE(5,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "txctl",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d5",         V_MV78230_PLUS)),
+	MPP_MODE(6,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "rxd0",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d6",         V_MV78230_PLUS)),
+	MPP_MODE(7,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "rxd1",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d7",         V_MV78230_PLUS)),
+	MPP_MODE(8,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "rxd2",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d8",         V_MV78230_PLUS)),
+	MPP_MODE(9,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "rxd3",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d9",         V_MV78230_PLUS)),
+	MPP_MODE(10,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "rxctl",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d10",        V_MV78230_PLUS)),
+	MPP_MODE(11,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "rxclk",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d11",        V_MV78230_PLUS)),
+	MPP_MODE(12,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "txd4",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "ge1", "clkout",     V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d12",        V_MV78230_PLUS)),
+	MPP_MODE(13,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "txd5",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "ge1", "txd0",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d13",        V_MV78230_PLUS)),
+	MPP_MODE(14,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "txd6",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "ge1", "txd1",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d14",        V_MV78230_PLUS)),
+	MPP_MODE(15,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "txd7",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "ge1", "txd2",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d15",        V_MV78230_PLUS)),
+	MPP_MODE(16,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "txclk",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "ge1", "txd3",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d16",        V_MV78230_PLUS)),
+	MPP_MODE(17,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "col",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "ge1", "txctl",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d17",        V_MV78230_PLUS)),
+	MPP_MODE(18,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "rxerr",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "ge1", "rxd0",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "ptp", "trig",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d18",        V_MV78230_PLUS)),
+	MPP_MODE(19,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "crs",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "ge1", "rxd1",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "ptp", "evreq",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d19",        V_MV78230_PLUS)),
+	MPP_MODE(20,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "rxd4",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "ge1", "rxd2",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "ptp", "clk",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d20",        V_MV78230_PLUS)),
+	MPP_MODE(21,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "rxd5",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "ge1", "rxd3",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "mem", "bat",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d21",        V_MV78230_PLUS)),
+	MPP_MODE(22,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "rxd6",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "ge1", "rxctl",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "sata0", "prsnt",    V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d22",        V_MV78230_PLUS)),
+	MPP_MODE(23,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ge0", "rxd7",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "ge1", "rxclk",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "sata1", "prsnt",    V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "d23",        V_MV78230_PLUS)),
+	MPP_MODE(24,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "sata1", "prsnt",    V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "nf", "bootcs-re",   V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "tdm", "rst",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "hsync",      V_MV78230_PLUS)),
+	MPP_MODE(25,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "sata0", "prsnt",    V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "nf", "bootcs-we",   V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "tdm", "pclk",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "vsync",      V_MV78230_PLUS)),
+	MPP_MODE(26,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "tdm", "fsync",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "clk",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x5, "vdd", "cpu1-pd",    V_MV78230_PLUS)),
+	MPP_MODE(27,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ptp", "trig",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "tdm", "dtx",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "e",          V_MV78230_PLUS)),
+	MPP_MODE(28,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ptp", "evreq",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "tdm", "drx",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "pwm",        V_MV78230_PLUS)),
+	MPP_MODE(29,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "ptp", "clk",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "tdm", "int0",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "ref-clk",    V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x5, "vdd", "cpu0-pd",    V_MV78230_PLUS)),
+	MPP_MODE(30,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "sd0", "clk",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "tdm", "int1",       V_MV78230_PLUS)),
+	MPP_MODE(31,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "sd0", "cmd",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "tdm", "int2",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x5, "vdd", "cpu0-pd",    V_MV78230_PLUS)),
+	MPP_MODE(32,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "sd0", "d0",         V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "tdm", "int3",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x5, "vdd", "cpu1-pd",    V_MV78230_PLUS)),
+	MPP_MODE(33,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "sd0", "d1",         V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "tdm", "int4",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "mem", "bat",        V_MV78230_PLUS)),
+	MPP_MODE(34,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "sd0", "d2",         V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "sata0", "prsnt",    V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "tdm", "int5",       V_MV78230_PLUS)),
+	MPP_MODE(35,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "sd0", "d3",         V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "sata1", "prsnt",    V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "tdm", "int6",       V_MV78230_PLUS)),
+	MPP_MODE(36,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "spi", "mosi",       V_MV78230_PLUS)),
+	MPP_MODE(37,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "spi", "miso",       V_MV78230_PLUS)),
+	MPP_MODE(38,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "spi", "sck",        V_MV78230_PLUS)),
+	MPP_MODE(39,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "spi", "cs0",        V_MV78230_PLUS)),
+	MPP_MODE(40,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "spi", "cs1",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "uart2", "cts",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "vdd", "cpu1-pd",    V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "vga-hsync",  V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x5, "pcie", "clkreq0",   V_MV78230_PLUS)),
+	MPP_MODE(41,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "spi", "cs2",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "uart2", "rts",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "sata1", "prsnt",    V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "lcd", "vga-vsync",  V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x5, "pcie", "clkreq1",   V_MV78230_PLUS)),
+	MPP_MODE(42,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "uart2", "rxd",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "uart0", "cts",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "tdm", "int7",       V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "tdm-1", "timer",    V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x5, "vdd", "cpu0-pd",    V_MV78230_PLUS)),
+	MPP_MODE(43,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "uart2", "txd",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "uart0", "rts",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "spi", "cs3",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "pcie", "rstout",    V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x5, "vdd", "cpu2-3-pd",  V_MV78460)),
+	MPP_MODE(44,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "uart2", "cts",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "uart3", "rxd",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "spi", "cs4",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "mem", "bat",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x5, "pcie", "clkreq2",   V_MV78230_PLUS)),
+	MPP_MODE(45,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "uart2", "rts",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "uart3", "txd",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "spi", "cs5",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "sata1", "prsnt",    V_MV78230_PLUS)),
+	MPP_MODE(46,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "uart3", "rts",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "uart1", "rts",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "spi", "cs6",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "sata0", "prsnt",    V_MV78230_PLUS)),
+	MPP_MODE(47,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "uart3", "cts",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "uart1", "cts",      V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x3, "spi", "cs7",        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x4, "ref", "clkout",     V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x5, "pcie", "clkreq3",   V_MV78230_PLUS)),
+	MPP_MODE(48,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "tclk", NULL,        V_MV78230_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "dev", "burst/last", V_MV78230_PLUS)),
+	MPP_MODE(49,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "we3",        V_MV78260_PLUS)),
+	MPP_MODE(50,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "we2",        V_MV78260_PLUS)),
+	MPP_MODE(51,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad16",       V_MV78260_PLUS)),
+	MPP_MODE(52,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad17",       V_MV78260_PLUS)),
+	MPP_MODE(53,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad18",       V_MV78260_PLUS)),
+	MPP_MODE(54,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad19",       V_MV78260_PLUS)),
+	MPP_MODE(55,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad20",       V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "vdd", "cpu0-pd",    V_MV78260_PLUS)),
+	MPP_MODE(56,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad21",       V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "vdd", "cpu1-pd",    V_MV78260_PLUS)),
+	MPP_MODE(57,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad22",       V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x2, "vdd", "cpu2-3-pd",  V_MV78460)),
+	MPP_MODE(58,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad23",       V_MV78260_PLUS)),
+	MPP_MODE(59,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad24",       V_MV78260_PLUS)),
+	MPP_MODE(60,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad25",       V_MV78260_PLUS)),
+	MPP_MODE(61,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad26",       V_MV78260_PLUS)),
+	MPP_MODE(62,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad27",       V_MV78260_PLUS)),
+	MPP_MODE(63,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad28",       V_MV78260_PLUS)),
+	MPP_MODE(64,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad29",       V_MV78260_PLUS)),
+	MPP_MODE(65,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad30",       V_MV78260_PLUS)),
+	MPP_MODE(66,
+		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_MV78260_PLUS),
+		 MPP_VAR_FUNCTION(0x1, "dev", "ad31",       V_MV78260_PLUS)),
+};
+
+static struct mvebu_pinctrl_soc_info armada_xp_pinctrl_info;
+
+static struct of_device_id armada_xp_pinctrl_of_match[] __devinitdata = {
+	{
+		.compatible = "marvell,mv78230-pinctrl",
+		.data       = (void *) V_MV78230,
+	},
+	{
+		.compatible = "marvell,mv78260-pinctrl",
+		.data       = (void *) V_MV78260,
+	},
+	{
+		.compatible = "marvell,mv78460-pinctrl",
+		.data       = (void *) V_MV78460,
+	},
+	{ },
+};
+
+static struct mvebu_mpp_ctrl mv78230_mpp_controls[] = {
+	MPP_REG_CTRL(0, 48),
+};
+
+static struct pinctrl_gpio_range mv78230_mpp_gpio_ranges[] = {
+	MPP_GPIO_RANGE(0,   0,  0, 32),
+	MPP_GPIO_RANGE(1,  32, 32, 17),
+};
+
+static struct mvebu_mpp_ctrl mv78260_mpp_controls[] = {
+	MPP_REG_CTRL(0, 66),
+};
+
+static struct pinctrl_gpio_range mv78260_mpp_gpio_ranges[] = {
+	MPP_GPIO_RANGE(0,   0,  0, 32),
+	MPP_GPIO_RANGE(1,  32, 32, 32),
+	MPP_GPIO_RANGE(2,  64, 64,  3),
+};
+
+static struct mvebu_mpp_ctrl mv78460_mpp_controls[] = {
+	MPP_REG_CTRL(0, 66),
+};
+
+static struct pinctrl_gpio_range mv78460_mpp_gpio_ranges[] = {
+	MPP_GPIO_RANGE(0,   0,  0, 32),
+	MPP_GPIO_RANGE(1,  32, 32, 32),
+	MPP_GPIO_RANGE(2,  64, 64,  3),
+};
+
+static int __devinit armada_xp_pinctrl_probe(struct platform_device *pdev)
+{
+	struct mvebu_pinctrl_soc_info *soc = &armada_xp_pinctrl_info;
+	const struct of_device_id *match =
+		of_match_device(armada_xp_pinctrl_of_match, &pdev->dev);
+
+	if (!match)
+		return -ENODEV;
+
+	soc->variant = (unsigned) match->data & 0xff;
+
+	switch (soc->variant) {
+	case V_MV78230:
+		soc->controls = mv78230_mpp_controls;
+		soc->ncontrols = ARRAY_SIZE(mv78230_mpp_controls);
+		soc->modes = armada_xp_mpp_modes;
+		/* We don't necessarily want the full list of the
+		 * armada_xp_mpp_modes, but only the first 'n' ones
+		 * that are available on this SoC */
+		soc->nmodes = mv78230_mpp_controls[0].npins;
+		soc->gpioranges = mv78230_mpp_gpio_ranges;
+		soc->ngpioranges = ARRAY_SIZE(mv78230_mpp_gpio_ranges);
+		break;
+	case V_MV78260:
+		soc->controls = mv78260_mpp_controls;
+		soc->ncontrols = ARRAY_SIZE(mv78260_mpp_controls);
+		soc->modes = armada_xp_mpp_modes;
+		/* We don't necessarily want the full list of the
+		 * armada_xp_mpp_modes, but only the first 'n' ones
+		 * that are available on this SoC */
+		soc->nmodes = mv78260_mpp_controls[0].npins;
+		soc->gpioranges = mv78260_mpp_gpio_ranges;
+		soc->ngpioranges = ARRAY_SIZE(mv78260_mpp_gpio_ranges);
+		break;
+	case V_MV78460:
+		soc->controls = mv78460_mpp_controls;
+		soc->ncontrols = ARRAY_SIZE(mv78460_mpp_controls);
+		soc->modes = armada_xp_mpp_modes;
+		/* We don't necessarily want the full list of the
+		 * armada_xp_mpp_modes, but only the first 'n' ones
+		 * that are available on this SoC */
+		soc->nmodes = mv78460_mpp_controls[0].npins;
+		soc->gpioranges = mv78460_mpp_gpio_ranges;
+		soc->ngpioranges = ARRAY_SIZE(mv78460_mpp_gpio_ranges);
+		break;
+	}
+
+	pdev->dev.platform_data = soc;
+
+	return mvebu_pinctrl_probe(pdev);
+}
+
+static int __devexit armada_xp_pinctrl_remove(struct platform_device *pdev)
+{
+	return mvebu_pinctrl_remove(pdev);
+}
+
+static struct platform_driver armada_xp_pinctrl_driver = {
+	.driver = {
+		.name = "armada-xp-pinctrl",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(armada_xp_pinctrl_of_match),
+	},
+	.probe = armada_xp_pinctrl_probe,
+	.remove = __devexit_p(armada_xp_pinctrl_remove),
+};
+
+module_platform_driver(armada_xp_pinctrl_driver);
+
+MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
+MODULE_DESCRIPTION("Marvell Armada XP pinctrl driver");
+MODULE_LICENSE("GPL v2");

+ 620 - 0
drivers/pinctrl/pinctrl-dove.c

@@ -0,0 +1,620 @@
+/*
+ * Marvell Dove pinctrl driver based on mvebu pinctrl core
+ *
+ * Author: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-mvebu.h"
+
+#define DOVE_SB_REGS_VIRT_BASE		0xfde00000
+#define DOVE_MPP_VIRT_BASE		(DOVE_SB_REGS_VIRT_BASE | 0xd0200)
+#define DOVE_PMU_MPP_GENERAL_CTRL	(DOVE_MPP_VIRT_BASE + 0x10)
+#define  DOVE_AU0_AC97_SEL		BIT(16)
+#define DOVE_GLOBAL_CONFIG_1		(DOVE_SB_REGS_VIRT_BASE | 0xe802C)
+#define  DOVE_TWSI_ENABLE_OPTION1	BIT(7)
+#define DOVE_GLOBAL_CONFIG_2		(DOVE_SB_REGS_VIRT_BASE | 0xe8030)
+#define  DOVE_TWSI_ENABLE_OPTION2	BIT(20)
+#define  DOVE_TWSI_ENABLE_OPTION3	BIT(21)
+#define  DOVE_TWSI_OPTION3_GPIO		BIT(22)
+#define DOVE_SSP_CTRL_STATUS_1		(DOVE_SB_REGS_VIRT_BASE | 0xe8034)
+#define  DOVE_SSP_ON_AU1		BIT(0)
+#define DOVE_MPP_GENERAL_VIRT_BASE	(DOVE_SB_REGS_VIRT_BASE | 0xe803c)
+#define  DOVE_AU1_SPDIFO_GPIO_EN	BIT(1)
+#define  DOVE_NAND_GPIO_EN		BIT(0)
+#define DOVE_GPIO_LO_VIRT_BASE		(DOVE_SB_REGS_VIRT_BASE | 0xd0400)
+#define DOVE_MPP_CTRL4_VIRT_BASE	(DOVE_GPIO_LO_VIRT_BASE + 0x40)
+#define  DOVE_SPI_GPIO_SEL		BIT(5)
+#define  DOVE_UART1_GPIO_SEL		BIT(4)
+#define  DOVE_AU1_GPIO_SEL		BIT(3)
+#define  DOVE_CAM_GPIO_SEL		BIT(2)
+#define  DOVE_SD1_GPIO_SEL		BIT(1)
+#define  DOVE_SD0_GPIO_SEL		BIT(0)
+
+#define MPPS_PER_REG	8
+#define MPP_BITS	4
+#define MPP_MASK	0xf
+
+#define CONFIG_PMU	BIT(4)
+
+static int dove_pmu_mpp_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
+				 unsigned long *config)
+{
+	unsigned off = (ctrl->pid / MPPS_PER_REG) * MPP_BITS;
+	unsigned shift = (ctrl->pid % MPPS_PER_REG) * MPP_BITS;
+	unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
+	unsigned long mpp = readl(DOVE_MPP_VIRT_BASE + off);
+
+	if (pmu & (1 << ctrl->pid))
+		*config = CONFIG_PMU;
+	else
+		*config = (mpp >> shift) & MPP_MASK;
+	return 0;
+}
+
+static int dove_pmu_mpp_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
+				 unsigned long config)
+{
+	unsigned off = (ctrl->pid / MPPS_PER_REG) * MPP_BITS;
+	unsigned shift = (ctrl->pid % MPPS_PER_REG) * MPP_BITS;
+	unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
+	unsigned long mpp = readl(DOVE_MPP_VIRT_BASE + off);
+
+	if (config == CONFIG_PMU)
+		writel(pmu | (1 << ctrl->pid), DOVE_PMU_MPP_GENERAL_CTRL);
+	else {
+		writel(pmu & ~(1 << ctrl->pid), DOVE_PMU_MPP_GENERAL_CTRL);
+		mpp &= ~(MPP_MASK << shift);
+		mpp |= config << shift;
+		writel(mpp, DOVE_MPP_VIRT_BASE + off);
+	}
+	return 0;
+}
+
+static int dove_mpp4_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
+			      unsigned long *config)
+{
+	unsigned long mpp4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
+	unsigned long mask;
+
+	switch (ctrl->pid) {
+	case 24: /* mpp_camera */
+		mask = DOVE_CAM_GPIO_SEL;
+		break;
+	case 40: /* mpp_sdio0 */
+		mask = DOVE_SD0_GPIO_SEL;
+		break;
+	case 46: /* mpp_sdio1 */
+		mask = DOVE_SD1_GPIO_SEL;
+		break;
+	case 58: /* mpp_spi0 */
+		mask = DOVE_SPI_GPIO_SEL;
+		break;
+	case 62: /* mpp_uart1 */
+		mask = DOVE_UART1_GPIO_SEL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*config = ((mpp4 & mask) != 0);
+
+	return 0;
+}
+
+static int dove_mpp4_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
+			      unsigned long config)
+{
+	unsigned long mpp4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
+	unsigned long mask;
+
+	switch (ctrl->pid) {
+	case 24: /* mpp_camera */
+		mask = DOVE_CAM_GPIO_SEL;
+		break;
+	case 40: /* mpp_sdio0 */
+		mask = DOVE_SD0_GPIO_SEL;
+		break;
+	case 46: /* mpp_sdio1 */
+		mask = DOVE_SD1_GPIO_SEL;
+		break;
+	case 58: /* mpp_spi0 */
+		mask = DOVE_SPI_GPIO_SEL;
+		break;
+	case 62: /* mpp_uart1 */
+		mask = DOVE_UART1_GPIO_SEL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mpp4 &= ~mask;
+	if (config)
+		mpp4 |= mask;
+
+	writel(mpp4, DOVE_MPP_CTRL4_VIRT_BASE);
+
+	return 0;
+}
+
+static int dove_nand_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
+			      unsigned long *config)
+{
+	unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE);
+
+	*config = ((gmpp & DOVE_NAND_GPIO_EN) != 0);
+
+	return 0;
+}
+
+static int dove_nand_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
+			      unsigned long config)
+{
+	unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE);
+
+	gmpp &= ~DOVE_NAND_GPIO_EN;
+	if (config)
+		gmpp |= DOVE_NAND_GPIO_EN;
+
+	writel(gmpp, DOVE_MPP_GENERAL_VIRT_BASE);
+
+	return 0;
+}
+
+static int dove_audio0_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
+				unsigned long *config)
+{
+	unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
+
+	*config = ((pmu & DOVE_AU0_AC97_SEL) != 0);
+
+	return 0;
+}
+
+static int dove_audio0_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
+				unsigned long config)
+{
+	unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
+
+	pmu &= ~DOVE_AU0_AC97_SEL;
+	if (config)
+		pmu |= DOVE_AU0_AC97_SEL;
+	writel(pmu, DOVE_PMU_MPP_GENERAL_CTRL);
+
+	return 0;
+}
+
+static int dove_audio1_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
+				unsigned long *config)
+{
+	unsigned long mpp4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
+	unsigned long sspc1 = readl(DOVE_SSP_CTRL_STATUS_1);
+	unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE);
+	unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2);
+
+	*config = 0;
+	if (mpp4 & DOVE_AU1_GPIO_SEL)
+		*config |= BIT(3);
+	if (sspc1 & DOVE_SSP_ON_AU1)
+		*config |= BIT(2);
+	if (gmpp & DOVE_AU1_SPDIFO_GPIO_EN)
+		*config |= BIT(1);
+	if (gcfg2 & DOVE_TWSI_OPTION3_GPIO)
+		*config |= BIT(0);
+
+	/* SSP/TWSI only if I2S1 not set*/
+	if ((*config & BIT(3)) == 0)
+		*config &= ~(BIT(2) | BIT(0));
+	/* TWSI only if SPDIFO not set*/
+	if ((*config & BIT(1)) == 0)
+		*config &= ~BIT(0);
+	return 0;
+}
+
+static int dove_audio1_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
+				unsigned long config)
+{
+	unsigned long mpp4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
+	unsigned long sspc1 = readl(DOVE_SSP_CTRL_STATUS_1);
+	unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE);
+	unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2);
+
+	if (config & BIT(0))
+		gcfg2 |= DOVE_TWSI_OPTION3_GPIO;
+	if (config & BIT(1))
+		gmpp |= DOVE_AU1_SPDIFO_GPIO_EN;
+	if (config & BIT(2))
+		sspc1 |= DOVE_SSP_ON_AU1;
+	if (config & BIT(3))
+		mpp4 |= DOVE_AU1_GPIO_SEL;
+
+	writel(mpp4, DOVE_MPP_CTRL4_VIRT_BASE);
+	writel(sspc1, DOVE_SSP_CTRL_STATUS_1);
+	writel(gmpp, DOVE_MPP_GENERAL_VIRT_BASE);
+	writel(gcfg2, DOVE_GLOBAL_CONFIG_2);
+
+	return 0;
+}
+
+/* mpp[52:57] gpio pins depend heavily on current config;
+ * gpio_req does not try to mux in gpio capabilities to not
+ * break other functions. If you require all mpps as gpio
+ * enforce gpio setting by pinctrl mapping.
+ */
+static int dove_audio1_ctrl_gpio_req(struct mvebu_mpp_ctrl *ctrl, u8 pid)
+{
+	unsigned long config;
+
+	dove_audio1_ctrl_get(ctrl, &config);
+
+	switch (config) {
+	case 0x02: /* i2s1 : gpio[56:57] */
+	case 0x0e: /* ssp  : gpio[56:57] */
+		if (pid >= 56)
+			return 0;
+		return -ENOTSUPP;
+	case 0x08: /* spdifo : gpio[52:55] */
+	case 0x0b: /* twsi   : gpio[52:55] */
+		if (pid <= 55)
+			return 0;
+		return -ENOTSUPP;
+	case 0x0a: /* all gpio */
+		return 0;
+	/* 0x00 : i2s1/spdifo : no gpio */
+	/* 0x0c : ssp/spdifo  : no gpio */
+	/* 0x0f : ssp/twsi    : no gpio */
+	}
+	return -ENOTSUPP;
+}
+
+/* mpp[52:57] has gpio pins capable of in and out */
+static int dove_audio1_ctrl_gpio_dir(struct mvebu_mpp_ctrl *ctrl, u8 pid,
+				bool input)
+{
+	if (pid < 52 || pid > 57)
+		return -ENOTSUPP;
+	return 0;
+}
+
+static int dove_twsi_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
+			      unsigned long *config)
+{
+	unsigned long gcfg1 = readl(DOVE_GLOBAL_CONFIG_1);
+	unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2);
+
+	*config = 0;
+	if (gcfg1 & DOVE_TWSI_ENABLE_OPTION1)
+		*config = 1;
+	else if (gcfg2 & DOVE_TWSI_ENABLE_OPTION2)
+		*config = 2;
+	else if (gcfg2 & DOVE_TWSI_ENABLE_OPTION3)
+		*config = 3;
+
+	return 0;
+}
+
+static int dove_twsi_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
+				unsigned long config)
+{
+	unsigned long gcfg1 = readl(DOVE_GLOBAL_CONFIG_1);
+	unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2);
+
+	gcfg1 &= ~DOVE_TWSI_ENABLE_OPTION1;
+	gcfg2 &= ~(DOVE_TWSI_ENABLE_OPTION2 | DOVE_TWSI_ENABLE_OPTION2);
+
+	switch (config) {
+	case 1:
+		gcfg1 |= DOVE_TWSI_ENABLE_OPTION1;
+		break;
+	case 2:
+		gcfg2 |= DOVE_TWSI_ENABLE_OPTION2;
+		break;
+	case 3:
+		gcfg2 |= DOVE_TWSI_ENABLE_OPTION3;
+		break;
+	}
+
+	writel(gcfg1, DOVE_GLOBAL_CONFIG_1);
+	writel(gcfg2, DOVE_GLOBAL_CONFIG_2);
+
+	return 0;
+}
+
+static struct mvebu_mpp_ctrl dove_mpp_controls[] = {
+	MPP_FUNC_CTRL(0, 0, "mpp0", dove_pmu_mpp_ctrl),
+	MPP_FUNC_CTRL(1, 1, "mpp1", dove_pmu_mpp_ctrl),
+	MPP_FUNC_CTRL(2, 2, "mpp2", dove_pmu_mpp_ctrl),
+	MPP_FUNC_CTRL(3, 3, "mpp3", dove_pmu_mpp_ctrl),
+	MPP_FUNC_CTRL(4, 4, "mpp4", dove_pmu_mpp_ctrl),
+	MPP_FUNC_CTRL(5, 5, "mpp5", dove_pmu_mpp_ctrl),
+	MPP_FUNC_CTRL(6, 6, "mpp6", dove_pmu_mpp_ctrl),
+	MPP_FUNC_CTRL(7, 7, "mpp7", dove_pmu_mpp_ctrl),
+	MPP_FUNC_CTRL(8, 8, "mpp8", dove_pmu_mpp_ctrl),
+	MPP_FUNC_CTRL(9, 9, "mpp9", dove_pmu_mpp_ctrl),
+	MPP_FUNC_CTRL(10, 10, "mpp10", dove_pmu_mpp_ctrl),
+	MPP_FUNC_CTRL(11, 11, "mpp11", dove_pmu_mpp_ctrl),
+	MPP_FUNC_CTRL(12, 12, "mpp12", dove_pmu_mpp_ctrl),
+	MPP_FUNC_CTRL(13, 13, "mpp13", dove_pmu_mpp_ctrl),
+	MPP_FUNC_CTRL(14, 14, "mpp14", dove_pmu_mpp_ctrl),
+	MPP_FUNC_CTRL(15, 15, "mpp15", dove_pmu_mpp_ctrl),
+	MPP_REG_CTRL(16, 23),
+	MPP_FUNC_CTRL(24, 39, "mpp_camera", dove_mpp4_ctrl),
+	MPP_FUNC_CTRL(40, 45, "mpp_sdio0", dove_mpp4_ctrl),
+	MPP_FUNC_CTRL(46, 51, "mpp_sdio1", dove_mpp4_ctrl),
+	MPP_FUNC_GPIO_CTRL(52, 57, "mpp_audio1", dove_audio1_ctrl),
+	MPP_FUNC_CTRL(58, 61, "mpp_spi0", dove_mpp4_ctrl),
+	MPP_FUNC_CTRL(62, 63, "mpp_uart1", dove_mpp4_ctrl),
+	MPP_FUNC_CTRL(64, 71, "mpp_nand", dove_nand_ctrl),
+	MPP_FUNC_CTRL(72, 72, "audio0", dove_audio0_ctrl),
+	MPP_FUNC_CTRL(73, 73, "twsi", dove_twsi_ctrl),
+};
+
+static struct mvebu_mpp_mode dove_mpp_modes[] = {
+	MPP_MODE(0,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x02, "uart2", "rts"),
+		MPP_FUNCTION(0x03, "sdio0", "cd"),
+		MPP_FUNCTION(0x0f, "lcd0", "pwm"),
+		MPP_FUNCTION(0x10, "pmu", NULL)),
+	MPP_MODE(1,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x02, "uart2", "cts"),
+		MPP_FUNCTION(0x03, "sdio0", "wp"),
+		MPP_FUNCTION(0x0f, "lcd1", "pwm"),
+		MPP_FUNCTION(0x10, "pmu", NULL)),
+	MPP_MODE(2,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x01, "sata", "prsnt"),
+		MPP_FUNCTION(0x02, "uart2", "txd"),
+		MPP_FUNCTION(0x03, "sdio0", "buspwr"),
+		MPP_FUNCTION(0x04, "uart1", "rts"),
+		MPP_FUNCTION(0x10, "pmu", NULL)),
+	MPP_MODE(3,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x01, "sata", "act"),
+		MPP_FUNCTION(0x02, "uart2", "rxd"),
+		MPP_FUNCTION(0x03, "sdio0", "ledctrl"),
+		MPP_FUNCTION(0x04, "uart1", "cts"),
+		MPP_FUNCTION(0x0f, "lcd-spi", "cs1"),
+		MPP_FUNCTION(0x10, "pmu", NULL)),
+	MPP_MODE(4,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x02, "uart3", "rts"),
+		MPP_FUNCTION(0x03, "sdio1", "cd"),
+		MPP_FUNCTION(0x04, "spi1", "miso"),
+		MPP_FUNCTION(0x10, "pmu", NULL)),
+	MPP_MODE(5,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x02, "uart3", "cts"),
+		MPP_FUNCTION(0x03, "sdio1", "wp"),
+		MPP_FUNCTION(0x04, "spi1", "cs"),
+		MPP_FUNCTION(0x10, "pmu", NULL)),
+	MPP_MODE(6,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x02, "uart3", "txd"),
+		MPP_FUNCTION(0x03, "sdio1", "buspwr"),
+		MPP_FUNCTION(0x04, "spi1", "mosi"),
+		MPP_FUNCTION(0x10, "pmu", NULL)),
+	MPP_MODE(7,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x02, "uart3", "rxd"),
+		MPP_FUNCTION(0x03, "sdio1", "ledctrl"),
+		MPP_FUNCTION(0x04, "spi1", "sck"),
+		MPP_FUNCTION(0x10, "pmu", NULL)),
+	MPP_MODE(8,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x01, "watchdog", "rstout"),
+		MPP_FUNCTION(0x10, "pmu", NULL)),
+	MPP_MODE(9,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x05, "pex1", "clkreq"),
+		MPP_FUNCTION(0x10, "pmu", NULL)),
+	MPP_MODE(10,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x05, "ssp", "sclk"),
+		MPP_FUNCTION(0x10, "pmu", NULL)),
+	MPP_MODE(11,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x01, "sata", "prsnt"),
+		MPP_FUNCTION(0x02, "sata-1", "act"),
+		MPP_FUNCTION(0x03, "sdio0", "ledctrl"),
+		MPP_FUNCTION(0x04, "sdio1", "ledctrl"),
+		MPP_FUNCTION(0x05, "pex0", "clkreq"),
+		MPP_FUNCTION(0x10, "pmu", NULL)),
+	MPP_MODE(12,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x01, "sata", "act"),
+		MPP_FUNCTION(0x02, "uart2", "rts"),
+		MPP_FUNCTION(0x03, "audio0", "extclk"),
+		MPP_FUNCTION(0x04, "sdio1", "cd"),
+		MPP_FUNCTION(0x10, "pmu", NULL)),
+	MPP_MODE(13,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x02, "uart2", "cts"),
+		MPP_FUNCTION(0x03, "audio1", "extclk"),
+		MPP_FUNCTION(0x04, "sdio1", "wp"),
+		MPP_FUNCTION(0x05, "ssp", "extclk"),
+		MPP_FUNCTION(0x10, "pmu", NULL)),
+	MPP_MODE(14,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x02, "uart2", "txd"),
+		MPP_FUNCTION(0x04, "sdio1", "buspwr"),
+		MPP_FUNCTION(0x05, "ssp", "rxd"),
+		MPP_FUNCTION(0x10, "pmu", NULL)),
+	MPP_MODE(15,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x02, "uart2", "rxd"),
+		MPP_FUNCTION(0x04, "sdio1", "ledctrl"),
+		MPP_FUNCTION(0x05, "ssp", "sfrm"),
+		MPP_FUNCTION(0x10, "pmu", NULL)),
+	MPP_MODE(16,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x02, "uart3", "rts"),
+		MPP_FUNCTION(0x03, "sdio0", "cd"),
+		MPP_FUNCTION(0x04, "lcd-spi", "cs1"),
+		MPP_FUNCTION(0x05, "ac97", "sdi1")),
+	MPP_MODE(17,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x01, "ac97-1", "sysclko"),
+		MPP_FUNCTION(0x02, "uart3", "cts"),
+		MPP_FUNCTION(0x03, "sdio0", "wp"),
+		MPP_FUNCTION(0x04, "twsi", "sda"),
+		MPP_FUNCTION(0x05, "ac97", "sdi2")),
+	MPP_MODE(18,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x02, "uart3", "txd"),
+		MPP_FUNCTION(0x03, "sdio0", "buspwr"),
+		MPP_FUNCTION(0x04, "lcd0", "pwm"),
+		MPP_FUNCTION(0x05, "ac97", "sdi3")),
+	MPP_MODE(19,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x02, "uart3", "rxd"),
+		MPP_FUNCTION(0x03, "sdio0", "ledctrl"),
+		MPP_FUNCTION(0x04, "twsi", "sck")),
+	MPP_MODE(20,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x01, "ac97", "sysclko"),
+		MPP_FUNCTION(0x02, "lcd-spi", "miso"),
+		MPP_FUNCTION(0x03, "sdio1", "cd"),
+		MPP_FUNCTION(0x05, "sdio0", "cd"),
+		MPP_FUNCTION(0x06, "spi1", "miso")),
+	MPP_MODE(21,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x01, "uart1", "rts"),
+		MPP_FUNCTION(0x02, "lcd-spi", "cs0"),
+		MPP_FUNCTION(0x03, "sdio1", "wp"),
+		MPP_FUNCTION(0x04, "ssp", "sfrm"),
+		MPP_FUNCTION(0x05, "sdio0", "wp"),
+		MPP_FUNCTION(0x06, "spi1", "cs")),
+	MPP_MODE(22,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x01, "uart1", "cts"),
+		MPP_FUNCTION(0x02, "lcd-spi", "mosi"),
+		MPP_FUNCTION(0x03, "sdio1", "buspwr"),
+		MPP_FUNCTION(0x04, "ssp", "txd"),
+		MPP_FUNCTION(0x05, "sdio0", "buspwr"),
+		MPP_FUNCTION(0x06, "spi1", "mosi")),
+	MPP_MODE(23,
+		MPP_FUNCTION(0x00, "gpio", NULL),
+		MPP_FUNCTION(0x02, "lcd-spi", "sck"),
+		MPP_FUNCTION(0x03, "sdio1", "ledctrl"),
+		MPP_FUNCTION(0x04, "ssp", "sclk"),
+		MPP_FUNCTION(0x05, "sdio0", "ledctrl"),
+		MPP_FUNCTION(0x06, "spi1", "sck")),
+	MPP_MODE(24,
+		MPP_FUNCTION(0x00, "camera", NULL),
+		MPP_FUNCTION(0x01, "gpio", NULL)),
+	MPP_MODE(40,
+		MPP_FUNCTION(0x00, "sdio0", NULL),
+		MPP_FUNCTION(0x01, "gpio", NULL)),
+	MPP_MODE(46,
+		MPP_FUNCTION(0x00, "sdio1", NULL),
+		MPP_FUNCTION(0x01, "gpio", NULL)),
+	MPP_MODE(52,
+		MPP_FUNCTION(0x00, "i2s1/spdifo", NULL),
+		MPP_FUNCTION(0x02, "i2s1", NULL),
+		MPP_FUNCTION(0x08, "spdifo", NULL),
+		MPP_FUNCTION(0x0a, "gpio", NULL),
+		MPP_FUNCTION(0x0b, "twsi", NULL),
+		MPP_FUNCTION(0x0c, "ssp/spdifo", NULL),
+		MPP_FUNCTION(0x0e, "ssp", NULL),
+		MPP_FUNCTION(0x0f, "ssp/twsi", NULL)),
+	MPP_MODE(58,
+		MPP_FUNCTION(0x00, "spi0", NULL),
+		MPP_FUNCTION(0x01, "gpio", NULL)),
+	MPP_MODE(62,
+		MPP_FUNCTION(0x00, "uart1", NULL),
+		MPP_FUNCTION(0x01, "gpio", NULL)),
+	MPP_MODE(64,
+		MPP_FUNCTION(0x00, "nand", NULL),
+		MPP_FUNCTION(0x01, "gpo", NULL)),
+	MPP_MODE(72,
+		MPP_FUNCTION(0x00, "i2s", NULL),
+		MPP_FUNCTION(0x01, "ac97", NULL)),
+	MPP_MODE(73,
+		MPP_FUNCTION(0x00, "twsi-none", NULL),
+		MPP_FUNCTION(0x01, "twsi-opt1", NULL),
+		MPP_FUNCTION(0x02, "twsi-opt2", NULL),
+		MPP_FUNCTION(0x03, "twsi-opt3", NULL)),
+};
+
+static struct pinctrl_gpio_range dove_mpp_gpio_ranges[] = {
+	MPP_GPIO_RANGE(0,  0,  0, 32),
+	MPP_GPIO_RANGE(1, 32, 32, 32),
+	MPP_GPIO_RANGE(2, 64, 64,  8),
+};
+
+static struct mvebu_pinctrl_soc_info dove_pinctrl_info = {
+	.controls = dove_mpp_controls,
+	.ncontrols = ARRAY_SIZE(dove_mpp_controls),
+	.modes = dove_mpp_modes,
+	.nmodes = ARRAY_SIZE(dove_mpp_modes),
+	.gpioranges = dove_mpp_gpio_ranges,
+	.ngpioranges = ARRAY_SIZE(dove_mpp_gpio_ranges),
+	.variant = 0,
+};
+
+static struct clk *clk;
+
+static struct of_device_id dove_pinctrl_of_match[] __devinitdata = {
+	{ .compatible = "marvell,dove-pinctrl", .data = &dove_pinctrl_info },
+	{ }
+};
+
+static int __devinit dove_pinctrl_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *match =
+		of_match_device(dove_pinctrl_of_match, &pdev->dev);
+	pdev->dev.platform_data = match->data;
+
+	/*
+	 * General MPP Configuration Register is part of pdma registers.
+	 * grab clk to make sure it is ticking.
+	 */
+	clk = devm_clk_get(&pdev->dev, NULL);
+	if (!IS_ERR(clk))
+		clk_prepare_enable(clk);
+
+	return mvebu_pinctrl_probe(pdev);
+}
+
+static int __devexit dove_pinctrl_remove(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = mvebu_pinctrl_remove(pdev);
+	if (!IS_ERR(clk))
+		clk_disable_unprepare(clk);
+	return ret;
+}
+
+static struct platform_driver dove_pinctrl_driver = {
+	.driver = {
+		.name = "dove-pinctrl",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(dove_pinctrl_of_match),
+	},
+	.probe = dove_pinctrl_probe,
+	.remove = __devexit_p(dove_pinctrl_remove),
+};
+
+module_platform_driver(dove_pinctrl_driver);
+
+MODULE_AUTHOR("Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>");
+MODULE_DESCRIPTION("Marvell Dove pinctrl driver");
+MODULE_LICENSE("GPL v2");

+ 472 - 0
drivers/pinctrl/pinctrl-kirkwood.c

@@ -0,0 +1,472 @@
+/*
+ * Marvell Kirkwood pinctrl driver based on mvebu pinctrl core
+ *
+ * Author: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-mvebu.h"
+
+#define V(f6180, f6190, f6192, f6281, f6282)		\
+	((f6180 << 0) | (f6190 << 1) | (f6192 << 2) |	\
+	 (f6281 << 3) | (f6282 << 4))
+
+enum kirkwood_variant {
+	VARIANT_MV88F6180 = V(1, 0, 0, 0, 0),
+	VARIANT_MV88F6190 = V(0, 1, 0, 0, 0),
+	VARIANT_MV88F6192 = V(0, 0, 1, 0, 0),
+	VARIANT_MV88F6281 = V(0, 0, 0, 1, 0),
+	VARIANT_MV88F6282 = V(0, 0, 0, 0, 1),
+};
+
+static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = {
+	MPP_MODE(0,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "nand", "io2",     V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "spi", "cs",       V(1, 1, 1, 1, 1))),
+	MPP_MODE(1,
+		MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "nand", "io3",     V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "spi", "mosi",     V(1, 1, 1, 1, 1))),
+	MPP_MODE(2,
+		MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "nand", "io4",     V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "spi", "sck",      V(1, 1, 1, 1, 1))),
+	MPP_MODE(3,
+		MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "nand", "io5",     V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "spi", "miso",     V(1, 1, 1, 1, 1))),
+	MPP_MODE(4,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "nand", "io6",     V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "uart0", "rxd",    V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x5, "sata1", "act",    V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "hsync",    V(0, 0, 0, 0, 1)),
+		MPP_VAR_FUNCTION(0xd, "ptp", "clk",      V(1, 1, 1, 1, 0))),
+	MPP_MODE(5,
+		MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "nand", "io7",     V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "uart0", "txd",    V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "ptp", "trig",     V(1, 1, 1, 1, 0)),
+		MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "vsync",    V(0, 0, 0, 0, 1))),
+	MPP_MODE(6,
+		MPP_VAR_FUNCTION(0x0, "sysrst", "out",   V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "spi", "mosi",     V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "ptp", "trig",     V(1, 1, 1, 1, 0))),
+	MPP_MODE(7,
+		MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "pex", "rsto",     V(1, 1, 1, 1, 0)),
+		MPP_VAR_FUNCTION(0x2, "spi", "cs",       V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ptp", "trig",     V(1, 1, 1, 1, 0)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "pwm",      V(0, 0, 0, 0, 1))),
+	MPP_MODE(8,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "twsi0", "sda",    V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "uart0", "rts",    V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "uart1", "rts",    V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "mii-1", "rxerr",  V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x5, "sata1", "prsnt",  V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xc, "ptp", "clk",      V(1, 1, 1, 1, 0)),
+		MPP_VAR_FUNCTION(0xd, "mii", "col",      V(1, 1, 1, 1, 1))),
+	MPP_MODE(9,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "twsi0", "sck",    V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "uart0", "cts",    V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "uart1", "cts",    V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x5, "sata0", "prsnt",  V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xc, "ptp", "evreq",    V(1, 1, 1, 1, 0)),
+		MPP_VAR_FUNCTION(0xd, "mii", "crs",      V(1, 1, 1, 1, 1))),
+	MPP_MODE(10,
+		MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "spi", "sck",      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0X3, "uart0", "txd",    V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x5, "sata1", "act",    V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xc, "ptp", "trig",     V(1, 1, 1, 1, 0))),
+	MPP_MODE(11,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "spi", "miso",     V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "uart0", "rxd",    V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "ptp-1", "evreq",  V(1, 1, 1, 1, 0)),
+		MPP_VAR_FUNCTION(0xc, "ptp-2", "trig",   V(1, 1, 1, 1, 0)),
+		MPP_VAR_FUNCTION(0xd, "ptp", "clk",      V(1, 1, 1, 1, 0)),
+		MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1))),
+	MPP_MODE(12,
+		MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 0, 1)),
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 0)),
+		MPP_VAR_FUNCTION(0x1, "sdio", "clk",     V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xa, "audio", "spdifo", V(0, 0, 0, 0, 1)),
+		MPP_VAR_FUNCTION(0xb, "spi", "mosi",     V(0, 0, 0, 0, 1)),
+		MPP_VAR_FUNCTION(0xd, "twsi1", "sda",    V(0, 0, 0, 0, 1))),
+	MPP_MODE(13,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "sdio", "cmd",     V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "uart1", "txd",    V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xa, "audio", "rmclk",  V(0, 0, 0, 0, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "pwm",      V(0, 0, 0, 0, 1))),
+	MPP_MODE(14,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "sdio", "d0",      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "uart1", "rxd",    V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "sata1", "prsnt",  V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xa, "audio", "spdifi", V(0, 0, 0, 0, 1)),
+		MPP_VAR_FUNCTION(0xb, "audio-1", "sdi",  V(0, 0, 0, 0, 1)),
+		MPP_VAR_FUNCTION(0xd, "mii", "col",      V(1, 1, 1, 1, 1))),
+	MPP_MODE(15,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "sdio", "d1",      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "uart0", "rts",    V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "uart1", "txd",    V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "sata0", "act",    V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "spi", "cs",       V(0, 0, 0, 0, 1))),
+	MPP_MODE(16,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "sdio", "d2",      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "uart0", "cts",    V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "uart1", "rxd",    V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "sata1", "act",    V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "extclk",   V(0, 0, 0, 0, 1)),
+		MPP_VAR_FUNCTION(0xd, "mii", "crs",      V(1, 1, 1, 1, 1))),
+	MPP_MODE(17,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "sdio", "d3",      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "sata0", "prsnt",  V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xa, "sata1", "act",    V(0, 0, 0, 0, 1)),
+		MPP_VAR_FUNCTION(0xd, "twsi1", "sck",    V(0, 0, 0, 0, 1))),
+	MPP_MODE(18,
+		MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "nand", "io0",     V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "pex", "clkreq",   V(0, 0, 0, 0, 1))),
+	MPP_MODE(19,
+		MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "nand", "io1",     V(1, 1, 1, 1, 1))),
+	MPP_MODE(20,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp0",       V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql",    V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ge1", "txd0",     V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x5, "sata1", "act",    V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d0",       V(0, 0, 0, 0, 1)),
+		MPP_VAR_FUNCTION(0xc, "mii", "rxerr",    V(1, 0, 0, 0, 0))),
+	MPP_MODE(21,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp1",       V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql",    V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ge1", "txd1",     V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(1, 0, 0, 0, 0)),
+		MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d1",       V(0, 0, 0, 0, 1))),
+	MPP_MODE(22,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp2",       V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql",    V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ge1", "txd2",     V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(1, 0, 0, 0, 0)),
+		MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x5, "sata1", "prsnt",  V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d2",       V(0, 0, 0, 0, 1))),
+	MPP_MODE(23,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp3",       V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql",    V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ge1", "txd3",     V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(1, 0, 0, 0, 0)),
+		MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x5, "sata0", "prsnt",  V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d3",       V(0, 0, 0, 0, 1))),
+	MPP_MODE(24,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp4",       V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0",  V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ge1", "rxd0",     V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(1, 0, 0, 0, 0)),
+		MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d4",       V(0, 0, 0, 0, 1))),
+	MPP_MODE(25,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp5",       V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck",  V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ge1", "rxd1",     V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(1, 0, 0, 0, 0)),
+		MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d5",       V(0, 0, 0, 0, 1))),
+	MPP_MODE(26,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp6",       V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ge1", "rxd2",     V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(1, 0, 0, 0, 0)),
+		MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d6",       V(0, 0, 0, 0, 1))),
+	MPP_MODE(27,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp7",       V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ge1", "rxd3",     V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(1, 0, 0, 0, 0)),
+		MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d7",       V(0, 0, 0, 0, 1))),
+	MPP_MODE(28,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp8",       V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "int",      V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ge1", "col",      V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(1, 0, 0, 0, 0)),
+		MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d8",       V(0, 0, 0, 0, 1))),
+	MPP_MODE(29,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(1, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp9",       V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "rst",      V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ge1", "txclk",    V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(1, 0, 0, 0, 0)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d9",       V(0, 0, 0, 0, 1))),
+	MPP_MODE(30,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp10",      V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "pclk",     V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ge1", "rxctl",    V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d10",      V(0, 0, 0, 0, 1))),
+	MPP_MODE(31,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp11",      V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "fs",       V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ge1", "rxclk",    V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d11",      V(0, 0, 0, 0, 1))),
+	MPP_MODE(32,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp12",      V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "drx",      V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ge1", "txclko",   V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d12",      V(0, 0, 0, 0, 1))),
+	MPP_MODE(33,
+		MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "dtx",      V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ge1", "txctl",    V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d13",      V(0, 0, 0, 0, 1))),
+	MPP_MODE(34,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1",  V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ge1", "txen",     V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x5, "sata1", "act",    V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d14",      V(0, 0, 0, 0, 1))),
+	MPP_MODE(35,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql",    V(0, 0, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x3, "ge1", "rxerr",    V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d15",      V(0, 0, 0, 0, 1)),
+		MPP_VAR_FUNCTION(0xc, "mii", "rxerr",    V(0, 1, 1, 1, 1))),
+	MPP_MODE(36,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp0",       V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1",  V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "twsi1", "sda",    V(0, 0, 0, 0, 1))),
+	MPP_MODE(37,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp1",       V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql",    V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "twsi1", "sck",    V(0, 0, 0, 0, 1))),
+	MPP_MODE(38,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp2",       V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql",    V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "rmclk",  V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d18",      V(0, 0, 0, 0, 1))),
+	MPP_MODE(39,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp3",       V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0",  V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "bclk",   V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d19",      V(0, 0, 0, 0, 1))),
+	MPP_MODE(40,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp4",       V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck",  V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "sdo",    V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d20",      V(0, 0, 0, 0, 1))),
+	MPP_MODE(41,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp5",       V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "lrclk",  V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d21",      V(0, 0, 0, 0, 1))),
+	MPP_MODE(42,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp6",       V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "mclk",   V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d22",      V(0, 0, 0, 0, 1))),
+	MPP_MODE(43,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp7",       V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "int",      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "sdi",    V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d23",      V(0, 0, 0, 0, 1))),
+	MPP_MODE(44,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp8",       V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "rst",      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "clk",      V(0, 0, 0, 0, 1))),
+	MPP_MODE(45,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp9",       V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "pclk",     V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "e",        V(0, 0, 0, 0, 1))),
+	MPP_MODE(46,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp10",      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "fs",       V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "hsync",    V(0, 0, 0, 0, 1))),
+	MPP_MODE(47,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp11",      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "drx",      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "vsync",    V(0, 0, 0, 0, 1))),
+	MPP_MODE(48,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp12",      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "dtx",      V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d16",      V(0, 0, 0, 0, 1))),
+	MPP_MODE(49,
+		MPP_VAR_FUNCTION(0x0, "gpio", NULL,      V(0, 0, 0, 1, 0)),
+		MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(0, 0, 0, 0, 1)),
+		MPP_VAR_FUNCTION(0x1, "ts", "mp9",       V(0, 0, 0, 1, 0)),
+		MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql",    V(0, 0, 0, 1, 1)),
+		MPP_VAR_FUNCTION(0x5, "ptp", "clk",      V(0, 0, 0, 1, 0)),
+		MPP_VAR_FUNCTION(0xa, "pex", "clkreq",   V(0, 0, 0, 0, 1)),
+		MPP_VAR_FUNCTION(0xb, "lcd", "d17",      V(0, 0, 0, 0, 1))),
+};
+
+static struct mvebu_mpp_ctrl mv88f6180_mpp_controls[] = {
+	MPP_REG_CTRL(0, 29),
+};
+
+static struct pinctrl_gpio_range mv88f6180_gpio_ranges[] = {
+	MPP_GPIO_RANGE(0, 0, 0, 30),
+};
+
+static struct mvebu_mpp_ctrl mv88f619x_mpp_controls[] = {
+	MPP_REG_CTRL(0, 35),
+};
+
+static struct pinctrl_gpio_range mv88f619x_gpio_ranges[] = {
+	MPP_GPIO_RANGE(0,  0,  0, 32),
+	MPP_GPIO_RANGE(1, 32, 32,  4),
+};
+
+static struct mvebu_mpp_ctrl mv88f628x_mpp_controls[] = {
+	MPP_REG_CTRL(0, 49),
+};
+
+static struct pinctrl_gpio_range mv88f628x_gpio_ranges[] = {
+	MPP_GPIO_RANGE(0,  0,  0, 32),
+	MPP_GPIO_RANGE(1, 32, 32, 18),
+};
+
+static struct mvebu_pinctrl_soc_info mv88f6180_info = {
+	.variant = VARIANT_MV88F6180,
+	.controls = mv88f6180_mpp_controls,
+	.ncontrols = ARRAY_SIZE(mv88f6180_mpp_controls),
+	.modes = mv88f6xxx_mpp_modes,
+	.nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes),
+	.gpioranges = mv88f6180_gpio_ranges,
+	.ngpioranges = ARRAY_SIZE(mv88f6180_gpio_ranges),
+};
+
+static struct mvebu_pinctrl_soc_info mv88f6190_info = {
+	.variant = VARIANT_MV88F6190,
+	.controls = mv88f619x_mpp_controls,
+	.ncontrols = ARRAY_SIZE(mv88f619x_mpp_controls),
+	.modes = mv88f6xxx_mpp_modes,
+	.nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes),
+	.gpioranges = mv88f619x_gpio_ranges,
+	.ngpioranges = ARRAY_SIZE(mv88f619x_gpio_ranges),
+};
+
+static struct mvebu_pinctrl_soc_info mv88f6192_info = {
+	.variant = VARIANT_MV88F6192,
+	.controls = mv88f619x_mpp_controls,
+	.ncontrols = ARRAY_SIZE(mv88f619x_mpp_controls),
+	.modes = mv88f6xxx_mpp_modes,
+	.nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes),
+	.gpioranges = mv88f619x_gpio_ranges,
+	.ngpioranges = ARRAY_SIZE(mv88f619x_gpio_ranges),
+};
+
+static struct mvebu_pinctrl_soc_info mv88f6281_info = {
+	.variant = VARIANT_MV88F6281,
+	.controls = mv88f628x_mpp_controls,
+	.ncontrols = ARRAY_SIZE(mv88f628x_mpp_controls),
+	.modes = mv88f6xxx_mpp_modes,
+	.nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes),
+	.gpioranges = mv88f628x_gpio_ranges,
+	.ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges),
+};
+
+static struct mvebu_pinctrl_soc_info mv88f6282_info = {
+	.variant = VARIANT_MV88F6282,
+	.controls = mv88f628x_mpp_controls,
+	.ncontrols = ARRAY_SIZE(mv88f628x_mpp_controls),
+	.modes = mv88f6xxx_mpp_modes,
+	.nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes),
+	.gpioranges = mv88f628x_gpio_ranges,
+	.ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges),
+};
+
+static struct of_device_id kirkwood_pinctrl_of_match[] __devinitdata = {
+	{ .compatible = "marvell,88f6180-pinctrl", .data = &mv88f6180_info },
+	{ .compatible = "marvell,88f6190-pinctrl", .data = &mv88f6190_info },
+	{ .compatible = "marvell,88f6192-pinctrl", .data = &mv88f6192_info },
+	{ .compatible = "marvell,88f6281-pinctrl", .data = &mv88f6281_info },
+	{ .compatible = "marvell,88f6282-pinctrl", .data = &mv88f6282_info },
+	{ }
+};
+
+static int __devinit kirkwood_pinctrl_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *match =
+		of_match_device(kirkwood_pinctrl_of_match, &pdev->dev);
+	pdev->dev.platform_data = match->data;
+	return mvebu_pinctrl_probe(pdev);
+}
+
+static int __devexit kirkwood_pinctrl_remove(struct platform_device *pdev)
+{
+	return mvebu_pinctrl_remove(pdev);
+}
+
+static struct platform_driver kirkwood_pinctrl_driver = {
+	.driver = {
+		.name = "kirkwood-pinctrl",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(kirkwood_pinctrl_of_match),
+	},
+	.probe = kirkwood_pinctrl_probe,
+	.remove = __devexit_p(kirkwood_pinctrl_remove),
+};
+
+module_platform_driver(kirkwood_pinctrl_driver);
+
+MODULE_AUTHOR("Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>");
+MODULE_DESCRIPTION("Marvell Kirkwood pinctrl driver");
+MODULE_LICENSE("GPL v2");

+ 754 - 0
drivers/pinctrl/pinctrl-mvebu.c

@@ -0,0 +1,754 @@
+/*
+ * Marvell MVEBU pinctrl core driver
+ *
+ * Authors: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *          Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "core.h"
+#include "pinctrl-mvebu.h"
+
+#define MPPS_PER_REG	8
+#define MPP_BITS	4
+#define MPP_MASK	0xf
+
+struct mvebu_pinctrl_function {
+	const char *name;
+	const char **groups;
+	unsigned num_groups;
+};
+
+struct mvebu_pinctrl_group {
+	const char *name;
+	struct mvebu_mpp_ctrl *ctrl;
+	struct mvebu_mpp_ctrl_setting *settings;
+	unsigned num_settings;
+	unsigned gid;
+	unsigned *pins;
+	unsigned npins;
+};
+
+struct mvebu_pinctrl {
+	struct device *dev;
+	struct pinctrl_dev *pctldev;
+	struct pinctrl_desc desc;
+	void __iomem *base;
+	struct mvebu_pinctrl_group *groups;
+	unsigned num_groups;
+	struct mvebu_pinctrl_function *functions;
+	unsigned num_functions;
+	u8 variant;
+};
+
+static struct mvebu_pinctrl_group *mvebu_pinctrl_find_group_by_pid(
+	struct mvebu_pinctrl *pctl, unsigned pid)
+{
+	unsigned n;
+	for (n = 0; n < pctl->num_groups; n++) {
+		if (pid >= pctl->groups[n].pins[0] &&
+		    pid < pctl->groups[n].pins[0] +
+			pctl->groups[n].npins)
+			return &pctl->groups[n];
+	}
+	return NULL;
+}
+
+static struct mvebu_pinctrl_group *mvebu_pinctrl_find_group_by_name(
+	struct mvebu_pinctrl *pctl, const char *name)
+{
+	unsigned n;
+	for (n = 0; n < pctl->num_groups; n++) {
+		if (strcmp(name, pctl->groups[n].name) == 0)
+			return &pctl->groups[n];
+	}
+	return NULL;
+}
+
+static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_setting_by_val(
+	struct mvebu_pinctrl *pctl, struct mvebu_pinctrl_group *grp,
+	unsigned long config)
+{
+	unsigned n;
+	for (n = 0; n < grp->num_settings; n++) {
+		if (config == grp->settings[n].val) {
+			if (!pctl->variant || (pctl->variant &
+					       grp->settings[n].variant))
+				return &grp->settings[n];
+		}
+	}
+	return NULL;
+}
+
+static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_setting_by_name(
+	struct mvebu_pinctrl *pctl, struct mvebu_pinctrl_group *grp,
+	const char *name)
+{
+	unsigned n;
+	for (n = 0; n < grp->num_settings; n++) {
+		if (strcmp(name, grp->settings[n].name) == 0) {
+			if (!pctl->variant || (pctl->variant &
+					       grp->settings[n].variant))
+				return &grp->settings[n];
+		}
+	}
+	return NULL;
+}
+
+static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_gpio_setting(
+	struct mvebu_pinctrl *pctl, struct mvebu_pinctrl_group *grp)
+{
+	unsigned n;
+	for (n = 0; n < grp->num_settings; n++) {
+		if (grp->settings[n].flags &
+			(MVEBU_SETTING_GPO | MVEBU_SETTING_GPI)) {
+			if (!pctl->variant || (pctl->variant &
+						grp->settings[n].variant))
+				return &grp->settings[n];
+		}
+	}
+	return NULL;
+}
+
+static struct mvebu_pinctrl_function *mvebu_pinctrl_find_function_by_name(
+	struct mvebu_pinctrl *pctl, const char *name)
+{
+	unsigned n;
+	for (n = 0; n < pctl->num_functions; n++) {
+		if (strcmp(name, pctl->functions[n].name) == 0)
+			return &pctl->functions[n];
+	}
+	return NULL;
+}
+
+/*
+ * Common mpp pin configuration registers on MVEBU are
+ * registers of eight 4-bit values for each mpp setting.
+ * Register offset and bit mask are calculated accordingly below.
+ */
+static int mvebu_common_mpp_get(struct mvebu_pinctrl *pctl,
+				struct mvebu_pinctrl_group *grp,
+				unsigned long *config)
+{
+	unsigned pin = grp->gid;
+	unsigned off = (pin / MPPS_PER_REG) * MPP_BITS;
+	unsigned shift = (pin % MPPS_PER_REG) * MPP_BITS;
+
+	*config = readl(pctl->base + off);
+	*config >>= shift;
+	*config &= MPP_MASK;
+
+	return 0;
+}
+
+static int mvebu_common_mpp_set(struct mvebu_pinctrl *pctl,
+				struct mvebu_pinctrl_group *grp,
+				unsigned long config)
+{
+	unsigned pin = grp->gid;
+	unsigned off = (pin / MPPS_PER_REG) * MPP_BITS;
+	unsigned shift = (pin % MPPS_PER_REG) * MPP_BITS;
+	unsigned long reg;
+
+	reg = readl(pctl->base + off);
+	reg &= ~(MPP_MASK << shift);
+	reg |= (config << shift);
+	writel(reg, pctl->base + off);
+
+	return 0;
+}
+
+static int mvebu_pinconf_group_get(struct pinctrl_dev *pctldev,
+				unsigned gid, unsigned long *config)
+{
+	struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	struct mvebu_pinctrl_group *grp = &pctl->groups[gid];
+
+	if (!grp->ctrl)
+		return -EINVAL;
+
+	if (grp->ctrl->mpp_get)
+		return grp->ctrl->mpp_get(grp->ctrl, config);
+
+	return mvebu_common_mpp_get(pctl, grp, config);
+}
+
+static int mvebu_pinconf_group_set(struct pinctrl_dev *pctldev,
+				unsigned gid, unsigned long config)
+{
+	struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	struct mvebu_pinctrl_group *grp = &pctl->groups[gid];
+
+	if (!grp->ctrl)
+		return -EINVAL;
+
+	if (grp->ctrl->mpp_set)
+		return grp->ctrl->mpp_set(grp->ctrl, config);
+
+	return mvebu_common_mpp_set(pctl, grp, config);
+}
+
+static void mvebu_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
+					struct seq_file *s, unsigned gid)
+{
+	struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	struct mvebu_pinctrl_group *grp = &pctl->groups[gid];
+	struct mvebu_mpp_ctrl_setting *curr;
+	unsigned long config;
+	unsigned n;
+
+	if (mvebu_pinconf_group_get(pctldev, gid, &config))
+		return;
+
+	curr = mvebu_pinctrl_find_setting_by_val(pctl, grp, config);
+
+	if (curr) {
+		seq_printf(s, "current: %s", curr->name);
+		if (curr->subname)
+			seq_printf(s, "(%s)", curr->subname);
+		if (curr->flags & (MVEBU_SETTING_GPO | MVEBU_SETTING_GPI)) {
+			seq_printf(s, "(");
+			if (curr->flags & MVEBU_SETTING_GPI)
+				seq_printf(s, "i");
+			if (curr->flags & MVEBU_SETTING_GPO)
+				seq_printf(s, "o");
+			seq_printf(s, ")");
+		}
+	} else
+		seq_printf(s, "current: UNKNOWN");
+
+	if (grp->num_settings > 1) {
+		seq_printf(s, ", available = [");
+		for (n = 0; n < grp->num_settings; n++) {
+			if (curr == &grp->settings[n])
+				continue;
+
+			/* skip unsupported settings for this variant */
+			if (pctl->variant &&
+			    !(pctl->variant & grp->settings[n].variant))
+				continue;
+
+			seq_printf(s, " %s", grp->settings[n].name);
+			if (grp->settings[n].subname)
+				seq_printf(s, "(%s)", grp->settings[n].subname);
+			if (grp->settings[n].flags &
+				(MVEBU_SETTING_GPO | MVEBU_SETTING_GPI)) {
+				seq_printf(s, "(");
+				if (grp->settings[n].flags & MVEBU_SETTING_GPI)
+					seq_printf(s, "i");
+				if (grp->settings[n].flags & MVEBU_SETTING_GPO)
+					seq_printf(s, "o");
+				seq_printf(s, ")");
+			}
+		}
+		seq_printf(s, " ]");
+	}
+	return;
+}
+
+static struct pinconf_ops mvebu_pinconf_ops = {
+	.pin_config_group_get = mvebu_pinconf_group_get,
+	.pin_config_group_set = mvebu_pinconf_group_set,
+	.pin_config_group_dbg_show = mvebu_pinconf_group_dbg_show,
+};
+
+static int mvebu_pinmux_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+	struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	return pctl->num_functions;
+}
+
+static const char *mvebu_pinmux_get_func_name(struct pinctrl_dev *pctldev,
+					unsigned fid)
+{
+	struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	return pctl->functions[fid].name;
+}
+
+static int mvebu_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned fid,
+				const char * const **groups,
+				unsigned * const num_groups)
+{
+	struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	*groups = pctl->functions[fid].groups;
+	*num_groups = pctl->functions[fid].num_groups;
+	return 0;
+}
+
+static int mvebu_pinmux_enable(struct pinctrl_dev *pctldev, unsigned fid,
+			unsigned gid)
+{
+	struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	struct mvebu_pinctrl_function *func = &pctl->functions[fid];
+	struct mvebu_pinctrl_group *grp = &pctl->groups[gid];
+	struct mvebu_mpp_ctrl_setting *setting;
+	int ret;
+
+	setting = mvebu_pinctrl_find_setting_by_name(pctl, grp,
+						     func->name);
+	if (!setting) {
+		dev_err(pctl->dev,
+			"unable to find setting %s in group %s\n",
+			func->name, func->groups[gid]);
+		return -EINVAL;
+	}
+
+	ret = mvebu_pinconf_group_set(pctldev, grp->gid, setting->val);
+	if (ret) {
+		dev_err(pctl->dev, "cannot set group %s to %s\n",
+			func->groups[gid], func->name);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mvebu_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev,
+			struct pinctrl_gpio_range *range, unsigned offset)
+{
+	struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	struct mvebu_pinctrl_group *grp;
+	struct mvebu_mpp_ctrl_setting *setting;
+
+	grp = mvebu_pinctrl_find_group_by_pid(pctl, offset);
+	if (!grp)
+		return -EINVAL;
+
+	if (grp->ctrl->mpp_gpio_req)
+		return grp->ctrl->mpp_gpio_req(grp->ctrl, offset);
+
+	setting = mvebu_pinctrl_find_gpio_setting(pctl, grp);
+	if (!setting)
+		return -ENOTSUPP;
+
+	return mvebu_pinconf_group_set(pctldev, grp->gid, setting->val);
+}
+
+static int mvebu_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
+	   struct pinctrl_gpio_range *range, unsigned offset, bool input)
+{
+	struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	struct mvebu_pinctrl_group *grp;
+	struct mvebu_mpp_ctrl_setting *setting;
+
+	grp = mvebu_pinctrl_find_group_by_pid(pctl, offset);
+	if (!grp)
+		return -EINVAL;
+
+	if (grp->ctrl->mpp_gpio_dir)
+		return grp->ctrl->mpp_gpio_dir(grp->ctrl, offset, input);
+
+	setting = mvebu_pinctrl_find_gpio_setting(pctl, grp);
+	if (!setting)
+		return -ENOTSUPP;
+
+	if ((input && (setting->flags & MVEBU_SETTING_GPI)) ||
+	    (!input && (setting->flags & MVEBU_SETTING_GPO)))
+		return 0;
+
+	return -ENOTSUPP;
+}
+
+static struct pinmux_ops mvebu_pinmux_ops = {
+	.get_functions_count = mvebu_pinmux_get_funcs_count,
+	.get_function_name = mvebu_pinmux_get_func_name,
+	.get_function_groups = mvebu_pinmux_get_groups,
+	.gpio_request_enable = mvebu_pinmux_gpio_request_enable,
+	.gpio_set_direction = mvebu_pinmux_gpio_set_direction,
+	.enable = mvebu_pinmux_enable,
+};
+
+static int mvebu_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	return pctl->num_groups;
+}
+
+static const char *mvebu_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+						unsigned gid)
+{
+	struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	return pctl->groups[gid].name;
+}
+
+static int mvebu_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+					unsigned gid, const unsigned **pins,
+					unsigned *num_pins)
+{
+	struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	*pins = pctl->groups[gid].pins;
+	*num_pins = pctl->groups[gid].npins;
+	return 0;
+}
+
+static int mvebu_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+					struct device_node *np,
+					struct pinctrl_map **map,
+					unsigned *num_maps)
+{
+	struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	struct property *prop;
+	const char *function;
+	const char *group;
+	int ret, nmaps, n;
+
+	*map = NULL;
+	*num_maps = 0;
+
+	ret = of_property_read_string(np, "marvell,function", &function);
+	if (ret) {
+		dev_err(pctl->dev,
+			"missing marvell,function in node %s\n", np->name);
+		return 0;
+	}
+
+	nmaps = of_property_count_strings(np, "marvell,pins");
+	if (nmaps < 0) {
+		dev_err(pctl->dev,
+			"missing marvell,pins in node %s\n", np->name);
+		return 0;
+	}
+
+	*map = kmalloc(nmaps * sizeof(struct pinctrl_map), GFP_KERNEL);
+	if (map == NULL) {
+		dev_err(pctl->dev,
+			"cannot allocate pinctrl_map memory for %s\n",
+			np->name);
+		return -ENOMEM;
+	}
+
+	n = 0;
+	of_property_for_each_string(np, "marvell,pins", prop, group) {
+		struct mvebu_pinctrl_group *grp =
+			mvebu_pinctrl_find_group_by_name(pctl, group);
+
+		if (!grp) {
+			dev_err(pctl->dev, "unknown pin %s", group);
+			continue;
+		}
+
+		if (!mvebu_pinctrl_find_setting_by_name(pctl, grp, function)) {
+			dev_err(pctl->dev, "unsupported function %s on pin %s",
+				function, group);
+			continue;
+		}
+
+		(*map)[n].type = PIN_MAP_TYPE_MUX_GROUP;
+		(*map)[n].data.mux.group = group;
+		(*map)[n].data.mux.function = function;
+		n++;
+	}
+
+	*num_maps = nmaps;
+
+	return 0;
+}
+
+static void mvebu_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+				struct pinctrl_map *map, unsigned num_maps)
+{
+	kfree(map);
+}
+
+static struct pinctrl_ops mvebu_pinctrl_ops = {
+	.get_groups_count = mvebu_pinctrl_get_groups_count,
+	.get_group_name = mvebu_pinctrl_get_group_name,
+	.get_group_pins = mvebu_pinctrl_get_group_pins,
+	.dt_node_to_map = mvebu_pinctrl_dt_node_to_map,
+	.dt_free_map = mvebu_pinctrl_dt_free_map,
+};
+
+static int __devinit _add_function(struct mvebu_pinctrl_function *funcs,
+				   const char *name)
+{
+	while (funcs->num_groups) {
+		/* function already there */
+		if (strcmp(funcs->name, name) == 0) {
+			funcs->num_groups++;
+			return -EEXIST;
+		}
+		funcs++;
+	}
+	funcs->name = name;
+	funcs->num_groups = 1;
+	return 0;
+}
+
+static int __devinit mvebu_pinctrl_build_functions(struct platform_device *pdev,
+						   struct mvebu_pinctrl *pctl)
+{
+	struct mvebu_pinctrl_function *funcs;
+	int num = 0;
+	int n, s;
+
+	/* we allocate functions for number of pins and hope
+	 * there are less unique functions than pins available */
+	funcs = devm_kzalloc(&pdev->dev, pctl->desc.npins *
+			     sizeof(struct mvebu_pinctrl_function), GFP_KERNEL);
+	if (!funcs)
+		return -ENOMEM;
+
+	for (n = 0; n < pctl->num_groups; n++) {
+		struct mvebu_pinctrl_group *grp = &pctl->groups[n];
+		for (s = 0; s < grp->num_settings; s++) {
+			/* skip unsupported settings on this variant */
+			if (pctl->variant &&
+			    !(pctl->variant & grp->settings[s].variant))
+				continue;
+
+			/* check for unique functions and count groups */
+			if (_add_function(funcs, grp->settings[s].name))
+				continue;
+
+			num++;
+		}
+	}
+
+	/* with the number of unique functions and it's groups known,
+	   reallocate functions and assign group names */
+	funcs = krealloc(funcs, num * sizeof(struct mvebu_pinctrl_function),
+			 GFP_KERNEL);
+	if (!funcs)
+		return -ENOMEM;
+
+	pctl->num_functions = num;
+	pctl->functions = funcs;
+
+	for (n = 0; n < pctl->num_groups; n++) {
+		struct mvebu_pinctrl_group *grp = &pctl->groups[n];
+		for (s = 0; s < grp->num_settings; s++) {
+			struct mvebu_pinctrl_function *f;
+			const char **groups;
+
+			/* skip unsupported settings on this variant */
+			if (pctl->variant &&
+			    !(pctl->variant & grp->settings[s].variant))
+				continue;
+
+			f = mvebu_pinctrl_find_function_by_name(pctl,
+							grp->settings[s].name);
+
+			/* allocate group name array if not done already */
+			if (!f->groups) {
+				f->groups = devm_kzalloc(&pdev->dev,
+						 f->num_groups * sizeof(char *),
+						 GFP_KERNEL);
+				if (!f->groups)
+					return -ENOMEM;
+			}
+
+			/* find next free group name and assign current name */
+			groups = f->groups;
+			while (*groups)
+				groups++;
+			*groups = grp->name;
+		}
+	}
+
+	return 0;
+}
+
+int __devinit mvebu_pinctrl_probe(struct platform_device *pdev)
+{
+	struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev);
+	struct device_node *np = pdev->dev.of_node;
+	struct mvebu_pinctrl *pctl;
+	void __iomem *base;
+	struct pinctrl_pin_desc *pdesc;
+	unsigned gid, n, k;
+	int ret;
+
+	if (!soc || !soc->controls || !soc->modes) {
+		dev_err(&pdev->dev, "wrong pinctrl soc info\n");
+		return -EINVAL;
+	}
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		dev_err(&pdev->dev, "unable to get base address\n");
+		return -ENODEV;
+	}
+
+	pctl = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pinctrl),
+			GFP_KERNEL);
+	if (!pctl) {
+		dev_err(&pdev->dev, "unable to alloc driver\n");
+		return -ENOMEM;
+	}
+
+	pctl->desc.name = dev_name(&pdev->dev);
+	pctl->desc.owner = THIS_MODULE;
+	pctl->desc.pctlops = &mvebu_pinctrl_ops;
+	pctl->desc.pmxops = &mvebu_pinmux_ops;
+	pctl->desc.confops = &mvebu_pinconf_ops;
+	pctl->variant = soc->variant;
+	pctl->base = base;
+	pctl->dev = &pdev->dev;
+	platform_set_drvdata(pdev, pctl);
+
+	/* count controls and create names for mvebu generic
+	   register controls; also does sanity checks */
+	pctl->num_groups = 0;
+	pctl->desc.npins = 0;
+	for (n = 0; n < soc->ncontrols; n++) {
+		struct mvebu_mpp_ctrl *ctrl = &soc->controls[n];
+		char *names;
+
+		pctl->desc.npins += ctrl->npins;
+		/* initial control pins */
+		for (k = 0; k < ctrl->npins; k++)
+			ctrl->pins[k] = ctrl->pid + k;
+
+		/* special soc specific control */
+		if (ctrl->mpp_get || ctrl->mpp_set) {
+			if (!ctrl->name || !ctrl->mpp_set || !ctrl->mpp_set) {
+				dev_err(&pdev->dev, "wrong soc control info\n");
+				return -EINVAL;
+			}
+			pctl->num_groups += 1;
+			continue;
+		}
+
+		/* generic mvebu register control */
+		names = devm_kzalloc(&pdev->dev, ctrl->npins * 8, GFP_KERNEL);
+		if (!names) {
+			dev_err(&pdev->dev, "failed to alloc mpp names\n");
+			return -ENOMEM;
+		}
+		for (k = 0; k < ctrl->npins; k++)
+			sprintf(names + 8*k, "mpp%d", ctrl->pid+k);
+		ctrl->name = names;
+		pctl->num_groups += ctrl->npins;
+	}
+
+	pdesc = devm_kzalloc(&pdev->dev, pctl->desc.npins *
+			     sizeof(struct pinctrl_pin_desc), GFP_KERNEL);
+	if (!pdesc) {
+		dev_err(&pdev->dev, "failed to alloc pinctrl pins\n");
+		return -ENOMEM;
+	}
+
+	for (n = 0; n < pctl->desc.npins; n++)
+		pdesc[n].number = n;
+	pctl->desc.pins = pdesc;
+
+	pctl->groups = devm_kzalloc(&pdev->dev, pctl->num_groups *
+			     sizeof(struct mvebu_pinctrl_group), GFP_KERNEL);
+	if (!pctl->groups) {
+		dev_err(&pdev->dev, "failed to alloc pinctrl groups\n");
+		return -ENOMEM;
+	}
+
+	/* assign mpp controls to groups */
+	gid = 0;
+	for (n = 0; n < soc->ncontrols; n++) {
+		struct mvebu_mpp_ctrl *ctrl = &soc->controls[n];
+		pctl->groups[gid].gid = gid;
+		pctl->groups[gid].ctrl = ctrl;
+		pctl->groups[gid].name = ctrl->name;
+		pctl->groups[gid].pins = ctrl->pins;
+		pctl->groups[gid].npins = ctrl->npins;
+
+		/* generic mvebu register control maps to a number of groups */
+		if (!ctrl->mpp_get && !ctrl->mpp_set) {
+			pctl->groups[gid].npins = 1;
+
+			for (k = 1; k < ctrl->npins; k++) {
+				gid++;
+				pctl->groups[gid].gid = gid;
+				pctl->groups[gid].ctrl = ctrl;
+				pctl->groups[gid].name = &ctrl->name[8*k];
+				pctl->groups[gid].pins = &ctrl->pins[k];
+				pctl->groups[gid].npins = 1;
+			}
+		}
+		gid++;
+	}
+
+	/* assign mpp modes to groups */
+	for (n = 0; n < soc->nmodes; n++) {
+		struct mvebu_mpp_mode *mode = &soc->modes[n];
+		struct mvebu_pinctrl_group *grp =
+			mvebu_pinctrl_find_group_by_pid(pctl, mode->pid);
+		unsigned num_settings;
+
+		if (!grp) {
+			dev_warn(&pdev->dev, "unknown pinctrl group %d\n",
+				mode->pid);
+			continue;
+		}
+
+		for (num_settings = 0; ;) {
+			struct mvebu_mpp_ctrl_setting *set =
+				&mode->settings[num_settings];
+
+			if (!set->name)
+				break;
+			num_settings++;
+
+			/* skip unsupported settings for this variant */
+			if (pctl->variant && !(pctl->variant & set->variant))
+				continue;
+
+			/* find gpio/gpo/gpi settings */
+			if (strcmp(set->name, "gpio") == 0)
+				set->flags = MVEBU_SETTING_GPI |
+					MVEBU_SETTING_GPO;
+			else if (strcmp(set->name, "gpo") == 0)
+				set->flags = MVEBU_SETTING_GPO;
+			else if (strcmp(set->name, "gpi") == 0)
+				set->flags = MVEBU_SETTING_GPI;
+		}
+
+		grp->settings = mode->settings;
+		grp->num_settings = num_settings;
+	}
+
+	ret = mvebu_pinctrl_build_functions(pdev, pctl);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to build functions\n");
+		return ret;
+	}
+
+	pctl->pctldev = pinctrl_register(&pctl->desc, &pdev->dev, pctl);
+	if (!pctl->pctldev) {
+		dev_err(&pdev->dev, "unable to register pinctrl driver\n");
+		return -EINVAL;
+	}
+
+	dev_info(&pdev->dev, "registered pinctrl driver\n");
+
+	/* register gpio ranges */
+	for (n = 0; n < soc->ngpioranges; n++)
+		pinctrl_add_gpio_range(pctl->pctldev, &soc->gpioranges[n]);
+
+	return 0;
+}
+
+int __devexit mvebu_pinctrl_remove(struct platform_device *pdev)
+{
+	struct mvebu_pinctrl *pctl = platform_get_drvdata(pdev);
+	pinctrl_unregister(pctl->pctldev);
+	return 0;
+}

+ 192 - 0
drivers/pinctrl/pinctrl-mvebu.h

@@ -0,0 +1,192 @@
+/*
+ * Marvell MVEBU pinctrl driver
+ *
+ * Authors: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *          Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __PINCTRL_MVEBU_H__
+#define __PINCTRL_MVEBU_H__
+
+/**
+ * struct mvebu_mpp_ctrl - describe a mpp control
+ * @name: name of the control group
+ * @pid: first pin id handled by this control
+ * @npins: number of pins controlled by this control
+ * @mpp_get: (optional) special function to get mpp setting
+ * @mpp_set: (optional) special function to set mpp setting
+ * @mpp_gpio_req: (optional) special function to request gpio
+ * @mpp_gpio_dir: (optional) special function to set gpio direction
+ *
+ * A mpp_ctrl describes a muxable unit, e.g. pin, group of pins, or
+ * internal function, inside the SoC. Each muxable unit can be switched
+ * between two or more different settings, e.g. assign mpp pin 13 to
+ * uart1 or sata.
+ *
+ * If optional mpp_get/_set functions are set these are used to get/set
+ * a specific mode. Otherwise it is assumed that the mpp control is based
+ * on 4-bit groups in subsequent registers. The optional mpp_gpio_req/_dir
+ * functions can be used to allow pin settings with varying gpio pins.
+ */
+struct mvebu_mpp_ctrl {
+	const char *name;
+	u8 pid;
+	u8 npins;
+	unsigned *pins;
+	int (*mpp_get)(struct mvebu_mpp_ctrl *ctrl, unsigned long *config);
+	int (*mpp_set)(struct mvebu_mpp_ctrl *ctrl, unsigned long config);
+	int (*mpp_gpio_req)(struct mvebu_mpp_ctrl *ctrl, u8 pid);
+	int (*mpp_gpio_dir)(struct mvebu_mpp_ctrl *ctrl, u8 pid, bool input);
+};
+
+/**
+ * struct mvebu_mpp_ctrl_setting - describe a mpp ctrl setting
+ * @val: ctrl setting value
+ * @name: ctrl setting name, e.g. uart2, spi0 - unique per mpp_mode
+ * @subname: (optional) additional ctrl setting name, e.g. rts, cts
+ * @variant: (optional) variant identifier mask
+ * @flags: (private) flags to store gpi/gpo/gpio capabilities
+ *
+ * A ctrl_setting describes a specific internal mux function that a mpp pin
+ * can be switched to. The value (val) will be written in the corresponding
+ * register for common mpp pin configuration registers on MVEBU. SoC specific
+ * mpp_get/_set function may use val to distinguish between different settings.
+ *
+ * The name will be used to switch to this setting in DT description, e.g.
+ * marvell,function = "uart2". subname is only for debugging purposes.
+ *
+ * If name is one of "gpi", "gpo", "gpio" gpio capabilities are
+ * parsed during initialization and stored in flags.
+ *
+ * The variant can be used to combine different revisions of one SoC to a
+ * common pinctrl driver. It is matched (AND) with variant of soc_info to
+ * determine if a setting is available on the current SoC revision.
+ */
+struct mvebu_mpp_ctrl_setting {
+	u8 val;
+	const char *name;
+	const char *subname;
+	u8 variant;
+	u8 flags;
+#define  MVEBU_SETTING_GPO	(1 << 0)
+#define  MVEBU_SETTING_GPI	(1 << 1)
+};
+
+/**
+ * struct mvebu_mpp_mode - link ctrl and settings
+ * @pid: first pin id handled by this mode
+ * @settings: list of settings available for this mode
+ *
+ * A mode connects all available settings with the corresponding mpp_ctrl
+ * given by pid.
+ */
+struct mvebu_mpp_mode {
+	u8 pid;
+	struct mvebu_mpp_ctrl_setting *settings;
+};
+
+/**
+ * struct mvebu_pinctrl_soc_info - SoC specific info passed to pinctrl-mvebu
+ * @variant: variant mask of soc_info
+ * @controls: list of available mvebu_mpp_ctrls
+ * @ncontrols: number of available mvebu_mpp_ctrls
+ * @modes: list of available mvebu_mpp_modes
+ * @nmodes: number of available mvebu_mpp_modes
+ * @gpioranges: list of pinctrl_gpio_ranges
+ * @ngpioranges: number of available pinctrl_gpio_ranges
+ *
+ * This struct describes all pinctrl related information for a specific SoC.
+ * If variant is unequal 0 it will be matched (AND) with variant of each
+ * setting and allows to distinguish between different revisions of one SoC.
+ */
+struct mvebu_pinctrl_soc_info {
+	u8 variant;
+	struct mvebu_mpp_ctrl *controls;
+	int ncontrols;
+	struct mvebu_mpp_mode *modes;
+	int nmodes;
+	struct pinctrl_gpio_range *gpioranges;
+	int ngpioranges;
+};
+
+#define MPP_REG_CTRL(_idl, _idh)				\
+	{							\
+		.name = NULL,					\
+		.pid = _idl,					\
+		.npins = _idh - _idl + 1,			\
+		.pins = (unsigned[_idh - _idl + 1]) { },	\
+		.mpp_get = NULL,				\
+		.mpp_set = NULL,				\
+		.mpp_gpio_req = NULL,				\
+		.mpp_gpio_dir = NULL,				\
+	}
+
+#define MPP_FUNC_CTRL(_idl, _idh, _name, _func)			\
+	{							\
+		.name = _name,					\
+		.pid = _idl,					\
+		.npins = _idh - _idl + 1,			\
+		.pins = (unsigned[_idh - _idl + 1]) { },	\
+		.mpp_get = _func ## _get,			\
+		.mpp_set = _func ## _set,			\
+		.mpp_gpio_req = NULL,				\
+		.mpp_gpio_dir = NULL,				\
+	}
+
+#define MPP_FUNC_GPIO_CTRL(_idl, _idh, _name, _func)		\
+	{							\
+		.name = _name,					\
+		.pid = _idl,					\
+		.npins = _idh - _idl + 1,			\
+		.pins = (unsigned[_idh - _idl + 1]) { },	\
+		.mpp_get = _func ## _get,			\
+		.mpp_set = _func ## _set,			\
+		.mpp_gpio_req = _func ## _gpio_req,		\
+		.mpp_gpio_dir = _func ## _gpio_dir,		\
+	}
+
+#define _MPP_VAR_FUNCTION(_val, _name, _subname, _mask)		\
+	{							\
+		.val = _val,					\
+		.name = _name,					\
+		.subname = _subname,				\
+		.variant = _mask,				\
+		.flags = 0,					\
+	}
+
+#if defined(CONFIG_DEBUG_FS)
+#define MPP_VAR_FUNCTION(_val, _name, _subname, _mask)		\
+	_MPP_VAR_FUNCTION(_val, _name, _subname, _mask)
+#else
+#define MPP_VAR_FUNCTION(_val, _name, _subname, _mask)		\
+	_MPP_VAR_FUNCTION(_val, _name, NULL, _mask)
+#endif
+
+#define MPP_FUNCTION(_val, _name, _subname)			\
+	MPP_VAR_FUNCTION(_val, _name, _subname, (u8)-1)
+
+#define MPP_MODE(_id, ...)					\
+	{							\
+		.pid = _id,					\
+		.settings = (struct mvebu_mpp_ctrl_setting[]){	\
+			__VA_ARGS__, { } },			\
+	}
+
+#define MPP_GPIO_RANGE(_id, _pinbase, _gpiobase, _npins)	\
+	{							\
+		.name = "mvebu-gpio",				\
+		.id = _id,					\
+		.pin_base = _pinbase,				\
+		.base = _gpiobase,				\
+		.npins = _npins,				\
+	}
+
+int mvebu_pinctrl_probe(struct platform_device *pdev);
+int mvebu_pinctrl_remove(struct platform_device *pdev);
+
+#endif