Commit c740ae74 authored by Olof Johansson's avatar Olof Johansson

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: default avatarOlof Johansson <olof@lixom.net>
parents 0d601f61 3415b08f
* 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>;
};
* 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)
* 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.
* 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.
* 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)
* 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";
};
};
......@@ -21,6 +21,12 @@ / {
model = "Marvell Armada 370 family SoC";
compatible = "marvell,armada370", "marvell,armada-370-xp";
aliases {
gpio0 = &gpio0;
gpio1 = &gpio1;
gpio2 = &gpio2;
};
mpic: interrupt-controller@d0020000 {
reg = <0xd0020a00 0x1d0>,
<0xd0021870 0x58>;
......@@ -31,5 +37,43 @@ system-controller@d0018200 {
compatible = "marvell,armada-370-xp-system-controller";
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>;
};
};
};
......@@ -14,11 +14,11 @@
*/
/dts-v1/;
/include/ "armada-xp.dtsi"
/include/ "armada-xp-mv78460.dtsi"
/ {
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 {
bootargs = "console=ttyS0,115200 earlyprintk";
......
/*
* 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>;
};
};
};
/*
* 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>;
};
};
};
/*
* 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>;
};
};
};
......@@ -21,6 +21,8 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_FS_XATTR is not set
......
......@@ -13,13 +13,25 @@ if ARCH_MVEBU
menu "Marvell SOC with device tree"
config MACH_ARMADA_370_XP
bool "Marvell Armada 370 and Aramada XP boards"
bool
select ARMADA_370_XP_TIMER
select CPU_V7
config MACH_ARMADA_370
bool "Marvell Armada 370 boards"
select MACH_ARMADA_370_XP
select PINCTRL_ARMADA_370
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
......
......@@ -150,6 +150,12 @@ config GPIO_MSM_V2
Qualcomm MSM chips. Most of the pins on the MSM can be
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
def_bool y
depends on ARCH_MXC
......
......@@ -41,6 +41,7 @@ obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o
obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o
obj-$(CONFIG_GPIO_MSM_V1) += gpio-msm-v1.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_MXS) += gpio-mxs.o
obj-$(CONFIG_ARCH_OMAP) += gpio-omap.o
......
/*
* 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);
......@@ -145,6 +145,28 @@ config PINCTRL_COH901
COH 901 335 and COH 901 571/3. They contain 3, 5 or 7
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"
endmenu
......
......@@ -29,5 +29,10 @@ obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o
obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o
obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.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/
/*
* 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");
/*
* 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");
/*
* 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");
/*
* 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");
/*
* 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;
}
/*
* 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment