diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-09-26 21:00:25 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-09-26 21:00:25 +0200 |
commit | 075dbe9f6e3c21596c5245826a4ee1f1c1676eb8 (patch) | |
tree | 6539cf3902bf7b882211ee1917a132b2642c5790 /drivers | |
parent | Merge tag 'asm-generic-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git... (diff) | |
parent | dt-bindings: gpio: ep9301: Add missing "#interrupt-cells" to examples (diff) | |
download | linux-075dbe9f6e3c21596c5245826a4ee1f1c1676eb8.tar.xz linux-075dbe9f6e3c21596c5245826a4ee1f1c1676eb8.zip |
Merge tag 'soc-ep93xx-dt-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull SoC update from Arnd Bergmann:
"Convert ep93xx to devicetree
This concludes a long journey towards replacing the old board files
with devictree description on the Cirrus Logic EP93xx platform.
Nikita Shubin has been working on this for a long time, for details
see the last post on
https://lore.kernel.org/lkml/20240909-ep93xx-v12-0-e86ab2423d4b@maquefel.me/"
* tag 'soc-ep93xx-dt-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (47 commits)
dt-bindings: gpio: ep9301: Add missing "#interrupt-cells" to examples
MAINTAINERS: Update EP93XX ARM ARCHITECTURE maintainer
soc: ep93xx: drop reference to removed EP93XX_SOC_COMMON config
net: cirrus: use u8 for addr to calm down sparse
dmaengine: cirrus: use snprintf() to calm down gcc 13.3.0
dmaengine: ep93xx: Fix a NULL vs IS_ERR() check in probe()
pinctrl: ep93xx: Fix raster pins typo
spi: ep93xx: update kerneldoc comments for ep93xx_spi
clk: ep93xx: Fix off by one in ep93xx_div_recalc_rate()
clk: ep93xx: add module license
dmaengine: cirrus: remove platform code
ASoC: cirrus: edb93xx: Delete driver
ARM: ep93xx: soc: drop defines
ARM: ep93xx: delete all boardfiles
ata: pata_ep93xx: remove legacy pinctrl use
pwm: ep93xx: drop legacy pinctrl
ARM: ep93xx: DT for the Cirrus ep93xx SoC platforms
ARM: dts: ep93xx: Add EDB9302 DT
ARM: dts: ep93xx: add ts7250 board
ARM: dts: add Cirrus EP93XX SoC .dtsi
...
Diffstat (limited to 'drivers')
25 files changed, 3405 insertions, 473 deletions
diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c index a34e56a9d535..f3f5b2b0ecc9 100644 --- a/drivers/ata/pata_ep93xx.c +++ b/drivers/ata/pata_ep93xx.c @@ -44,8 +44,8 @@ #include <linux/delay.h> #include <linux/dmaengine.h> #include <linux/ktime.h> +#include <linux/mod_devicetable.h> -#include <linux/platform_data/dma-ep93xx.h> #include <linux/soc/cirrus/ep93xx.h> #define DRV_NAME "ep93xx-ide" @@ -126,7 +126,7 @@ enum { }; struct ep93xx_pata_data { - const struct platform_device *pdev; + struct platform_device *pdev; void __iomem *ide_base; struct ata_timing t; bool iordy; @@ -135,9 +135,7 @@ struct ep93xx_pata_data { unsigned long udma_out_phys; struct dma_chan *dma_rx_channel; - struct ep93xx_dma_data dma_rx_data; struct dma_chan *dma_tx_channel; - struct ep93xx_dma_data dma_tx_data; }; static void ep93xx_pata_clear_regs(void __iomem *base) @@ -637,20 +635,13 @@ static void ep93xx_pata_release_dma(struct ep93xx_pata_data *drv_data) } } -static bool ep93xx_pata_dma_filter(struct dma_chan *chan, void *filter_param) +static int ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data) { - if (ep93xx_dma_chan_is_m2p(chan)) - return false; - - chan->private = filter_param; - return true; -} - -static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data) -{ - const struct platform_device *pdev = drv_data->pdev; + struct platform_device *pdev = drv_data->pdev; + struct device *dev = &pdev->dev; dma_cap_mask_t mask; struct dma_slave_config conf; + int ret; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); @@ -660,22 +651,16 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data) * to request only one channel, and reprogram it's direction at * start of new transfer. */ - drv_data->dma_rx_data.port = EP93XX_DMA_IDE; - drv_data->dma_rx_data.direction = DMA_DEV_TO_MEM; - drv_data->dma_rx_data.name = "ep93xx-pata-rx"; - drv_data->dma_rx_channel = dma_request_channel(mask, - ep93xx_pata_dma_filter, &drv_data->dma_rx_data); - if (!drv_data->dma_rx_channel) - return; - - drv_data->dma_tx_data.port = EP93XX_DMA_IDE; - drv_data->dma_tx_data.direction = DMA_MEM_TO_DEV; - drv_data->dma_tx_data.name = "ep93xx-pata-tx"; - drv_data->dma_tx_channel = dma_request_channel(mask, - ep93xx_pata_dma_filter, &drv_data->dma_tx_data); - if (!drv_data->dma_tx_channel) { - dma_release_channel(drv_data->dma_rx_channel); - return; + drv_data->dma_rx_channel = dma_request_chan(dev, "rx"); + if (IS_ERR(drv_data->dma_rx_channel)) + return dev_err_probe(dev, PTR_ERR(drv_data->dma_rx_channel), + "rx DMA setup failed\n"); + + drv_data->dma_tx_channel = dma_request_chan(&pdev->dev, "tx"); + if (IS_ERR(drv_data->dma_tx_channel)) { + ret = dev_err_probe(dev, PTR_ERR(drv_data->dma_tx_channel), + "tx DMA setup failed\n"); + goto fail_release_rx; } /* Configure receive channel direction and source address */ @@ -683,10 +668,10 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data) conf.direction = DMA_DEV_TO_MEM; conf.src_addr = drv_data->udma_in_phys; conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - if (dmaengine_slave_config(drv_data->dma_rx_channel, &conf)) { - dev_err(&pdev->dev, "failed to configure rx dma channel\n"); - ep93xx_pata_release_dma(drv_data); - return; + ret = dmaengine_slave_config(drv_data->dma_rx_channel, &conf); + if (ret) { + dev_err_probe(dev, ret, "failed to configure rx dma channel"); + goto fail_release_dma; } /* Configure transmit channel direction and destination address */ @@ -694,10 +679,20 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data) conf.direction = DMA_MEM_TO_DEV; conf.dst_addr = drv_data->udma_out_phys; conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - if (dmaengine_slave_config(drv_data->dma_tx_channel, &conf)) { - dev_err(&pdev->dev, "failed to configure tx dma channel\n"); - ep93xx_pata_release_dma(drv_data); + ret = dmaengine_slave_config(drv_data->dma_tx_channel, &conf); + if (ret) { + dev_err_probe(dev, ret, "failed to configure tx dma channel"); + goto fail_release_dma; } + + return 0; + +fail_release_rx: + dma_release_channel(drv_data->dma_rx_channel); +fail_release_dma: + ep93xx_pata_release_dma(drv_data); + + return ret; } static void ep93xx_pata_dma_start(struct ata_queued_cmd *qc) @@ -925,34 +920,26 @@ static int ep93xx_pata_probe(struct platform_device *pdev) void __iomem *ide_base; int err; - err = ep93xx_ide_acquire_gpio(pdev); - if (err) - return err; - /* INT[3] (IRQ_EP93XX_EXT3) line connected as pull down */ irq = platform_get_irq(pdev, 0); - if (irq < 0) { - err = irq; - goto err_rel_gpio; - } + if (irq < 0) + return irq; ide_base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res); - if (IS_ERR(ide_base)) { - err = PTR_ERR(ide_base); - goto err_rel_gpio; - } + if (IS_ERR(ide_base)) + return PTR_ERR(ide_base); drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL); - if (!drv_data) { - err = -ENOMEM; - goto err_rel_gpio; - } + if (!drv_data) + return -ENOMEM; drv_data->pdev = pdev; drv_data->ide_base = ide_base; drv_data->udma_in_phys = mem_res->start + IDEUDMADATAIN; drv_data->udma_out_phys = mem_res->start + IDEUDMADATAOUT; - ep93xx_pata_dma_init(drv_data); + err = ep93xx_pata_dma_init(drv_data); + if (err) + return err; /* allocate host */ host = ata_host_alloc(&pdev->dev, 1); @@ -1003,8 +990,6 @@ static int ep93xx_pata_probe(struct platform_device *pdev) err_rel_dma: ep93xx_pata_release_dma(drv_data); -err_rel_gpio: - ep93xx_ide_release_gpio(pdev); return err; } @@ -1016,12 +1001,18 @@ static void ep93xx_pata_remove(struct platform_device *pdev) ata_host_detach(host); ep93xx_pata_release_dma(drv_data); ep93xx_pata_clear_regs(drv_data->ide_base); - ep93xx_ide_release_gpio(pdev); } +static const struct of_device_id ep93xx_pata_of_ids[] = { + { .compatible = "cirrus,ep9312-pata" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ep93xx_pata_of_ids); + static struct platform_driver ep93xx_pata_platform_driver = { .driver = { .name = DRV_NAME, + .of_match_table = ep93xx_pata_of_ids, }, .probe = ep93xx_pata_probe, .remove_new = ep93xx_pata_remove, diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 260961668e48..299bc678ed1b 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -218,6 +218,14 @@ config COMMON_CLK_EN7523 This driver provides the fixed clocks and gates present on Airoha ARM silicon. +config COMMON_CLK_EP93XX + tristate "Clock driver for Cirrus Logic ep93xx SoC" + depends on ARCH_EP93XX || COMPILE_TEST + select AUXILIARY_BUS + select REGMAP_MMIO + help + This driver supports the SoC clocks on the Cirrus Logic ep93xx. + config COMMON_CLK_FSL_FLEXSPI tristate "Clock driver for FlexSPI on Layerscape SoCs" depends on ARCH_LAYERSCAPE || COMPILE_TEST diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 9b783c3e5d2f..fb8878a5d7d9 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o +obj-$(CONFIG_COMMON_CLK_EP93XX) += clk-ep93xx.o obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o obj-$(CONFIG_COMMON_CLK_EN7523) += clk-en7523.o obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o diff --git a/drivers/clk/clk-ep93xx.c b/drivers/clk/clk-ep93xx.c new file mode 100644 index 000000000000..f888aed79b11 --- /dev/null +++ b/drivers/clk/clk-ep93xx.c @@ -0,0 +1,850 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Clock control for Cirrus EP93xx chips. + * Copyright (C) 2021 Nikita Shubin <nikita.shubin@maquefel.me> + * + * Based on a rewrite of arch/arm/mach-ep93xx/clock.c: + * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> + */ +#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt + +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/clk-provider.h> +#include <linux/math.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/spinlock.h> + +#include <linux/soc/cirrus/ep93xx.h> +#include <dt-bindings/clock/cirrus,ep9301-syscon.h> + +#include <asm/div64.h> + +#define EP93XX_EXT_CLK_RATE 14745600 +#define EP93XX_EXT_RTC_RATE 32768 + +#define EP93XX_SYSCON_POWER_STATE 0x00 +#define EP93XX_SYSCON_PWRCNT 0x04 +#define EP93XX_SYSCON_PWRCNT_UARTBAUD BIT(29) +#define EP93XX_SYSCON_PWRCNT_USH_EN 28 +#define EP93XX_SYSCON_PWRCNT_DMA_M2M1 27 +#define EP93XX_SYSCON_PWRCNT_DMA_M2M0 26 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P8 25 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P9 24 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P6 23 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P7 22 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P4 21 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P5 20 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P2 19 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P3 18 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P0 17 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P1 16 +#define EP93XX_SYSCON_CLKSET1 0x20 +#define EP93XX_SYSCON_CLKSET1_NBYP1 BIT(23) +#define EP93XX_SYSCON_CLKSET2 0x24 +#define EP93XX_SYSCON_CLKSET2_NBYP2 BIT(19) +#define EP93XX_SYSCON_CLKSET2_PLL2_EN BIT(18) +#define EP93XX_SYSCON_DEVCFG 0x80 +#define EP93XX_SYSCON_DEVCFG_U3EN 24 +#define EP93XX_SYSCON_DEVCFG_U2EN 20 +#define EP93XX_SYSCON_DEVCFG_U1EN 18 +#define EP93XX_SYSCON_VIDCLKDIV 0x84 +#define EP93XX_SYSCON_CLKDIV_ENABLE 15 +#define EP93XX_SYSCON_CLKDIV_ESEL BIT(14) +#define EP93XX_SYSCON_CLKDIV_PSEL BIT(13) +#define EP93XX_SYSCON_CLKDIV_MASK GENMASK(14, 13) +#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT 8 +#define EP93XX_SYSCON_I2SCLKDIV 0x8c +#define EP93XX_SYSCON_I2SCLKDIV_SENA 31 +#define EP93XX_SYSCON_I2SCLKDIV_ORIDE BIT(29) +#define EP93XX_SYSCON_I2SCLKDIV_SPOL BIT(19) +#define EP93XX_SYSCON_KEYTCHCLKDIV 0x90 +#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN 31 +#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV 16 +#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN 15 +#define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV 0 +#define EP93XX_SYSCON_CHIPID 0x94 +#define EP93XX_SYSCON_CHIPID_ID 0x9213 + +#define EP93XX_FIXED_CLK_COUNT 21 + +static const char ep93xx_adc_divisors[] = { 16, 4 }; +static const char ep93xx_sclk_divisors[] = { 2, 4 }; +static const char ep93xx_lrclk_divisors[] = { 32, 64, 128 }; + +struct ep93xx_clk { + struct clk_hw hw; + u16 idx; + u16 reg; + u32 mask; + u8 bit_idx; + u8 shift; + u8 width; + u8 num_div; + const char *div; +}; + +struct ep93xx_clk_priv { + spinlock_t lock; + struct ep93xx_regmap_adev *aux_dev; + struct device *dev; + void __iomem *base; + struct regmap *map; + struct clk_hw *fixed[EP93XX_FIXED_CLK_COUNT]; + struct ep93xx_clk reg[]; +}; + +static struct ep93xx_clk *ep93xx_clk_from(struct clk_hw *hw) +{ + return container_of(hw, struct ep93xx_clk, hw); +} + +static struct ep93xx_clk_priv *ep93xx_priv_from(struct ep93xx_clk *clk) +{ + return container_of(clk, struct ep93xx_clk_priv, reg[clk->idx]); +} + +static void ep93xx_clk_write(struct ep93xx_clk_priv *priv, unsigned int reg, unsigned int val) +{ + struct ep93xx_regmap_adev *aux = priv->aux_dev; + + aux->write(aux->map, aux->lock, reg, val); +} + +static int ep93xx_clk_is_enabled(struct clk_hw *hw) +{ + struct ep93xx_clk *clk = ep93xx_clk_from(hw); + struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); + u32 val; + + regmap_read(priv->map, clk->reg, &val); + + return !!(val & BIT(clk->bit_idx)); +} + +static int ep93xx_clk_enable(struct clk_hw *hw) +{ + struct ep93xx_clk *clk = ep93xx_clk_from(hw); + struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); + u32 val; + + guard(spinlock_irqsave)(&priv->lock); + + regmap_read(priv->map, clk->reg, &val); + val |= BIT(clk->bit_idx); + + ep93xx_clk_write(priv, clk->reg, val); + + return 0; +} + +static void ep93xx_clk_disable(struct clk_hw *hw) +{ + struct ep93xx_clk *clk = ep93xx_clk_from(hw); + struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); + u32 val; + + guard(spinlock_irqsave)(&priv->lock); + + regmap_read(priv->map, clk->reg, &val); + val &= ~BIT(clk->bit_idx); + + ep93xx_clk_write(priv, clk->reg, val); +} + +static const struct clk_ops clk_ep93xx_gate_ops = { + .enable = ep93xx_clk_enable, + .disable = ep93xx_clk_disable, + .is_enabled = ep93xx_clk_is_enabled, +}; + +static int ep93xx_clk_register_gate(struct ep93xx_clk *clk, + const char *name, + struct clk_parent_data *parent_data, + unsigned long flags, + unsigned int reg, + u8 bit_idx) +{ + struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); + struct clk_init_data init = { }; + + init.name = name; + init.ops = &clk_ep93xx_gate_ops; + init.flags = flags; + init.parent_data = parent_data; + init.num_parents = 1; + + clk->reg = reg; + clk->bit_idx = bit_idx; + clk->hw.init = &init; + + return devm_clk_hw_register(priv->dev, &clk->hw); +} + +static u8 ep93xx_mux_get_parent(struct clk_hw *hw) +{ + struct ep93xx_clk *clk = ep93xx_clk_from(hw); + struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); + u32 val; + + regmap_read(priv->map, clk->reg, &val); + + val &= EP93XX_SYSCON_CLKDIV_MASK; + + switch (val) { + case EP93XX_SYSCON_CLKDIV_ESEL: + return 1; /* PLL1 */ + case EP93XX_SYSCON_CLKDIV_MASK: + return 2; /* PLL2 */ + default: + return 0; /* XTALI */ + }; +} + +static int ep93xx_mux_set_parent_lock(struct clk_hw *hw, u8 index) +{ + struct ep93xx_clk *clk = ep93xx_clk_from(hw); + struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); + u32 val; + + if (index >= 3) + return -EINVAL; + + guard(spinlock_irqsave)(&priv->lock); + + regmap_read(priv->map, clk->reg, &val); + val &= ~(EP93XX_SYSCON_CLKDIV_MASK); + val |= index > 0 ? EP93XX_SYSCON_CLKDIV_ESEL : 0; + val |= index > 1 ? EP93XX_SYSCON_CLKDIV_PSEL : 0; + + ep93xx_clk_write(priv, clk->reg, val); + + return 0; +} + +static bool is_best(unsigned long rate, unsigned long now, + unsigned long best) +{ + return abs_diff(rate, now) < abs_diff(rate, best); +} + +static int ep93xx_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + unsigned long best_rate = 0, actual_rate, mclk_rate; + unsigned long rate = req->rate; + struct clk_hw *parent_best = NULL; + unsigned long parent_rate_best; + unsigned long parent_rate; + int div, pdiv; + unsigned int i; + + /* + * Try the two pll's and the external clock, + * because the valid predividers are 2, 2.5 and 3, we multiply + * all the clocks by 2 to avoid floating point math. + * + * This is based on the algorithm in the ep93xx raster guide: + * http://be-a-maverick.com/en/pubs/appNote/AN269REV1.pdf + * + */ + for (i = 0; i < clk_hw_get_num_parents(hw); i++) { + struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i); + + parent_rate = clk_hw_get_rate(parent); + mclk_rate = parent_rate * 2; + + /* Try each predivider value */ + for (pdiv = 4; pdiv <= 6; pdiv++) { + div = DIV_ROUND_CLOSEST(mclk_rate, rate * pdiv); + if (!in_range(div, 1, 127)) + continue; + + actual_rate = DIV_ROUND_CLOSEST(mclk_rate, pdiv * div); + if (is_best(rate, actual_rate, best_rate)) { + best_rate = actual_rate; + parent_rate_best = parent_rate; + parent_best = parent; + } + } + } + + if (!parent_best) + return -EINVAL; + + req->best_parent_rate = parent_rate_best; + req->best_parent_hw = parent_best; + req->rate = best_rate; + + return 0; +} + +static unsigned long ep93xx_ddiv_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct ep93xx_clk *clk = ep93xx_clk_from(hw); + struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); + unsigned int pdiv, div; + u32 val; + + regmap_read(priv->map, clk->reg, &val); + pdiv = (val >> EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) & GENMASK(1, 0); + div = val & GENMASK(6, 0); + if (!div) + return 0; + + return DIV_ROUND_CLOSEST(parent_rate * 2, (pdiv + 3) * div); +} + +static int ep93xx_ddiv_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct ep93xx_clk *clk = ep93xx_clk_from(hw); + struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); + int pdiv, div, npdiv, ndiv; + unsigned long actual_rate, mclk_rate, rate_err = ULONG_MAX; + u32 val; + + regmap_read(priv->map, clk->reg, &val); + mclk_rate = parent_rate * 2; + + for (pdiv = 4; pdiv <= 6; pdiv++) { + div = DIV_ROUND_CLOSEST(mclk_rate, rate * pdiv); + if (!in_range(div, 1, 127)) + continue; + + actual_rate = DIV_ROUND_CLOSEST(mclk_rate, pdiv * div); + if (abs(actual_rate - rate) < rate_err) { + npdiv = pdiv - 3; + ndiv = div; + rate_err = abs(actual_rate - rate); + } + } + + if (rate_err == ULONG_MAX) + return -EINVAL; + + /* + * Clear old dividers. + * Bit 7 is reserved bit in all ClkDiv registers. + */ + val &= ~(GENMASK(9, 0) & ~BIT(7)); + + /* Set the new pdiv and div bits for the new clock rate */ + val |= (npdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | ndiv; + + ep93xx_clk_write(priv, clk->reg, val); + + return 0; +} + +static const struct clk_ops clk_ddiv_ops = { + .enable = ep93xx_clk_enable, + .disable = ep93xx_clk_disable, + .is_enabled = ep93xx_clk_is_enabled, + .get_parent = ep93xx_mux_get_parent, + .set_parent = ep93xx_mux_set_parent_lock, + .determine_rate = ep93xx_mux_determine_rate, + .recalc_rate = ep93xx_ddiv_recalc_rate, + .set_rate = ep93xx_ddiv_set_rate, +}; + +static int ep93xx_clk_register_ddiv(struct ep93xx_clk *clk, + const char *name, + struct clk_parent_data *parent_data, + u8 num_parents, + unsigned int reg, + u8 bit_idx) +{ + struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); + struct clk_init_data init = { }; + + init.name = name; + init.ops = &clk_ddiv_ops; + init.flags = 0; + init.parent_data = parent_data; + init.num_parents = num_parents; + + clk->reg = reg; + clk->bit_idx = bit_idx; + clk->hw.init = &init; + + return devm_clk_hw_register(priv->dev, &clk->hw); +} + +static unsigned long ep93xx_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct ep93xx_clk *clk = ep93xx_clk_from(hw); + struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); + u32 val; + u8 index; + + regmap_read(priv->map, clk->reg, &val); + index = (val & clk->mask) >> clk->shift; + if (index >= clk->num_div) + return 0; + + return DIV_ROUND_CLOSEST(parent_rate, clk->div[index]); +} + +static long ep93xx_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct ep93xx_clk *clk = ep93xx_clk_from(hw); + unsigned long best = 0, now; + unsigned int i; + + for (i = 0; i < clk->num_div; i++) { + if ((rate * clk->div[i]) == *parent_rate) + return rate; + + now = DIV_ROUND_CLOSEST(*parent_rate, clk->div[i]); + if (!best || is_best(rate, now, best)) + best = now; + } + + return best; +} + +static int ep93xx_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct ep93xx_clk *clk = ep93xx_clk_from(hw); + struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); + unsigned int i; + u32 val; + + regmap_read(priv->map, clk->reg, &val); + val &= ~clk->mask; + for (i = 0; i < clk->num_div; i++) + if (rate == DIV_ROUND_CLOSEST(parent_rate, clk->div[i])) + break; + + if (i == clk->num_div) + return -EINVAL; + + val |= i << clk->shift; + + ep93xx_clk_write(priv, clk->reg, val); + + return 0; +} + +static const struct clk_ops ep93xx_div_ops = { + .enable = ep93xx_clk_enable, + .disable = ep93xx_clk_disable, + .is_enabled = ep93xx_clk_is_enabled, + .recalc_rate = ep93xx_div_recalc_rate, + .round_rate = ep93xx_div_round_rate, + .set_rate = ep93xx_div_set_rate, +}; + +static int ep93xx_register_div(struct ep93xx_clk *clk, + const char *name, + const struct clk_parent_data *parent_data, + unsigned int reg, + u8 enable_bit, + u8 shift, + u8 width, + const char *clk_divisors, + u8 num_div) +{ + struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk); + struct clk_init_data init = { }; + + init.name = name; + init.ops = &ep93xx_div_ops; + init.flags = 0; + init.parent_data = parent_data; + init.num_parents = 1; + + clk->reg = reg; + clk->bit_idx = enable_bit; + clk->mask = GENMASK(shift + width - 1, shift); + clk->shift = shift; + clk->div = clk_divisors; + clk->num_div = num_div; + clk->hw.init = &init; + + return devm_clk_hw_register(priv->dev, &clk->hw); +} + +struct ep93xx_gate { + unsigned int idx; + unsigned int bit; + const char *name; +}; + +static const struct ep93xx_gate ep93xx_uarts[] = { + { EP93XX_CLK_UART1, EP93XX_SYSCON_DEVCFG_U1EN, "uart1" }, + { EP93XX_CLK_UART2, EP93XX_SYSCON_DEVCFG_U2EN, "uart2" }, + { EP93XX_CLK_UART3, EP93XX_SYSCON_DEVCFG_U3EN, "uart3" }, +}; + +static int ep93xx_uart_clock_init(struct ep93xx_clk_priv *priv) +{ + struct clk_parent_data parent_data = { }; + unsigned int i, idx, ret, clk_uart_div; + struct ep93xx_clk *clk; + u32 val; + + regmap_read(priv->map, EP93XX_SYSCON_PWRCNT, &val); + if (val & EP93XX_SYSCON_PWRCNT_UARTBAUD) + clk_uart_div = 1; + else + clk_uart_div = 2; + + priv->fixed[EP93XX_CLK_UART] = + devm_clk_hw_register_fixed_factor_index(priv->dev, "uart", + 0, /* XTALI external clock */ + 0, 1, clk_uart_div); + parent_data.hw = priv->fixed[EP93XX_CLK_UART]; + + /* parenting uart gate clocks to uart clock */ + for (i = 0; i < ARRAY_SIZE(ep93xx_uarts); i++) { + idx = ep93xx_uarts[i].idx - EP93XX_CLK_UART1; + clk = &priv->reg[idx]; + clk->idx = idx; + ret = ep93xx_clk_register_gate(clk, + ep93xx_uarts[i].name, + &parent_data, CLK_SET_RATE_PARENT, + EP93XX_SYSCON_DEVCFG, + ep93xx_uarts[i].bit); + if (ret) + return dev_err_probe(priv->dev, ret, + "failed to register uart[%d] clock\n", i); + } + + return 0; +} + +static const struct ep93xx_gate ep93xx_dmas[] = { + { EP93XX_CLK_M2M0, EP93XX_SYSCON_PWRCNT_DMA_M2M0, "m2m0" }, + { EP93XX_CLK_M2M1, EP93XX_SYSCON_PWRCNT_DMA_M2M1, "m2m1" }, + { EP93XX_CLK_M2P0, EP93XX_SYSCON_PWRCNT_DMA_M2P0, "m2p0" }, + { EP93XX_CLK_M2P1, EP93XX_SYSCON_PWRCNT_DMA_M2P1, "m2p1" }, + { EP93XX_CLK_M2P2, EP93XX_SYSCON_PWRCNT_DMA_M2P2, "m2p2" }, + { EP93XX_CLK_M2P3, EP93XX_SYSCON_PWRCNT_DMA_M2P3, "m2p3" }, + { EP93XX_CLK_M2P4, EP93XX_SYSCON_PWRCNT_DMA_M2P4, "m2p4" }, + { EP93XX_CLK_M2P5, EP93XX_SYSCON_PWRCNT_DMA_M2P5, "m2p5" }, + { EP93XX_CLK_M2P6, EP93XX_SYSCON_PWRCNT_DMA_M2P6, "m2p6" }, + { EP93XX_CLK_M2P7, EP93XX_SYSCON_PWRCNT_DMA_M2P7, "m2p7" }, + { EP93XX_CLK_M2P8, EP93XX_SYSCON_PWRCNT_DMA_M2P8, "m2p8" }, + { EP93XX_CLK_M2P9, EP93XX_SYSCON_PWRCNT_DMA_M2P9, "m2p9" }, +}; + +static int ep93xx_dma_clock_init(struct ep93xx_clk_priv *priv) +{ + struct clk_parent_data parent_data = { }; + unsigned int i, idx; + + parent_data.hw = priv->fixed[EP93XX_CLK_HCLK]; + for (i = 0; i < ARRAY_SIZE(ep93xx_dmas); i++) { + idx = ep93xx_dmas[i].idx; + priv->fixed[idx] = devm_clk_hw_register_gate_parent_data(priv->dev, + ep93xx_dmas[i].name, + &parent_data, 0, + priv->base + EP93XX_SYSCON_PWRCNT, + ep93xx_dmas[i].bit, + 0, + &priv->lock); + if (IS_ERR(priv->fixed[idx])) + return PTR_ERR(priv->fixed[idx]); + } + + return 0; +} + +static struct clk_hw *of_clk_ep93xx_get(struct of_phandle_args *clkspec, void *data) +{ + struct ep93xx_clk_priv *priv = data; + unsigned int idx = clkspec->args[0]; + + if (idx < EP93XX_CLK_UART1) + return priv->fixed[idx]; + + if (idx <= EP93XX_CLK_I2S_LRCLK) + return &priv->reg[idx - EP93XX_CLK_UART1].hw; + + return ERR_PTR(-EINVAL); +} + +/* + * PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS + */ +static unsigned long calc_pll_rate(u64 rate, u32 config_word) +{ + rate *= ((config_word >> 11) & GENMASK(4, 0)) + 1; /* X1FBD */ + rate *= ((config_word >> 5) & GENMASK(5, 0)) + 1; /* X2FBD */ + do_div(rate, (config_word & GENMASK(4, 0)) + 1); /* X2IPD */ + rate >>= (config_word >> 16) & GENMASK(1, 0); /* PS */ + + return rate; +} + +static int ep93xx_plls_init(struct ep93xx_clk_priv *priv) +{ + const char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 }; + const char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 }; + const char pclk_divisors[] = { 1, 2, 4, 8 }; + struct clk_parent_data xtali = { .index = 0 }; + unsigned int clk_f_div, clk_h_div, clk_p_div; + unsigned long clk_pll1_rate, clk_pll2_rate; + struct device *dev = priv->dev; + struct clk_hw *hw, *pll1; + u32 value; + + /* Determine the bootloader configured pll1 rate */ + regmap_read(priv->map, EP93XX_SYSCON_CLKSET1, &value); + + if (value & EP93XX_SYSCON_CLKSET1_NBYP1) + clk_pll1_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value); + else + clk_pll1_rate = EP93XX_EXT_CLK_RATE; + + pll1 = devm_clk_hw_register_fixed_rate_parent_data(dev, "pll1", &xtali, + 0, clk_pll1_rate); + if (IS_ERR(pll1)) + return PTR_ERR(pll1); + + priv->fixed[EP93XX_CLK_PLL1] = pll1; + + /* Initialize the pll1 derived clocks */ + clk_f_div = fclk_divisors[(value >> 25) & GENMASK(2, 0)]; + clk_h_div = hclk_divisors[(value >> 20) & GENMASK(2, 0)]; + clk_p_div = pclk_divisors[(value >> 18) & GENMASK(1, 0)]; + + hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, "fclk", pll1, 0, 1, clk_f_div); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + priv->fixed[EP93XX_CLK_FCLK] = hw; + + hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, "hclk", pll1, 0, 1, clk_h_div); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + priv->fixed[EP93XX_CLK_HCLK] = hw; + + hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, "pclk", hw, 0, 1, clk_p_div); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + priv->fixed[EP93XX_CLK_PCLK] = hw; + + /* Determine the bootloader configured pll2 rate */ + regmap_read(priv->map, EP93XX_SYSCON_CLKSET2, &value); + if (!(value & EP93XX_SYSCON_CLKSET2_NBYP2)) + clk_pll2_rate = EP93XX_EXT_CLK_RATE; + else if (value & EP93XX_SYSCON_CLKSET2_PLL2_EN) + clk_pll2_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value); + else + clk_pll2_rate = 0; + + hw = devm_clk_hw_register_fixed_rate_parent_data(dev, "pll2", &xtali, + 0, clk_pll2_rate); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + priv->fixed[EP93XX_CLK_PLL2] = hw; + + return 0; +} + +static int ep93xx_clk_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct ep93xx_regmap_adev *rdev = to_ep93xx_regmap_adev(adev); + struct clk_parent_data xtali = { .index = 0 }; + struct clk_parent_data ddiv_pdata[3] = { }; + unsigned int clk_spi_div, clk_usb_div; + struct clk_parent_data pdata = {}; + struct device *dev = &adev->dev; + struct ep93xx_clk_priv *priv; + struct ep93xx_clk *clk; + struct clk_hw *hw; + unsigned int idx; + int ret; + u32 value; + + priv = devm_kzalloc(dev, struct_size(priv, reg, 10), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->lock); + priv->dev = dev; + priv->aux_dev = rdev; + priv->map = rdev->map; + priv->base = rdev->base; + + ret = ep93xx_plls_init(priv); + if (ret) + return ret; + + regmap_read(priv->map, EP93XX_SYSCON_CLKSET2, &value); + clk_usb_div = (value >> 28 & GENMASK(3, 0)) + 1; + hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, "usb_clk", + priv->fixed[EP93XX_CLK_PLL2], 0, 1, + clk_usb_div); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + priv->fixed[EP93XX_CLK_USB] = hw; + + ret = ep93xx_uart_clock_init(priv); + if (ret) + return ret; + + ret = ep93xx_dma_clock_init(priv); + if (ret) + return ret; + + clk_spi_div = id->driver_data; + hw = devm_clk_hw_register_fixed_factor_index(dev, "ep93xx-spi.0", + 0, /* XTALI external clock */ + 0, 1, clk_spi_div); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + priv->fixed[EP93XX_CLK_SPI] = hw; + + /* PWM clock */ + hw = devm_clk_hw_register_fixed_factor_index(dev, "pwm_clk", 0, /* XTALI external clock */ + 0, 1, 1); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + priv->fixed[EP93XX_CLK_PWM] = hw; + + /* USB clock */ + pdata.hw = priv->fixed[EP93XX_CLK_USB]; + hw = devm_clk_hw_register_gate_parent_data(priv->dev, "ohci-platform", &pdata, + 0, priv->base + EP93XX_SYSCON_PWRCNT, + EP93XX_SYSCON_PWRCNT_USH_EN, 0, + &priv->lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + priv->fixed[EP93XX_CLK_USB] = hw; + + ddiv_pdata[0].index = 0; /* XTALI external clock */ + ddiv_pdata[1].hw = priv->fixed[EP93XX_CLK_PLL1]; + ddiv_pdata[2].hw = priv->fixed[EP93XX_CLK_PLL2]; + + /* touchscreen/ADC clock */ + idx = EP93XX_CLK_ADC - EP93XX_CLK_UART1; + clk = &priv->reg[idx]; + clk->idx = idx; + ret = ep93xx_register_div(clk, "ep93xx-adc", &xtali, + EP93XX_SYSCON_KEYTCHCLKDIV, + EP93XX_SYSCON_KEYTCHCLKDIV_TSEN, + EP93XX_SYSCON_KEYTCHCLKDIV_ADIV, + 1, + ep93xx_adc_divisors, + ARRAY_SIZE(ep93xx_adc_divisors)); + + + /* keypad clock */ + idx = EP93XX_CLK_KEYPAD - EP93XX_CLK_UART1; + clk = &priv->reg[idx]; + clk->idx = idx; + ret = ep93xx_register_div(clk, "ep93xx-keypad", &xtali, + EP93XX_SYSCON_KEYTCHCLKDIV, + EP93XX_SYSCON_KEYTCHCLKDIV_KEN, + EP93XX_SYSCON_KEYTCHCLKDIV_KDIV, + 1, + ep93xx_adc_divisors, + ARRAY_SIZE(ep93xx_adc_divisors)); + + /* + * On reset PDIV and VDIV is set to zero, while PDIV zero + * means clock disable, VDIV shouldn't be zero. + * So we set both video and i2s dividers to minimum. + * ENA - Enable CLK divider. + * PDIV - 00 - Disable clock + * VDIV - at least 2 + */ + + /* Check and enable video clk registers */ + regmap_read(priv->map, EP93XX_SYSCON_VIDCLKDIV, &value); + value |= BIT(EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2; + ep93xx_clk_write(priv, EP93XX_SYSCON_VIDCLKDIV, value); + + /* Check and enable i2s clk registers */ + regmap_read(priv->map, EP93XX_SYSCON_I2SCLKDIV, &value); + value |= BIT(EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2; + + /* + * Override the SAI_MSTR_CLK_CFG from the I2S block and use the + * I2SClkDiv Register settings. LRCLK transitions on the falling SCLK + * edge. + */ + value |= EP93XX_SYSCON_I2SCLKDIV_ORIDE | EP93XX_SYSCON_I2SCLKDIV_SPOL; + ep93xx_clk_write(priv, EP93XX_SYSCON_I2SCLKDIV, value); + + /* video clk */ + idx = EP93XX_CLK_VIDEO - EP93XX_CLK_UART1; + clk = &priv->reg[idx]; + clk->idx = idx; + ret = ep93xx_clk_register_ddiv(clk, "ep93xx-fb", + ddiv_pdata, ARRAY_SIZE(ddiv_pdata), + EP93XX_SYSCON_VIDCLKDIV, + EP93XX_SYSCON_CLKDIV_ENABLE); + + /* i2s clk */ + idx = EP93XX_CLK_I2S_MCLK - EP93XX_CLK_UART1; + clk = &priv->reg[idx]; + clk->idx = idx; + ret = ep93xx_clk_register_ddiv(clk, "mclk", + ddiv_pdata, ARRAY_SIZE(ddiv_pdata), + EP93XX_SYSCON_I2SCLKDIV, + EP93XX_SYSCON_CLKDIV_ENABLE); + + /* i2s sclk */ + idx = EP93XX_CLK_I2S_SCLK - EP93XX_CLK_UART1; + clk = &priv->reg[idx]; + clk->idx = idx; + pdata.hw = &priv->reg[EP93XX_CLK_I2S_MCLK - EP93XX_CLK_UART1].hw; + ret = ep93xx_register_div(clk, "sclk", &pdata, + EP93XX_SYSCON_I2SCLKDIV, + EP93XX_SYSCON_I2SCLKDIV_SENA, + 16, /* EP93XX_I2SCLKDIV_SDIV_SHIFT */ + 1, /* EP93XX_I2SCLKDIV_SDIV_WIDTH */ + ep93xx_sclk_divisors, + ARRAY_SIZE(ep93xx_sclk_divisors)); + + /* i2s lrclk */ + idx = EP93XX_CLK_I2S_LRCLK - EP93XX_CLK_UART1; + clk = &priv->reg[idx]; + clk->idx = idx; + pdata.hw = &priv->reg[EP93XX_CLK_I2S_SCLK - EP93XX_CLK_UART1].hw; + ret = ep93xx_register_div(clk, "lrclk", &pdata, + EP93XX_SYSCON_I2SCLKDIV, + EP93XX_SYSCON_I2SCLKDIV_SENA, + 17, /* EP93XX_I2SCLKDIV_LRDIV32_SHIFT */ + 2, /* EP93XX_I2SCLKDIV_LRDIV32_WIDTH */ + ep93xx_lrclk_divisors, + ARRAY_SIZE(ep93xx_lrclk_divisors)); + + /* IrDa clk uses same pattern but no init code presents in original clock driver */ + return devm_of_clk_add_hw_provider(priv->dev, of_clk_ep93xx_get, priv); +} + +static const struct auxiliary_device_id ep93xx_clk_ids[] = { + { .name = "soc_ep93xx.clk-ep93xx", .driver_data = 2, }, + { .name = "soc_ep93xx.clk-ep93xx.e2", .driver_data = 1, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(auxiliary, ep93xx_clk_ids); + +static struct auxiliary_driver ep93xx_clk_driver = { + .probe = ep93xx_clk_probe, + .id_table = ep93xx_clk_ids, +}; +module_auxiliary_driver(ep93xx_clk_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nikita Shubin <nikita.shubin@maquefel.me>"); +MODULE_DESCRIPTION("Clock control for Cirrus EP93xx chips"); diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index 4ee337e78c23..995427afe077 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@ -17,14 +17,15 @@ #include <linux/clk.h> #include <linux/init.h> #include <linux/interrupt.h> +#include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/module.h> #include <linux/mod_devicetable.h> +#include <linux/of_dma.h> +#include <linux/overflow.h> #include <linux/platform_device.h> #include <linux/slab.h> -#include <linux/platform_data/dma-ep93xx.h> - #include "dmaengine.h" /* M2P registers */ @@ -104,6 +105,31 @@ #define DMA_MAX_CHAN_BYTES 0xffff #define DMA_MAX_CHAN_DESCRIPTORS 32 +/* + * M2P channels. + * + * Note that these values are also directly used for setting the PPALLOC + * register. + */ +#define EP93XX_DMA_I2S1 0 +#define EP93XX_DMA_I2S2 1 +#define EP93XX_DMA_AAC1 2 +#define EP93XX_DMA_AAC2 3 +#define EP93XX_DMA_AAC3 4 +#define EP93XX_DMA_I2S3 5 +#define EP93XX_DMA_UART1 6 +#define EP93XX_DMA_UART2 7 +#define EP93XX_DMA_UART3 8 +#define EP93XX_DMA_IRDA 9 +/* M2M channels */ +#define EP93XX_DMA_SSP 10 +#define EP93XX_DMA_IDE 11 + +enum ep93xx_dma_type { + M2P_DMA, + M2M_DMA, +}; + struct ep93xx_dma_engine; static int ep93xx_dma_slave_config_write(struct dma_chan *chan, enum dma_transfer_direction dir, @@ -129,11 +155,17 @@ struct ep93xx_dma_desc { struct list_head node; }; +struct ep93xx_dma_chan_cfg { + u8 port; + enum dma_transfer_direction dir; +}; + /** * struct ep93xx_dma_chan - an EP93xx DMA M2P/M2M channel * @chan: dmaengine API channel * @edma: pointer to the engine device * @regs: memory mapped registers + * @dma_cfg: channel number, direction * @irq: interrupt number of the channel * @clk: clock used by this channel * @tasklet: channel specific tasklet used for callbacks @@ -157,14 +189,12 @@ struct ep93xx_dma_desc { * descriptor in the chain. When a descriptor is moved to the @active queue, * the first and chained descriptors are flattened into a single list. * - * @chan.private holds pointer to &struct ep93xx_dma_data which contains - * necessary channel configuration information. For memcpy channels this must - * be %NULL. */ struct ep93xx_dma_chan { struct dma_chan chan; const struct ep93xx_dma_engine *edma; void __iomem *regs; + struct ep93xx_dma_chan_cfg dma_cfg; int irq; struct clk *clk; struct tasklet_struct tasklet; @@ -216,6 +246,11 @@ struct ep93xx_dma_engine { struct ep93xx_dma_chan channels[] __counted_by(num_channels); }; +struct ep93xx_edma_data { + u32 id; + size_t num_channels; +}; + static inline struct device *chan2dev(struct ep93xx_dma_chan *edmac) { return &edmac->chan.dev->device; @@ -226,6 +261,31 @@ static struct ep93xx_dma_chan *to_ep93xx_dma_chan(struct dma_chan *chan) return container_of(chan, struct ep93xx_dma_chan, chan); } +static inline bool ep93xx_dma_chan_is_m2p(struct dma_chan *chan) +{ + if (device_is_compatible(chan->device->dev, "cirrus,ep9301-dma-m2p")) + return true; + + return !strcmp(dev_name(chan->device->dev), "ep93xx-dma-m2p"); +} + +/* + * ep93xx_dma_chan_direction - returns direction the channel can be used + * + * This function can be used in filter functions to find out whether the + * channel supports given DMA direction. Only M2P channels have such + * limitation, for M2M channels the direction is configurable. + */ +static inline enum dma_transfer_direction +ep93xx_dma_chan_direction(struct dma_chan *chan) +{ + if (!ep93xx_dma_chan_is_m2p(chan)) + return DMA_TRANS_NONE; + + /* even channels are for TX, odd for RX */ + return (chan->chan_id % 2 == 0) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; +} + /** * ep93xx_dma_set_active - set new active descriptor chain * @edmac: channel @@ -318,10 +378,9 @@ static void m2p_set_control(struct ep93xx_dma_chan *edmac, u32 control) static int m2p_hw_setup(struct ep93xx_dma_chan *edmac) { - struct ep93xx_dma_data *data = edmac->chan.private; u32 control; - writel(data->port & 0xf, edmac->regs + M2P_PPALLOC); + writel(edmac->dma_cfg.port & 0xf, edmac->regs + M2P_PPALLOC); control = M2P_CONTROL_CH_ERROR_INT | M2P_CONTROL_ICE | M2P_CONTROL_ENABLE; @@ -458,16 +517,15 @@ static int m2p_hw_interrupt(struct ep93xx_dma_chan *edmac) static int m2m_hw_setup(struct ep93xx_dma_chan *edmac) { - const struct ep93xx_dma_data *data = edmac->chan.private; u32 control = 0; - if (!data) { + if (edmac->dma_cfg.dir == DMA_MEM_TO_MEM) { /* This is memcpy channel, nothing to configure */ writel(control, edmac->regs + M2M_CONTROL); return 0; } - switch (data->port) { + switch (edmac->dma_cfg.port) { case EP93XX_DMA_SSP: /* * This was found via experimenting - anything less than 5 @@ -477,7 +535,7 @@ static int m2m_hw_setup(struct ep93xx_dma_chan *edmac) control = (5 << M2M_CONTROL_PWSC_SHIFT); control |= M2M_CONTROL_NO_HDSK; - if (data->direction == DMA_MEM_TO_DEV) { + if (edmac->dma_cfg.dir == DMA_MEM_TO_DEV) { control |= M2M_CONTROL_DAH; control |= M2M_CONTROL_TM_TX; control |= M2M_CONTROL_RSS_SSPTX; @@ -493,7 +551,7 @@ static int m2m_hw_setup(struct ep93xx_dma_chan *edmac) * This IDE part is totally untested. Values below are taken * from the EP93xx Users's Guide and might not be correct. */ - if (data->direction == DMA_MEM_TO_DEV) { + if (edmac->dma_cfg.dir == DMA_MEM_TO_DEV) { /* Worst case from the UG */ control = (3 << M2M_CONTROL_PWSC_SHIFT); control |= M2M_CONTROL_DAH; @@ -548,7 +606,6 @@ static void m2m_fill_desc(struct ep93xx_dma_chan *edmac) static void m2m_hw_submit(struct ep93xx_dma_chan *edmac) { - struct ep93xx_dma_data *data = edmac->chan.private; u32 control = readl(edmac->regs + M2M_CONTROL); /* @@ -574,7 +631,7 @@ static void m2m_hw_submit(struct ep93xx_dma_chan *edmac) control |= M2M_CONTROL_ENABLE; writel(control, edmac->regs + M2M_CONTROL); - if (!data) { + if (edmac->dma_cfg.dir == DMA_MEM_TO_MEM) { /* * For memcpy channels the software trigger must be asserted * in order to start the memcpy operation. @@ -636,7 +693,7 @@ static int m2m_hw_interrupt(struct ep93xx_dma_chan *edmac) */ if (ep93xx_dma_advance_active(edmac)) { m2m_fill_desc(edmac); - if (done && !edmac->chan.private) { + if (done && edmac->dma_cfg.dir == DMA_MEM_TO_MEM) { /* Software trigger for memcpy channel */ control = readl(edmac->regs + M2M_CONTROL); control |= M2M_CONTROL_START; @@ -867,25 +924,22 @@ static dma_cookie_t ep93xx_dma_tx_submit(struct dma_async_tx_descriptor *tx) static int ep93xx_dma_alloc_chan_resources(struct dma_chan *chan) { struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan); - struct ep93xx_dma_data *data = chan->private; const char *name = dma_chan_name(chan); int ret, i; /* Sanity check the channel parameters */ if (!edmac->edma->m2m) { - if (!data) - return -EINVAL; - if (data->port < EP93XX_DMA_I2S1 || - data->port > EP93XX_DMA_IRDA) + if (edmac->dma_cfg.port < EP93XX_DMA_I2S1 || + edmac->dma_cfg.port > EP93XX_DMA_IRDA) return -EINVAL; - if (data->direction != ep93xx_dma_chan_direction(chan)) + if (edmac->dma_cfg.dir != ep93xx_dma_chan_direction(chan)) return -EINVAL; } else { - if (data) { - switch (data->port) { + if (edmac->dma_cfg.dir != DMA_MEM_TO_MEM) { + switch (edmac->dma_cfg.port) { case EP93XX_DMA_SSP: case EP93XX_DMA_IDE: - if (!is_slave_direction(data->direction)) + if (!is_slave_direction(edmac->dma_cfg.dir)) return -EINVAL; break; default: @@ -894,9 +948,6 @@ static int ep93xx_dma_alloc_chan_resources(struct dma_chan *chan) } } - if (data && data->name) - name = data->name; - ret = clk_prepare_enable(edmac->clk); if (ret) return ret; @@ -1315,36 +1366,53 @@ static void ep93xx_dma_issue_pending(struct dma_chan *chan) ep93xx_dma_advance_work(to_ep93xx_dma_chan(chan)); } -static int __init ep93xx_dma_probe(struct platform_device *pdev) +static struct ep93xx_dma_engine *ep93xx_dma_of_probe(struct platform_device *pdev) { - struct ep93xx_dma_platform_data *pdata = dev_get_platdata(&pdev->dev); + const struct ep93xx_edma_data *data; + struct device *dev = &pdev->dev; struct ep93xx_dma_engine *edma; struct dma_device *dma_dev; - int ret, i; + char dma_clk_name[5]; + int i; - edma = kzalloc(struct_size(edma, channels, pdata->num_channels), GFP_KERNEL); + data = device_get_match_data(dev); + if (!data) + return ERR_PTR(dev_err_probe(dev, -ENODEV, "No device match found\n")); + + edma = devm_kzalloc(dev, struct_size(edma, channels, data->num_channels), + GFP_KERNEL); if (!edma) - return -ENOMEM; + return ERR_PTR(-ENOMEM); + edma->m2m = data->id; + edma->num_channels = data->num_channels; dma_dev = &edma->dma_dev; - edma->m2m = platform_get_device_id(pdev)->driver_data; - edma->num_channels = pdata->num_channels; INIT_LIST_HEAD(&dma_dev->channels); - for (i = 0; i < pdata->num_channels; i++) { - const struct ep93xx_dma_chan_data *cdata = &pdata->channels[i]; + for (i = 0; i < edma->num_channels; i++) { struct ep93xx_dma_chan *edmac = &edma->channels[i]; edmac->chan.device = dma_dev; - edmac->regs = cdata->base; - edmac->irq = cdata->irq; + edmac->regs = devm_platform_ioremap_resource(pdev, i); + if (IS_ERR(edmac->regs)) + return edmac->regs; + + edmac->irq = fwnode_irq_get(dev_fwnode(dev), i); + if (edmac->irq < 0) + return ERR_PTR(edmac->irq); + edmac->edma = edma; - edmac->clk = clk_get(NULL, cdata->name); + if (edma->m2m) + snprintf(dma_clk_name, sizeof(dma_clk_name), "m2m%u", i); + else + snprintf(dma_clk_name, sizeof(dma_clk_name), "m2p%u", i); + + edmac->clk = devm_clk_get(dev, dma_clk_name); if (IS_ERR(edmac->clk)) { - dev_warn(&pdev->dev, "failed to get clock for %s\n", - cdata->name); - continue; + dev_err_probe(dev, PTR_ERR(edmac->clk), + "no %s clock found\n", dma_clk_name); + return ERR_CAST(edmac->clk); } spin_lock_init(&edmac->lock); @@ -1357,6 +1425,90 @@ static int __init ep93xx_dma_probe(struct platform_device *pdev) &dma_dev->channels); } + return edma; +} + +static bool ep93xx_m2p_dma_filter(struct dma_chan *chan, void *filter_param) +{ + struct ep93xx_dma_chan *echan = to_ep93xx_dma_chan(chan); + struct ep93xx_dma_chan_cfg *cfg = filter_param; + + if (cfg->dir != ep93xx_dma_chan_direction(chan)) + return false; + + echan->dma_cfg = *cfg; + return true; +} + +static struct dma_chan *ep93xx_m2p_dma_of_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct ep93xx_dma_engine *edma = ofdma->of_dma_data; + dma_cap_mask_t mask = edma->dma_dev.cap_mask; + struct ep93xx_dma_chan_cfg dma_cfg; + u8 port = dma_spec->args[0]; + u8 direction = dma_spec->args[1]; + + if (port > EP93XX_DMA_IRDA) + return NULL; + + if (!is_slave_direction(direction)) + return NULL; + + dma_cfg.port = port; + dma_cfg.dir = direction; + + return __dma_request_channel(&mask, ep93xx_m2p_dma_filter, &dma_cfg, ofdma->of_node); +} + +static bool ep93xx_m2m_dma_filter(struct dma_chan *chan, void *filter_param) +{ + struct ep93xx_dma_chan *echan = to_ep93xx_dma_chan(chan); + struct ep93xx_dma_chan_cfg *cfg = filter_param; + + echan->dma_cfg = *cfg; + + return true; +} + +static struct dma_chan *ep93xx_m2m_dma_of_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct ep93xx_dma_engine *edma = ofdma->of_dma_data; + dma_cap_mask_t mask = edma->dma_dev.cap_mask; + struct ep93xx_dma_chan_cfg dma_cfg; + u8 port = dma_spec->args[0]; + u8 direction = dma_spec->args[1]; + + if (!is_slave_direction(direction)) + return NULL; + + switch (port) { + case EP93XX_DMA_SSP: + case EP93XX_DMA_IDE: + break; + default: + return NULL; + } + + dma_cfg.port = port; + dma_cfg.dir = direction; + + return __dma_request_channel(&mask, ep93xx_m2m_dma_filter, &dma_cfg, ofdma->of_node); +} + +static int ep93xx_dma_probe(struct platform_device *pdev) +{ + struct ep93xx_dma_engine *edma; + struct dma_device *dma_dev; + int ret; + + edma = ep93xx_dma_of_probe(pdev); + if (IS_ERR(edma)) + return PTR_ERR(edma); + + dma_dev = &edma->dma_dev; + dma_cap_zero(dma_dev->cap_mask); dma_cap_set(DMA_SLAVE, dma_dev->cap_mask); dma_cap_set(DMA_CYCLIC, dma_dev->cap_mask); @@ -1393,21 +1545,46 @@ static int __init ep93xx_dma_probe(struct platform_device *pdev) } ret = dma_async_device_register(dma_dev); - if (unlikely(ret)) { - for (i = 0; i < edma->num_channels; i++) { - struct ep93xx_dma_chan *edmac = &edma->channels[i]; - if (!IS_ERR_OR_NULL(edmac->clk)) - clk_put(edmac->clk); - } - kfree(edma); + if (ret) + return ret; + + if (edma->m2m) { + ret = of_dma_controller_register(pdev->dev.of_node, ep93xx_m2m_dma_of_xlate, + edma); } else { - dev_info(dma_dev->dev, "EP93xx M2%s DMA ready\n", - edma->m2m ? "M" : "P"); + ret = of_dma_controller_register(pdev->dev.of_node, ep93xx_m2p_dma_of_xlate, + edma); } + if (ret) + goto err_dma_unregister; + + dev_info(dma_dev->dev, "EP93xx M2%s DMA ready\n", edma->m2m ? "M" : "P"); + + return 0; + +err_dma_unregister: + dma_async_device_unregister(dma_dev); return ret; } +static const struct ep93xx_edma_data edma_m2p = { + .id = M2P_DMA, + .num_channels = 10, +}; + +static const struct ep93xx_edma_data edma_m2m = { + .id = M2M_DMA, + .num_channels = 2, +}; + +static const struct of_device_id ep93xx_dma_of_ids[] = { + { .compatible = "cirrus,ep9301-dma-m2p", .data = &edma_m2p }, + { .compatible = "cirrus,ep9301-dma-m2m", .data = &edma_m2m }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ep93xx_dma_of_ids); + static const struct platform_device_id ep93xx_dma_driver_ids[] = { { "ep93xx-dma-m2p", 0 }, { "ep93xx-dma-m2m", 1 }, @@ -1417,15 +1594,13 @@ static const struct platform_device_id ep93xx_dma_driver_ids[] = { static struct platform_driver ep93xx_dma_driver = { .driver = { .name = "ep93xx-dma", + .of_match_table = ep93xx_dma_of_ids, }, .id_table = ep93xx_dma_driver_ids, + .probe = ep93xx_dma_probe, }; -static int __init ep93xx_dma_module_init(void) -{ - return platform_driver_probe(&ep93xx_dma_driver, ep93xx_dma_probe); -} -subsys_initcall(ep93xx_dma_module_init); +module_platform_driver(ep93xx_dma_driver); MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>"); MODULE_DESCRIPTION("EP93xx DMA driver"); diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 6cedf46efec6..ab798c848215 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -12,6 +12,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/slab.h> @@ -19,29 +20,8 @@ #include <linux/bitops.h> #include <linux/seq_file.h> -#define EP93XX_GPIO_F_INT_STATUS 0x5c -#define EP93XX_GPIO_A_INT_STATUS 0xa0 -#define EP93XX_GPIO_B_INT_STATUS 0xbc - -/* Maximum value for gpio line identifiers */ -#define EP93XX_GPIO_LINE_MAX 63 - -/* Number of GPIO chips in EP93XX */ -#define EP93XX_GPIO_CHIP_NUM 8 - -/* Maximum value for irq capable line identifiers */ -#define EP93XX_GPIO_LINE_MAX_IRQ 23 - -#define EP93XX_GPIO_A_IRQ_BASE 64 -#define EP93XX_GPIO_B_IRQ_BASE 72 -/* - * Static mapping of GPIO bank F IRQS: - * F0..F7 (16..24) to irq 80..87. - */ -#define EP93XX_GPIO_F_IRQ_BASE 80 - struct ep93xx_gpio_irq_chip { - u8 irq_offset; + void __iomem *base; u8 int_unmasked; u8 int_enabled; u8 int_type1; @@ -50,15 +30,11 @@ struct ep93xx_gpio_irq_chip { }; struct ep93xx_gpio_chip { + void __iomem *base; struct gpio_chip gc; struct ep93xx_gpio_irq_chip *eic; }; -struct ep93xx_gpio { - void __iomem *base; - struct ep93xx_gpio_chip gc[EP93XX_GPIO_CHIP_NUM]; -}; - #define to_ep93xx_gpio_chip(x) container_of(x, struct ep93xx_gpio_chip, gc) static struct ep93xx_gpio_irq_chip *to_ep93xx_gpio_irq_chip(struct gpio_chip *gc) @@ -79,25 +55,23 @@ static struct ep93xx_gpio_irq_chip *to_ep93xx_gpio_irq_chip(struct gpio_chip *gc #define EP93XX_INT_RAW_STATUS_OFFSET 0x14 #define EP93XX_INT_DEBOUNCE_OFFSET 0x18 -static void ep93xx_gpio_update_int_params(struct ep93xx_gpio *epg, - struct ep93xx_gpio_irq_chip *eic) +static void ep93xx_gpio_update_int_params(struct ep93xx_gpio_irq_chip *eic) { - writeb_relaxed(0, epg->base + eic->irq_offset + EP93XX_INT_EN_OFFSET); + writeb_relaxed(0, eic->base + EP93XX_INT_EN_OFFSET); writeb_relaxed(eic->int_type2, - epg->base + eic->irq_offset + EP93XX_INT_TYPE2_OFFSET); + eic->base + EP93XX_INT_TYPE2_OFFSET); writeb_relaxed(eic->int_type1, - epg->base + eic->irq_offset + EP93XX_INT_TYPE1_OFFSET); + eic->base + EP93XX_INT_TYPE1_OFFSET); writeb_relaxed(eic->int_unmasked & eic->int_enabled, - epg->base + eic->irq_offset + EP93XX_INT_EN_OFFSET); + eic->base + EP93XX_INT_EN_OFFSET); } static void ep93xx_gpio_int_debounce(struct gpio_chip *gc, unsigned int offset, bool enable) { - struct ep93xx_gpio *epg = gpiochip_get_data(gc); struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc); int port_mask = BIT(offset); @@ -106,53 +80,43 @@ static void ep93xx_gpio_int_debounce(struct gpio_chip *gc, else eic->int_debounce &= ~port_mask; - writeb(eic->int_debounce, - epg->base + eic->irq_offset + EP93XX_INT_DEBOUNCE_OFFSET); + writeb(eic->int_debounce, eic->base + EP93XX_INT_DEBOUNCE_OFFSET); } -static void ep93xx_gpio_ab_irq_handler(struct irq_desc *desc) +static u32 ep93xx_gpio_ab_irq_handler(struct gpio_chip *gc) { - struct gpio_chip *gc = irq_desc_get_handler_data(desc); - struct ep93xx_gpio *epg = gpiochip_get_data(gc); - struct irq_chip *irqchip = irq_desc_get_chip(desc); + struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc); unsigned long stat; int offset; - chained_irq_enter(irqchip, desc); - - /* - * Dispatch the IRQs to the irqdomain of each A and B - * gpiochip irqdomains depending on what has fired. - * The tricky part is that the IRQ line is shared - * between bank A and B and each has their own gpiochip. - */ - stat = readb(epg->base + EP93XX_GPIO_A_INT_STATUS); + stat = readb(eic->base + EP93XX_INT_STATUS_OFFSET); for_each_set_bit(offset, &stat, 8) - generic_handle_domain_irq(epg->gc[0].gc.irq.domain, - offset); + generic_handle_domain_irq(gc->irq.domain, offset); - stat = readb(epg->base + EP93XX_GPIO_B_INT_STATUS); - for_each_set_bit(offset, &stat, 8) - generic_handle_domain_irq(epg->gc[1].gc.irq.domain, - offset); + return stat; +} - chained_irq_exit(irqchip, desc); +static irqreturn_t ep93xx_ab_irq_handler(int irq, void *dev_id) +{ + return IRQ_RETVAL(ep93xx_gpio_ab_irq_handler(dev_id)); } static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc) { - /* - * map discontiguous hw irq range to continuous sw irq range: - * - * IRQ_EP93XX_GPIO{0..7}MUX -> EP93XX_GPIO_LINE_F{0..7} - */ struct irq_chip *irqchip = irq_desc_get_chip(desc); - unsigned int irq = irq_desc_get_irq(desc); - int port_f_idx = (irq & 7) ^ 4; /* {20..23,48..51} -> {0..7} */ - int gpio_irq = EP93XX_GPIO_F_IRQ_BASE + port_f_idx; + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct gpio_irq_chip *gic = &gc->irq; + unsigned int parent = irq_desc_get_irq(desc); + unsigned int i; chained_irq_enter(irqchip, desc); - generic_handle_irq(gpio_irq); + for (i = 0; i < gic->num_parents; i++) + if (gic->parents[i] == parent) + break; + + if (i < gic->num_parents) + generic_handle_domain_irq(gc->irq.domain, i); + chained_irq_exit(irqchip, desc); } @@ -160,54 +124,53 @@ static void ep93xx_gpio_irq_ack(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc); - struct ep93xx_gpio *epg = gpiochip_get_data(gc); - int port_mask = BIT(d->irq & 7); + int port_mask = BIT(irqd_to_hwirq(d)); if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) { eic->int_type2 ^= port_mask; /* switch edge direction */ - ep93xx_gpio_update_int_params(epg, eic); + ep93xx_gpio_update_int_params(eic); } - writeb(port_mask, epg->base + eic->irq_offset + EP93XX_INT_EOI_OFFSET); + writeb(port_mask, eic->base + EP93XX_INT_EOI_OFFSET); } static void ep93xx_gpio_irq_mask_ack(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc); - struct ep93xx_gpio *epg = gpiochip_get_data(gc); - int port_mask = BIT(d->irq & 7); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + int port_mask = BIT(hwirq); if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) eic->int_type2 ^= port_mask; /* switch edge direction */ eic->int_unmasked &= ~port_mask; - ep93xx_gpio_update_int_params(epg, eic); + ep93xx_gpio_update_int_params(eic); - writeb(port_mask, epg->base + eic->irq_offset + EP93XX_INT_EOI_OFFSET); - gpiochip_disable_irq(gc, irqd_to_hwirq(d)); + writeb(port_mask, eic->base + EP93XX_INT_EOI_OFFSET); + gpiochip_disable_irq(gc, hwirq); } static void ep93xx_gpio_irq_mask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc); - struct ep93xx_gpio *epg = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); - eic->int_unmasked &= ~BIT(d->irq & 7); - ep93xx_gpio_update_int_params(epg, eic); - gpiochip_disable_irq(gc, irqd_to_hwirq(d)); + eic->int_unmasked &= ~BIT(hwirq); + ep93xx_gpio_update_int_params(eic); + gpiochip_disable_irq(gc, hwirq); } static void ep93xx_gpio_irq_unmask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc); - struct ep93xx_gpio *epg = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); - gpiochip_enable_irq(gc, irqd_to_hwirq(d)); - eic->int_unmasked |= BIT(d->irq & 7); - ep93xx_gpio_update_int_params(epg, eic); + gpiochip_enable_irq(gc, hwirq); + eic->int_unmasked |= BIT(hwirq); + ep93xx_gpio_update_int_params(eic); } /* @@ -219,12 +182,11 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc); - struct ep93xx_gpio *epg = gpiochip_get_data(gc); - int offset = d->irq & 7; - int port_mask = BIT(offset); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + int port_mask = BIT(hwirq); irq_flow_handler_t handler; - gc->direction_input(gc, offset); + gc->direction_input(gc, hwirq); switch (type) { case IRQ_TYPE_EDGE_RISING: @@ -250,7 +212,7 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type) case IRQ_TYPE_EDGE_BOTH: eic->int_type1 |= port_mask; /* set initial polarity based on current input level */ - if (gc->get(gc, offset)) + if (gc->get(gc, hwirq)) eic->int_type2 &= ~port_mask; /* falling */ else eic->int_type2 |= port_mask; /* rising */ @@ -264,51 +226,11 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type) eic->int_enabled |= port_mask; - ep93xx_gpio_update_int_params(epg, eic); + ep93xx_gpio_update_int_params(eic); return 0; } -/************************************************************************* - * gpiolib interface for EP93xx on-chip GPIOs - *************************************************************************/ -struct ep93xx_gpio_bank { - const char *label; - int data; - int dir; - int irq; - int base; - bool has_irq; - bool has_hierarchical_irq; - unsigned int irq_base; -}; - -#define EP93XX_GPIO_BANK(_label, _data, _dir, _irq, _base, _has_irq, _has_hier, _irq_base) \ - { \ - .label = _label, \ - .data = _data, \ - .dir = _dir, \ - .irq = _irq, \ - .base = _base, \ - .has_irq = _has_irq, \ - .has_hierarchical_irq = _has_hier, \ - .irq_base = _irq_base, \ - } - -static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = { - /* Bank A has 8 IRQs */ - EP93XX_GPIO_BANK("A", 0x00, 0x10, 0x90, 0, true, false, EP93XX_GPIO_A_IRQ_BASE), - /* Bank B has 8 IRQs */ - EP93XX_GPIO_BANK("B", 0x04, 0x14, 0xac, 8, true, false, EP93XX_GPIO_B_IRQ_BASE), - EP93XX_GPIO_BANK("C", 0x08, 0x18, 0x00, 40, false, false, 0), - EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 0x00, 24, false, false, 0), - EP93XX_GPIO_BANK("E", 0x20, 0x24, 0x00, 32, false, false, 0), - /* Bank F has 8 IRQs */ - EP93XX_GPIO_BANK("F", 0x30, 0x34, 0x4c, 16, false, true, EP93XX_GPIO_F_IRQ_BASE), - EP93XX_GPIO_BANK("G", 0x38, 0x3c, 0x00, 48, false, false, 0), - EP93XX_GPIO_BANK("H", 0x40, 0x44, 0x00, 56, false, false, 0), -}; - static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset, unsigned long config) { @@ -342,115 +264,112 @@ static const struct irq_chip gpio_eic_irq_chip = { GPIOCHIP_IRQ_RESOURCE_HELPERS, }; -static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc, - struct platform_device *pdev, - struct ep93xx_gpio *epg, - struct ep93xx_gpio_bank *bank) +static int ep93xx_setup_irqs(struct platform_device *pdev, + struct ep93xx_gpio_chip *egc) { - void __iomem *data = epg->base + bank->data; - void __iomem *dir = epg->base + bank->dir; struct gpio_chip *gc = &egc->gc; struct device *dev = &pdev->dev; - struct gpio_irq_chip *girq; - int err; - - err = bgpio_init(gc, dev, 1, data, NULL, NULL, dir, NULL, 0); - if (err) - return err; - - gc->label = bank->label; - gc->base = bank->base; - - girq = &gc->irq; - if (bank->has_irq || bank->has_hierarchical_irq) { - gc->set_config = ep93xx_gpio_set_config; - egc->eic = devm_kcalloc(dev, 1, - sizeof(*egc->eic), - GFP_KERNEL); - if (!egc->eic) - return -ENOMEM; - egc->eic->irq_offset = bank->irq; - gpio_irq_chip_set_chip(girq, &gpio_eic_irq_chip); - } + struct gpio_irq_chip *girq = &gc->irq; + int ret, irq, i; + void __iomem *intr; - if (bank->has_irq) { - int ab_parent_irq = platform_get_irq(pdev, 0); - - girq->parent_handler = ep93xx_gpio_ab_irq_handler; - girq->num_parents = 1; - girq->parents = devm_kcalloc(dev, girq->num_parents, - sizeof(*girq->parents), - GFP_KERNEL); - if (!girq->parents) - return -ENOMEM; - girq->default_type = IRQ_TYPE_NONE; - girq->handler = handle_level_irq; - girq->parents[0] = ab_parent_irq; - girq->first = bank->irq_base; - } + intr = devm_platform_ioremap_resource_byname(pdev, "intr"); + if (IS_ERR(intr)) + return PTR_ERR(intr); + + gc->set_config = ep93xx_gpio_set_config; + egc->eic = devm_kzalloc(dev, sizeof(*egc->eic), GFP_KERNEL); + if (!egc->eic) + return -ENOMEM; + + egc->eic->base = intr; + gpio_irq_chip_set_chip(girq, &gpio_eic_irq_chip); + girq->num_parents = platform_irq_count(pdev); + if (girq->num_parents == 0) + return -EINVAL; + + girq->parents = devm_kcalloc(dev, girq->num_parents, sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; - /* Only bank F has especially funky IRQ handling */ - if (bank->has_hierarchical_irq) { - int gpio_irq; - int i; + if (girq->num_parents == 1) { /* A/B irqchips */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; - /* - * FIXME: convert this to use hierarchical IRQ support! - * this requires fixing the root irqchip to be hierarchical. - */ + ret = devm_request_irq(dev, irq, ep93xx_ab_irq_handler, + IRQF_SHARED, gc->label, gc); + if (ret) + return dev_err_probe(dev, ret, "requesting IRQ: %d\n", irq); + + girq->parents[0] = irq; + } else { /* F irqchip */ girq->parent_handler = ep93xx_gpio_f_irq_handler; - girq->num_parents = 8; - girq->parents = devm_kcalloc(dev, girq->num_parents, - sizeof(*girq->parents), - GFP_KERNEL); - if (!girq->parents) - return -ENOMEM; - /* Pick resources 1..8 for these IRQs */ + for (i = 0; i < girq->num_parents; i++) { - girq->parents[i] = platform_get_irq(pdev, i + 1); - gpio_irq = bank->irq_base + i; - irq_set_chip_data(gpio_irq, &epg->gc[5]); - irq_set_chip_and_handler(gpio_irq, - girq->chip, - handle_level_irq); - irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST); + irq = platform_get_irq_optional(pdev, i); + if (irq < 0) + continue; + + girq->parents[i] = irq; } - girq->default_type = IRQ_TYPE_NONE; - girq->handler = handle_level_irq; - girq->first = bank->irq_base; + + girq->map = girq->parents; } - return devm_gpiochip_add_data(dev, gc, epg); + girq->default_type = IRQ_TYPE_NONE; + /* TODO: replace with handle_bad_irq() once we are fully hierarchical */ + girq->handler = handle_simple_irq; + + return 0; } static int ep93xx_gpio_probe(struct platform_device *pdev) { - struct ep93xx_gpio *epg; - int i; - - epg = devm_kzalloc(&pdev->dev, sizeof(*epg), GFP_KERNEL); - if (!epg) + struct ep93xx_gpio_chip *egc; + struct gpio_chip *gc; + void __iomem *data; + void __iomem *dir; + int ret; + + egc = devm_kzalloc(&pdev->dev, sizeof(*egc), GFP_KERNEL); + if (!egc) return -ENOMEM; - epg->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(epg->base)) - return PTR_ERR(epg->base); - - for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) { - struct ep93xx_gpio_chip *gc = &epg->gc[i]; - struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i]; - - if (ep93xx_gpio_add_bank(gc, pdev, epg, bank)) - dev_warn(&pdev->dev, "Unable to add gpio bank %s\n", - bank->label); + data = devm_platform_ioremap_resource_byname(pdev, "data"); + if (IS_ERR(data)) + return PTR_ERR(data); + + dir = devm_platform_ioremap_resource_byname(pdev, "dir"); + if (IS_ERR(dir)) + return PTR_ERR(dir); + + gc = &egc->gc; + ret = bgpio_init(gc, &pdev->dev, 1, data, NULL, NULL, dir, NULL, 0); + if (ret) + return dev_err_probe(&pdev->dev, ret, "unable to init generic GPIO\n"); + + gc->label = dev_name(&pdev->dev); + if (platform_irq_count(pdev) > 0) { + dev_dbg(&pdev->dev, "setting up irqs for %s\n", dev_name(&pdev->dev)); + ret = ep93xx_setup_irqs(pdev, egc); + if (ret) + dev_err_probe(&pdev->dev, ret, "setup irqs failed"); } - return 0; + return devm_gpiochip_add_data(&pdev->dev, gc, egc); } +static const struct of_device_id ep93xx_gpio_match[] = { + { .compatible = "cirrus,ep9301-gpio" }, + { /* sentinel */ } +}; + static struct platform_driver ep93xx_gpio_driver = { .driver = { .name = "gpio-ep93xx", + .of_match_table = ep93xx_gpio_match, }, .probe = ep93xx_gpio_probe, }; diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index 6b811d6bf625..dcbc50304a5a 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -6,20 +6,13 @@ * * Based on the pxa27x matrix keypad controller by Rodolfo Giometti. * - * NOTE: - * - * The 3-key reset is triggered by pressing the 3 keys in - * Row 0, Columns 2, 4, and 7 at the same time. This action can - * be disabled by setting the EP93XX_KEYPAD_DISABLE_3_KEY flag. - * - * Normal operation for the matrix does not autorepeat the key press. - * This action can be enabled by setting the EP93XX_KEYPAD_AUTOREPEAT - * flag. */ #include <linux/bits.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/interrupt.h> #include <linux/clk.h> #include <linux/io.h> @@ -27,7 +20,6 @@ #include <linux/input/matrix_keypad.h> #include <linux/slab.h> #include <linux/soc/cirrus/ep93xx.h> -#include <linux/platform_data/keypad-ep93xx.h> #include <linux/pm_wakeirq.h> /* @@ -61,12 +53,16 @@ #define KEY_REG_KEY1_MASK GENMASK(5, 0) #define KEY_REG_KEY1_SHIFT 0 +#define EP93XX_MATRIX_ROWS (8) +#define EP93XX_MATRIX_COLS (8) + #define EP93XX_MATRIX_SIZE (EP93XX_MATRIX_ROWS * EP93XX_MATRIX_COLS) struct ep93xx_keypad { - struct ep93xx_keypad_platform_data *pdata; struct input_dev *input_dev; struct clk *clk; + unsigned int debounce; + u16 prescale; void __iomem *mmio_base; @@ -133,23 +129,11 @@ static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id) static void ep93xx_keypad_config(struct ep93xx_keypad *keypad) { - struct ep93xx_keypad_platform_data *pdata = keypad->pdata; unsigned int val = 0; - clk_set_rate(keypad->clk, pdata->clk_rate); - - if (pdata->flags & EP93XX_KEYPAD_DISABLE_3_KEY) - val |= KEY_INIT_DIS3KY; - if (pdata->flags & EP93XX_KEYPAD_DIAG_MODE) - val |= KEY_INIT_DIAG; - if (pdata->flags & EP93XX_KEYPAD_BACK_DRIVE) - val |= KEY_INIT_BACK; - if (pdata->flags & EP93XX_KEYPAD_TEST_MODE) - val |= KEY_INIT_T2; - - val |= ((pdata->debounce << KEY_INIT_DBNC_SHIFT) & KEY_INIT_DBNC_MASK); + val |= (keypad->debounce << KEY_INIT_DBNC_SHIFT) & KEY_INIT_DBNC_MASK; - val |= ((pdata->prescale << KEY_INIT_PRSCL_SHIFT) & KEY_INIT_PRSCL_MASK); + val |= (keypad->prescale << KEY_INIT_PRSCL_SHIFT) & KEY_INIT_PRSCL_MASK; __raw_writel(val, keypad->mmio_base + KEY_INIT); } @@ -220,17 +204,10 @@ static int ep93xx_keypad_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(ep93xx_keypad_pm_ops, ep93xx_keypad_suspend, ep93xx_keypad_resume); -static void ep93xx_keypad_release_gpio_action(void *_pdev) -{ - struct platform_device *pdev = _pdev; - - ep93xx_keypad_release_gpio(pdev); -} - static int ep93xx_keypad_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct ep93xx_keypad *keypad; - const struct matrix_keymap_data *keymap_data; struct input_dev *input_dev; int err; @@ -238,14 +215,6 @@ static int ep93xx_keypad_probe(struct platform_device *pdev) if (!keypad) return -ENOMEM; - keypad->pdata = dev_get_platdata(&pdev->dev); - if (!keypad->pdata) - return -EINVAL; - - keymap_data = keypad->pdata->keymap_data; - if (!keymap_data) - return -EINVAL; - keypad->irq = platform_get_irq(pdev, 0); if (keypad->irq < 0) return keypad->irq; @@ -254,19 +223,13 @@ static int ep93xx_keypad_probe(struct platform_device *pdev) if (IS_ERR(keypad->mmio_base)) return PTR_ERR(keypad->mmio_base); - err = ep93xx_keypad_acquire_gpio(pdev); - if (err) - return err; - - err = devm_add_action_or_reset(&pdev->dev, - ep93xx_keypad_release_gpio_action, pdev); - if (err) - return err; - keypad->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(keypad->clk)) return PTR_ERR(keypad->clk); + device_property_read_u32(dev, "debounce-delay-ms", &keypad->debounce); + device_property_read_u16(dev, "cirrus,prescale", &keypad->prescale); + input_dev = devm_input_allocate_device(&pdev->dev); if (!input_dev) return -ENOMEM; @@ -278,13 +241,13 @@ static int ep93xx_keypad_probe(struct platform_device *pdev) input_dev->open = ep93xx_keypad_open; input_dev->close = ep93xx_keypad_close; - err = matrix_keypad_build_keymap(keymap_data, NULL, + err = matrix_keypad_build_keymap(NULL, NULL, EP93XX_MATRIX_ROWS, EP93XX_MATRIX_COLS, keypad->keycodes, input_dev); if (err) return err; - if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT) + if (device_property_read_bool(&pdev->dev, "autorepeat")) __set_bit(EV_REP, input_dev->evbit); input_set_drvdata(input_dev, keypad); @@ -313,10 +276,17 @@ static void ep93xx_keypad_remove(struct platform_device *pdev) dev_pm_clear_wake_irq(&pdev->dev); } +static const struct of_device_id ep93xx_keypad_of_ids[] = { + { .compatible = "cirrus,ep9307-keypad" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ep93xx_keypad_of_ids); + static struct platform_driver ep93xx_keypad_driver = { .driver = { .name = "ep93xx-keypad", .pm = pm_sleep_ptr(&ep93xx_keypad_pm_ops), + .of_match_table = ep93xx_keypad_of_ids, }, .probe = ep93xx_keypad_probe, .remove_new = ep93xx_keypad_remove, diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 614257308516..d0aaccf72d78 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -448,6 +448,12 @@ config MTD_NAND_RENESAS Enables support for the NAND controller found on Renesas R-Car Gen3 and RZ/N1 SoC families. +config MTD_NAND_TS72XX + tristate "ts72xx NAND controller" + depends on ARCH_EP93XX && HAS_IOMEM + help + Enables support for NAND controller on ts72xx SBCs. + comment "Misc" config MTD_SM_COMMON diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 25120a4afada..d0b0e6b83568 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_MTD_NAND_MLC_LPC32XX) += lpc32xx_mlc.o obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o +obj-$(CONFIG_MTD_NAND_TS72XX) += technologic-nand-controller.o obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o obj-$(CONFIG_MTD_NAND_VF610_NFC) += vf610_nfc.o diff --git a/drivers/mtd/nand/raw/technologic-nand-controller.c b/drivers/mtd/nand/raw/technologic-nand-controller.c new file mode 100644 index 000000000000..0e45a6fd91dd --- /dev/null +++ b/drivers/mtd/nand/raw/technologic-nand-controller.c @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Technologic Systems TS72xx NAND controller driver + * + * Copyright (C) 2023 Nikita Shubin <nikita.shubin@maquefel.me> + * + * Derived from: plat_nand.c + * Author: Vitaly Wool <vitalywool@gmail.com> + */ + +#include <linux/bits.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/platnand.h> + +#define TS72XX_NAND_CONTROL_ADDR_LINE BIT(22) /* 0xN0400000 */ +#define TS72XX_NAND_BUSY_ADDR_LINE BIT(23) /* 0xN0800000 */ + +#define TS72XX_NAND_ALE BIT(0) +#define TS72XX_NAND_CLE BIT(1) +#define TS72XX_NAND_NCE BIT(2) + +#define TS72XX_NAND_CTRL_CLE (TS72XX_NAND_NCE | TS72XX_NAND_CLE) +#define TS72XX_NAND_CTRL_ALE (TS72XX_NAND_NCE | TS72XX_NAND_ALE) + +struct ts72xx_nand_data { + struct nand_controller controller; + struct nand_chip chip; + void __iomem *base; + void __iomem *ctrl; + void __iomem *busy; +}; + +static inline struct ts72xx_nand_data *chip_to_ts72xx(struct nand_chip *chip) +{ + return container_of(chip, struct ts72xx_nand_data, chip); +} + +static int ts72xx_nand_attach_chip(struct nand_chip *chip) +{ + switch (chip->ecc.engine_type) { + case NAND_ECC_ENGINE_TYPE_ON_HOST: + return -EINVAL; + case NAND_ECC_ENGINE_TYPE_SOFT: + if (chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN) + chip->ecc.algo = NAND_ECC_ALGO_HAMMING; + chip->ecc.algo = NAND_ECC_ALGO_HAMMING; + fallthrough; + default: + return 0; + } +} + +static void ts72xx_nand_ctrl(struct nand_chip *chip, u8 value) +{ + struct ts72xx_nand_data *data = chip_to_ts72xx(chip); + unsigned char bits = ioread8(data->ctrl) & ~GENMASK(2, 0); + + iowrite8(bits | value, data->ctrl); +} + +static int ts72xx_nand_exec_instr(struct nand_chip *chip, + const struct nand_op_instr *instr) +{ + struct ts72xx_nand_data *data = chip_to_ts72xx(chip); + unsigned int timeout_us; + u32 status; + int ret; + + switch (instr->type) { + case NAND_OP_CMD_INSTR: + ts72xx_nand_ctrl(chip, TS72XX_NAND_CTRL_CLE); + iowrite8(instr->ctx.cmd.opcode, data->base); + ts72xx_nand_ctrl(chip, TS72XX_NAND_NCE); + break; + + case NAND_OP_ADDR_INSTR: + ts72xx_nand_ctrl(chip, TS72XX_NAND_CTRL_ALE); + iowrite8_rep(data->base, instr->ctx.addr.addrs, instr->ctx.addr.naddrs); + ts72xx_nand_ctrl(chip, TS72XX_NAND_NCE); + break; + + case NAND_OP_DATA_IN_INSTR: + ioread8_rep(data->base, instr->ctx.data.buf.in, instr->ctx.data.len); + break; + + case NAND_OP_DATA_OUT_INSTR: + iowrite8_rep(data->base, instr->ctx.data.buf.in, instr->ctx.data.len); + break; + + case NAND_OP_WAITRDY_INSTR: + timeout_us = instr->ctx.waitrdy.timeout_ms * 1000; + ret = readb_poll_timeout(data->busy, status, status & BIT(5), 0, timeout_us); + if (ret) + return ret; + + break; + } + + if (instr->delay_ns) + ndelay(instr->delay_ns); + + return 0; +} + +static int ts72xx_nand_exec_op(struct nand_chip *chip, + const struct nand_operation *op, bool check_only) +{ + unsigned int i; + int ret; + + if (check_only) + return 0; + + for (i = 0; i < op->ninstrs; i++) { + ret = ts72xx_nand_exec_instr(chip, &op->instrs[i]); + if (ret) + return ret; + } + + return 0; +} + +static const struct nand_controller_ops ts72xx_nand_ops = { + .attach_chip = ts72xx_nand_attach_chip, + .exec_op = ts72xx_nand_exec_op, +}; + +static int ts72xx_nand_probe(struct platform_device *pdev) +{ + struct ts72xx_nand_data *data; + struct fwnode_handle *child; + struct mtd_info *mtd; + int err; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + nand_controller_init(&data->controller); + data->controller.ops = &ts72xx_nand_ops; + data->chip.controller = &data->controller; + + data->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(data->base)) + return PTR_ERR(data->base); + data->ctrl = data->base + TS72XX_NAND_CONTROL_ADDR_LINE; + data->busy = data->base + TS72XX_NAND_BUSY_ADDR_LINE; + + child = fwnode_get_next_child_node(dev_fwnode(&pdev->dev), NULL); + if (!child) + return dev_err_probe(&pdev->dev, -ENXIO, + "ts72xx controller node should have exactly one child\n"); + + nand_set_flash_node(&data->chip, to_of_node(child)); + mtd = nand_to_mtd(&data->chip); + mtd->dev.parent = &pdev->dev; + platform_set_drvdata(pdev, data); + + /* + * This driver assumes that the default ECC engine should be TYPE_SOFT. + * Set ->engine_type before registering the NAND devices in order to + * provide a driver specific default value. + */ + data->chip.ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; + + /* Scan to find existence of the device */ + err = nand_scan(&data->chip, 1); + if (err) + goto err_handle_put; + + err = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0); + if (err) + goto err_clean_nand; + + return 0; + +err_clean_nand: + nand_cleanup(&data->chip); +err_handle_put: + fwnode_handle_put(child); + return err; +} + +static void ts72xx_nand_remove(struct platform_device *pdev) +{ + struct ts72xx_nand_data *data = platform_get_drvdata(pdev); + struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev); + struct nand_chip *chip = &data->chip; + int ret; + + ret = mtd_device_unregister(nand_to_mtd(chip)); + WARN_ON(ret); + nand_cleanup(chip); + fwnode_handle_put(fwnode); +} + +static const struct of_device_id ts72xx_id_table[] = { + { .compatible = "technologic,ts7200-nand" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ts72xx_id_table); + +static struct platform_driver ts72xx_nand_driver = { + .driver = { + .name = "ts72xx-nand", + .of_match_table = ts72xx_id_table, + }, + .probe = ts72xx_nand_probe, + .remove_new = ts72xx_nand_remove, +}; +module_platform_driver(ts72xx_nand_driver); + +MODULE_AUTHOR("Nikita Shubin <nikita.shubin@maquefel.me>"); +MODULE_DESCRIPTION("Technologic Systems TS72xx NAND controller driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/cirrus/ep93xx_eth.c b/drivers/net/ethernet/cirrus/ep93xx_eth.c index 1f495cfd7959..c2007cd86416 100644 --- a/drivers/net/ethernet/cirrus/ep93xx_eth.c +++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c @@ -16,13 +16,12 @@ #include <linux/ethtool.h> #include <linux/interrupt.h> #include <linux/moduleparam.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/io.h> #include <linux/slab.h> -#include <linux/platform_data/eth-ep93xx.h> - #define DRV_MODULE_NAME "ep93xx-eth" #define RX_QUEUE_ENTRIES 64 @@ -738,25 +737,6 @@ static const struct net_device_ops ep93xx_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, }; -static struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data) -{ - struct net_device *dev; - - dev = alloc_etherdev(sizeof(struct ep93xx_priv)); - if (dev == NULL) - return NULL; - - eth_hw_addr_set(dev, data->dev_addr); - - dev->ethtool_ops = &ep93xx_ethtool_ops; - dev->netdev_ops = &ep93xx_netdev_ops; - - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; - - return dev; -} - - static void ep93xx_eth_remove(struct platform_device *pdev) { struct net_device *dev; @@ -786,27 +766,49 @@ static void ep93xx_eth_remove(struct platform_device *pdev) static int ep93xx_eth_probe(struct platform_device *pdev) { - struct ep93xx_eth_data *data; struct net_device *dev; struct ep93xx_priv *ep; struct resource *mem; + void __iomem *base_addr; + struct device_node *np; + u8 addr[ETH_ALEN]; + u32 phy_id; int irq; int err; if (pdev == NULL) return -ENODEV; - data = dev_get_platdata(&pdev->dev); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (!mem || irq < 0) return -ENXIO; - dev = ep93xx_dev_alloc(data); + base_addr = ioremap(mem->start, resource_size(mem)); + if (!base_addr) + return dev_err_probe(&pdev->dev, -EIO, "Failed to ioremap ethernet registers\n"); + + np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); + if (!np) + return dev_err_probe(&pdev->dev, -ENODEV, "Please provide \"phy-handle\"\n"); + + err = of_property_read_u32(np, "reg", &phy_id); + of_node_put(np); + if (err) + return dev_err_probe(&pdev->dev, -ENOENT, "Failed to locate \"phy_id\"\n"); + + dev = alloc_etherdev(sizeof(struct ep93xx_priv)); if (dev == NULL) { err = -ENOMEM; goto err_out; } + + memcpy_fromio(addr, base_addr + 0x50, ETH_ALEN); + eth_hw_addr_set(dev, addr); + dev->ethtool_ops = &ep93xx_ethtool_ops; + dev->netdev_ops = &ep93xx_netdev_ops; + dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + ep = netdev_priv(dev); ep->dev = dev; SET_NETDEV_DEV(dev, &pdev->dev); @@ -822,15 +824,10 @@ static int ep93xx_eth_probe(struct platform_device *pdev) goto err_out; } - ep->base_addr = ioremap(mem->start, resource_size(mem)); - if (ep->base_addr == NULL) { - dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n"); - err = -EIO; - goto err_out; - } + ep->base_addr = base_addr; ep->irq = irq; - ep->mii.phy_id = data->phy_id; + ep->mii.phy_id = phy_id; ep->mii.phy_id_mask = 0x1f; ep->mii.reg_num_mask = 0x1f; ep->mii.dev = dev; @@ -857,12 +854,18 @@ err_out: return err; } +static const struct of_device_id ep93xx_eth_of_ids[] = { + { .compatible = "cirrus,ep9301-eth" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ep93xx_eth_of_ids); static struct platform_driver ep93xx_eth_driver = { .probe = ep93xx_eth_probe, .remove_new = ep93xx_eth_remove, .driver = { .name = "ep93xx-eth", + .of_match_table = ep93xx_eth_of_ids, }, }; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 18306569ef50..354536de564b 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -194,6 +194,13 @@ config PINCTRL_DIGICOLOR select PINMUX select GENERIC_PINCONF +config PINCTRL_EP93XX + bool + depends on ARCH_EP93XX || COMPILE_TEST + select PINMUX + select GENERIC_PINCONF + select MFD_SYSCON + config PINCTRL_EQUILIBRIUM tristate "Generic pinctrl and GPIO driver for Intel Lightning Mountain SoC" depends on OF && HAS_IOMEM diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 3c2355150961..97823f52b972 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_PINCTRL_DA850_PUPD) += pinctrl-da850-pupd.o obj-$(CONFIG_PINCTRL_DA9062) += pinctrl-da9062.o obj-$(CONFIG_PINCTRL_DIGICOLOR) += pinctrl-digicolor.o obj-$(CONFIG_PINCTRL_EQUILIBRIUM) += pinctrl-equilibrium.o +obj-$(CONFIG_PINCTRL_EP93XX) += pinctrl-ep93xx.o obj-$(CONFIG_PINCTRL_EYEQ5) += pinctrl-eyeq5.o obj-$(CONFIG_PINCTRL_GEMINI) += pinctrl-gemini.o obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o diff --git a/drivers/pinctrl/pinctrl-ep93xx.c b/drivers/pinctrl/pinctrl-ep93xx.c new file mode 100644 index 000000000000..abafbbb8fd6a --- /dev/null +++ b/drivers/pinctrl/pinctrl-ep93xx.c @@ -0,0 +1,1434 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for the EP93xx pin controller + * based on linux/drivers/pinctrl/pinmux-gemini.c + * + * Copyright (C) 2022 Nikita Shubin <nikita.shubin@maquefel.me> + * + * This is a group-only pin controller. + */ +#include <linux/array_size.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/mfd/syscon.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/seq_file.h> +#include <linux/slab.h> + +#include <linux/soc/cirrus/ep93xx.h> + +#include <linux/pinctrl/machine.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> + +#include "pinctrl-utils.h" + +#define DRIVER_NAME "pinctrl-ep93xx" + +enum ep93xx_pinctrl_model { + EP93XX_9301_PINCTRL, + EP93XX_9307_PINCTRL, + EP93XX_9312_PINCTRL, +}; + +struct ep93xx_pmx { + struct device *dev; + struct pinctrl_dev *pctl; + struct ep93xx_regmap_adev *aux_dev; + struct regmap *map; + enum ep93xx_pinctrl_model model; +}; + +static void ep93xx_pinctrl_update_bits(struct ep93xx_pmx *pmx, unsigned int reg, + unsigned int mask, unsigned int val) +{ + struct ep93xx_regmap_adev *aux = pmx->aux_dev; + + aux->update_bits(aux->map, aux->lock, reg, mask, val); +} + +struct ep93xx_pin_group { + struct pingroup grp; + u32 mask; + u32 value; +}; + +#define PMX_GROUP(_name, _pins, _mask, _value) \ + { \ + .grp = PINCTRL_PINGROUP(_name, _pins, ARRAY_SIZE(_pins)), \ + .mask = _mask, \ + .value = _value, \ + } + +#define EP93XX_SYSCON_DEVCFG 0x80 + +/* + * There are several system configuration options selectable by the DeviceCfg and SysCfg + * registers. These registers provide the selection of several pin multiplexing options and also + * provide software access to the system reset configuration options. Please refer to the + * descriptions of the registers, “DeviceCfg” on page 5-25 and “SysCfg” on page 5-34, for a + * detailed explanation. + */ +#define EP93XX_SYSCON_DEVCFG_D1ONG BIT(30) +#define EP93XX_SYSCON_DEVCFG_D0ONG BIT(29) +#define EP93XX_SYSCON_DEVCFG_IONU2 BIT(28) +#define EP93XX_SYSCON_DEVCFG_GONK BIT(27) +#define EP93XX_SYSCON_DEVCFG_TONG BIT(26) +#define EP93XX_SYSCON_DEVCFG_MONG BIT(25) +#define EP93XX_SYSCON_DEVCFG_A2ONG BIT(22) +#define EP93XX_SYSCON_DEVCFG_A1ONG BIT(21) +#define EP93XX_SYSCON_DEVCFG_HONIDE BIT(11) +#define EP93XX_SYSCON_DEVCFG_GONIDE BIT(10) +#define EP93XX_SYSCON_DEVCFG_PONG BIT(9) +#define EP93XX_SYSCON_DEVCFG_EONIDE BIT(8) +#define EP93XX_SYSCON_DEVCFG_I2SONSSP BIT(7) +#define EP93XX_SYSCON_DEVCFG_I2SONAC97 BIT(6) +#define EP93XX_SYSCON_DEVCFG_RASONP3 BIT(4) + +#define PADS_MASK (GENMASK(30, 25) | BIT(22) | BIT(21) | GENMASK(11, 6) | BIT(4)) +#define PADS_MAXBIT 30 + +/* Ordered by bit index */ +static const char * const ep93xx_padgroups[] = { + NULL, NULL, NULL, NULL, + "RasOnP3", + NULL, + "I2SonAC97", + "I2SonSSP", + "EonIDE", + "PonG", + "GonIDE", + "HonIDE", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "A1onG", + "A2onG", + NULL, NULL, + "MonG", + "TonG", + "GonK", + "IonU2", + "D0onG", + "D1onG", +}; + +/* ep9301, ep9302 */ +static const struct pinctrl_pin_desc ep9301_pins[] = { + PINCTRL_PIN(1, "CSn[7]"), + PINCTRL_PIN(2, "CSn[6]"), + PINCTRL_PIN(3, "CSn[3]"), + PINCTRL_PIN(4, "CSn[2]"), + PINCTRL_PIN(5, "CSn[1]"), + PINCTRL_PIN(6, "AD[25]"), + PINCTRL_PIN(7, "vdd_ring"), + PINCTRL_PIN(8, "gnd_ring"), + PINCTRL_PIN(9, "AD[24]"), + PINCTRL_PIN(10, "SDCLK"), + PINCTRL_PIN(11, "AD[23]"), + PINCTRL_PIN(12, "vdd_core"), + PINCTRL_PIN(13, "gnd_core"), + PINCTRL_PIN(14, "SDWEn"), + PINCTRL_PIN(15, "SDCSn[3]"), + PINCTRL_PIN(16, "SDCSn[2]"), + PINCTRL_PIN(17, "SDCSn[1]"), + PINCTRL_PIN(18, "SDCSn[0]"), + PINCTRL_PIN(19, "vdd_ring"), + PINCTRL_PIN(20, "gnd_ring"), + PINCTRL_PIN(21, "RASn"), + PINCTRL_PIN(22, "CASn"), + PINCTRL_PIN(23, "DQMn[1]"), + PINCTRL_PIN(24, "DQMn[0]"), + PINCTRL_PIN(25, "AD[22]"), + PINCTRL_PIN(26, "AD[21]"), + PINCTRL_PIN(27, "vdd_ring"), + PINCTRL_PIN(28, "gnd_ring"), + PINCTRL_PIN(29, "DA[15]"), + PINCTRL_PIN(30, "AD[7]"), + PINCTRL_PIN(31, "DA[14]"), + PINCTRL_PIN(32, "AD[6]"), + PINCTRL_PIN(33, "DA[13]"), + PINCTRL_PIN(34, "vdd_core"), + PINCTRL_PIN(35, "gnd_core"), + PINCTRL_PIN(36, "AD[5]"), + PINCTRL_PIN(37, "DA[12]"), + PINCTRL_PIN(38, "AD[4]"), + PINCTRL_PIN(39, "DA[11]"), + PINCTRL_PIN(40, "AD[3]"), + PINCTRL_PIN(41, "vdd_ring"), + PINCTRL_PIN(42, "gnd_ring"), + PINCTRL_PIN(43, "DA[10]"), + PINCTRL_PIN(44, "AD[2]"), + PINCTRL_PIN(45, "DA[9]"), + PINCTRL_PIN(46, "AD[1]"), + PINCTRL_PIN(47, "DA[8]"), + PINCTRL_PIN(48, "AD[0]"), + PINCTRL_PIN(49, "vdd_ring"), + PINCTRL_PIN(50, "gnd_ring"), + PINCTRL_PIN(51, "NC"), + PINCTRL_PIN(52, "NC"), + PINCTRL_PIN(53, "vdd_ring"), + PINCTRL_PIN(54, "gnd_ring"), + PINCTRL_PIN(55, "AD[15]"), + PINCTRL_PIN(56, "DA[7]"), + PINCTRL_PIN(57, "vdd_core"), + PINCTRL_PIN(58, "gnd_core"), + PINCTRL_PIN(59, "AD[14]"), + PINCTRL_PIN(60, "DA[6]"), + PINCTRL_PIN(61, "AD[13]"), + PINCTRL_PIN(62, "DA[5]"), + PINCTRL_PIN(63, "AD[12]"), + PINCTRL_PIN(64, "DA[4]"), + PINCTRL_PIN(65, "AD[11]"), + PINCTRL_PIN(66, "vdd_ring"), + PINCTRL_PIN(67, "gnd_ring"), + PINCTRL_PIN(68, "DA[3]"), + PINCTRL_PIN(69, "AD[10]"), + PINCTRL_PIN(70, "DA[2]"), + PINCTRL_PIN(71, "AD[9]"), + PINCTRL_PIN(72, "DA[1]"), + PINCTRL_PIN(73, "AD[8]"), + PINCTRL_PIN(74, "DA[0]"), + PINCTRL_PIN(75, "DSRn"), + PINCTRL_PIN(76, "DTRn"), + PINCTRL_PIN(77, "TCK"), + PINCTRL_PIN(78, "TDI"), + PINCTRL_PIN(79, "TDO"), + PINCTRL_PIN(80, "TMS"), + PINCTRL_PIN(81, "vdd_ring"), + PINCTRL_PIN(82, "gnd_ring"), + PINCTRL_PIN(83, "BOOT[1]"), + PINCTRL_PIN(84, "BOOT[0]"), + PINCTRL_PIN(85, "gnd_ring"), + PINCTRL_PIN(86, "NC"), + PINCTRL_PIN(87, "EECLK"), + PINCTRL_PIN(88, "EEDAT"), + PINCTRL_PIN(89, "ASYNC"), + PINCTRL_PIN(90, "vdd_core"), + PINCTRL_PIN(91, "gnd_core"), + PINCTRL_PIN(92, "ASDO"), + PINCTRL_PIN(93, "SCLK1"), + PINCTRL_PIN(94, "SFRM1"), + PINCTRL_PIN(95, "SSPRX1"), + PINCTRL_PIN(96, "SSPTX1"), + PINCTRL_PIN(97, "GRLED"), + PINCTRL_PIN(98, "RDLED"), + PINCTRL_PIN(99, "vdd_ring"), + PINCTRL_PIN(100, "gnd_ring"), + PINCTRL_PIN(101, "INT[3]"), + PINCTRL_PIN(102, "INT[1]"), + PINCTRL_PIN(103, "INT[0]"), + PINCTRL_PIN(104, "RTSn"), + PINCTRL_PIN(105, "USBm[0]"), + PINCTRL_PIN(106, "USBp[0]"), + PINCTRL_PIN(107, "ABITCLK"), + PINCTRL_PIN(108, "CTSn"), + PINCTRL_PIN(109, "RXD[0]"), + PINCTRL_PIN(110, "RXD[1]"), + PINCTRL_PIN(111, "vdd_ring"), + PINCTRL_PIN(112, "gnd_ring"), + PINCTRL_PIN(113, "TXD[0]"), + PINCTRL_PIN(114, "TXD[1]"), + PINCTRL_PIN(115, "CGPIO[0]"), + PINCTRL_PIN(116, "gnd_core"), + PINCTRL_PIN(117, "PLL_GND"), + PINCTRL_PIN(118, "XTALI"), + PINCTRL_PIN(119, "XTALO"), + PINCTRL_PIN(120, "PLL_VDD"), + PINCTRL_PIN(121, "vdd_core"), + PINCTRL_PIN(122, "gnd_ring"), + PINCTRL_PIN(123, "vdd_ring"), + PINCTRL_PIN(124, "RSTOn"), + PINCTRL_PIN(125, "PRSTn"), + PINCTRL_PIN(126, "CSn[0]"), + PINCTRL_PIN(127, "gnd_core"), + PINCTRL_PIN(128, "vdd_core"), + PINCTRL_PIN(129, "gnd_ring"), + PINCTRL_PIN(130, "vdd_ring"), + PINCTRL_PIN(131, "ADC[4]"), + PINCTRL_PIN(132, "ADC[3]"), + PINCTRL_PIN(133, "ADC[2]"), + PINCTRL_PIN(134, "ADC[1]"), + PINCTRL_PIN(135, "ADC[0]"), + PINCTRL_PIN(136, "ADC_VDD"), + PINCTRL_PIN(137, "RTCXTALI"), + PINCTRL_PIN(138, "RTCXTALO"), + PINCTRL_PIN(139, "ADC_GND"), + PINCTRL_PIN(140, "EGPIO[11]"), + PINCTRL_PIN(141, "EGPIO[10]"), + PINCTRL_PIN(142, "EGPIO[9]"), + PINCTRL_PIN(143, "EGPIO[8]"), + PINCTRL_PIN(144, "EGPIO[7]"), + PINCTRL_PIN(145, "EGPIO[6]"), + PINCTRL_PIN(146, "EGPIO[5]"), + PINCTRL_PIN(147, "EGPIO[4]"), + PINCTRL_PIN(148, "EGPIO[3]"), + PINCTRL_PIN(149, "gnd_ring"), + PINCTRL_PIN(150, "vdd_ring"), + PINCTRL_PIN(151, "EGPIO[2]"), + PINCTRL_PIN(152, "EGPIO[1]"), + PINCTRL_PIN(153, "EGPIO[0]"), + PINCTRL_PIN(154, "ARSTn"), + PINCTRL_PIN(155, "TRSTn"), + PINCTRL_PIN(156, "ASDI"), + PINCTRL_PIN(157, "USBm[2]"), + PINCTRL_PIN(158, "USBp[2]"), + PINCTRL_PIN(159, "WAITn"), + PINCTRL_PIN(160, "EGPIO[15]"), + PINCTRL_PIN(161, "gnd_ring"), + PINCTRL_PIN(162, "vdd_ring"), + PINCTRL_PIN(163, "EGPIO[14]"), + PINCTRL_PIN(164, "EGPIO[13]"), + PINCTRL_PIN(165, "EGPIO[12]"), + PINCTRL_PIN(166, "gnd_core"), + PINCTRL_PIN(167, "vdd_core"), + PINCTRL_PIN(168, "FGPIO[3]"), + PINCTRL_PIN(169, "FGPIO[2]"), + PINCTRL_PIN(170, "FGPIO[1]"), + PINCTRL_PIN(171, "gnd_ring"), + PINCTRL_PIN(172, "vdd_ring"), + PINCTRL_PIN(173, "CLD"), + PINCTRL_PIN(174, "CRS"), + PINCTRL_PIN(175, "TXERR"), + PINCTRL_PIN(176, "TXEN"), + PINCTRL_PIN(177, "MIITXD[0]"), + PINCTRL_PIN(178, "MIITXD[1]"), + PINCTRL_PIN(179, "MIITXD[2]"), + PINCTRL_PIN(180, "MIITXD[3]"), + PINCTRL_PIN(181, "TXCLK"), + PINCTRL_PIN(182, "RXERR"), + PINCTRL_PIN(183, "RXDVAL"), + PINCTRL_PIN(184, "MIIRXD[0]"), + PINCTRL_PIN(185, "MIIRXD[1]"), + PINCTRL_PIN(186, "MIIRXD[2]"), + PINCTRL_PIN(187, "gnd_ring"), + PINCTRL_PIN(188, "vdd_ring"), + PINCTRL_PIN(189, "MIIRXD[3]"), + PINCTRL_PIN(190, "RXCLK"), + PINCTRL_PIN(191, "MDIO"), + PINCTRL_PIN(192, "MDC"), + PINCTRL_PIN(193, "RDn"), + PINCTRL_PIN(194, "WRn"), + PINCTRL_PIN(195, "AD[16]"), + PINCTRL_PIN(196, "AD[17]"), + PINCTRL_PIN(197, "gnd_core"), + PINCTRL_PIN(198, "vdd_core"), + PINCTRL_PIN(199, "HGPIO[2]"), + PINCTRL_PIN(200, "HGPIO[3]"), + PINCTRL_PIN(201, "HGPIO[4]"), + PINCTRL_PIN(202, "HGPIO[5]"), + PINCTRL_PIN(203, "gnd_ring"), + PINCTRL_PIN(204, "vdd_ring"), + PINCTRL_PIN(205, "AD[18]"), + PINCTRL_PIN(206, "AD[19]"), + PINCTRL_PIN(207, "AD[20]"), + PINCTRL_PIN(208, "SDCLKEN"), +}; + +static const unsigned int ssp_ep9301_pins[] = { + 93, 94, 95, 96, +}; + +static const unsigned int ac97_ep9301_pins[] = { + 89, 92, 107, 154, 156, +}; + +/* + * Note: The EP9307 processor has one PWM with one output, PWMOUT. + * Note: The EP9301, EP9302, EP9312, and EP9315 processors each have two PWMs with + * two outputs, PWMOUT and PWMO1. PWMO1 is an alternate function for EGPIO14. + */ +/* The GPIO14E (14) pin overlap with pwm1 */ +static const unsigned int pwm_9301_pins[] = { 163 }; + +static const unsigned int gpio1a_9301_pins[] = { 163 }; + +/* ep9301/9302 have only 0 pin of GPIO C Port exposed */ +static const unsigned int gpio2a_9301_pins[] = { 115 }; + +/* ep9301/9302 have only 4,5 pin of GPIO E Port exposed */ +static const unsigned int gpio4a_9301_pins[] = { 97, 98 }; + +/* ep9301/9302 have only 4,5 pin of GPIO G Port exposed */ +static const unsigned int gpio6a_9301_pins[] = { 87, 88 }; + +static const unsigned int gpio7a_9301_pins[] = { 199, 200, 201, 202 }; + +/* Groups for the ep9301/ep9302 SoC/package */ +static const struct ep93xx_pin_group ep9301_pin_groups[] = { + PMX_GROUP("ssp", ssp_ep9301_pins, EP93XX_SYSCON_DEVCFG_I2SONSSP, 0), + PMX_GROUP("i2s_on_ssp", ssp_ep9301_pins, EP93XX_SYSCON_DEVCFG_I2SONSSP, + EP93XX_SYSCON_DEVCFG_I2SONSSP), + PMX_GROUP("ac97", ac97_ep9301_pins, EP93XX_SYSCON_DEVCFG_I2SONAC97, 0), + PMX_GROUP("i2s_on_ac97", ac97_ep9301_pins, EP93XX_SYSCON_DEVCFG_I2SONAC97, + EP93XX_SYSCON_DEVCFG_I2SONAC97), + PMX_GROUP("pwm1", pwm_9301_pins, EP93XX_SYSCON_DEVCFG_PONG, EP93XX_SYSCON_DEVCFG_PONG), + PMX_GROUP("gpio1agrp", gpio1a_9301_pins, EP93XX_SYSCON_DEVCFG_PONG, 0), + PMX_GROUP("gpio2agrp", gpio2a_9301_pins, EP93XX_SYSCON_DEVCFG_GONK, + EP93XX_SYSCON_DEVCFG_GONK), + PMX_GROUP("gpio4agrp", gpio4a_9301_pins, EP93XX_SYSCON_DEVCFG_EONIDE, + EP93XX_SYSCON_DEVCFG_EONIDE), + PMX_GROUP("gpio6agrp", gpio6a_9301_pins, EP93XX_SYSCON_DEVCFG_GONIDE, + EP93XX_SYSCON_DEVCFG_GONIDE), + PMX_GROUP("gpio7agrp", gpio7a_9301_pins, EP93XX_SYSCON_DEVCFG_HONIDE, + EP93XX_SYSCON_DEVCFG_HONIDE), +}; + +static const struct pinctrl_pin_desc ep9307_pins[] = { + /* Row A */ + PINCTRL_PIN(0, "CSn[1]"), /* A1 */ + PINCTRL_PIN(1, "CSn[7]"), /* A2 */ + PINCTRL_PIN(2, "SDCLKEN"), /* A3 */ + PINCTRL_PIN(3, "DA[31]"), /* A4 */ + PINCTRL_PIN(4, "DA[29]"), /* A5 */ + PINCTRL_PIN(5, "DA[27]"), /* A6 */ + PINCTRL_PIN(6, "HGPIO[2]"), /* A7 */ + PINCTRL_PIN(7, "RDn"), /* A8 */ + PINCTRL_PIN(8, "MIIRXD[3]"), /* A9 */ + PINCTRL_PIN(9, "RXDVAL"), /* A10 */ + PINCTRL_PIN(10, "MIITXD[1]"), /* A11 */ + PINCTRL_PIN(11, "CRS"), /* A12 */ + PINCTRL_PIN(12, "FGPIO[7]"), /* A13 */ + PINCTRL_PIN(13, "FGPIO[0]"), /* A14 */ + PINCTRL_PIN(14, "WAITn"), /* A15 */ + PINCTRL_PIN(15, "USBm[2]"), /* A16 */ + PINCTRL_PIN(16, "ASDI"), /* A17 */ + /* Row B */ + PINCTRL_PIN(17, "AD[25]"), /* B1 */ + PINCTRL_PIN(18, "CSn[2]"), /* B2 */ + PINCTRL_PIN(19, "CSn[6]"), /* B3 */ + PINCTRL_PIN(20, "AD[20]"), /* B4 */ + PINCTRL_PIN(21, "DA[30]"), /* B5 */ + PINCTRL_PIN(22, "AD[18]"), /* B6 */ + PINCTRL_PIN(23, "HGPIO[3]"), /* B7 */ + PINCTRL_PIN(24, "AD[17]"), /* B8 */ + PINCTRL_PIN(25, "RXCLK"), /* B9 */ + PINCTRL_PIN(26, "MIIRXD[1]"), /* B10 */ + PINCTRL_PIN(27, "MIITXD[2]"), /* B11 */ + PINCTRL_PIN(28, "TXEN"), /* B12 */ + PINCTRL_PIN(29, "FGPIO[5]"), /* B13 */ + PINCTRL_PIN(30, "EGPIO[15]"), /* B14 */ + PINCTRL_PIN(31, "USBp[2]"), /* B15 */ + PINCTRL_PIN(32, "ARSTn"), /* B16 */ + PINCTRL_PIN(33, "ADC_VDD"), /* B17 */ + /* Row C */ + PINCTRL_PIN(34, "AD[23]"), /* C1 */ + PINCTRL_PIN(35, "DA[26]"), /* C2 */ + PINCTRL_PIN(36, "CSn[3]"), /* C3 */ + PINCTRL_PIN(37, "DA[25]"), /* C4 */ + PINCTRL_PIN(38, "AD[24]"), /* C5 */ + PINCTRL_PIN(39, "AD[19]"), /* C6 */ + PINCTRL_PIN(40, "HGPIO[5]"), /* C7 */ + PINCTRL_PIN(41, "WRn"), /* C8 */ + PINCTRL_PIN(42, "MDIO"), /* C9 */ + PINCTRL_PIN(43, "MIIRXD[2]"), /* C10 */ + PINCTRL_PIN(44, "TXCLK"), /* C11 */ + PINCTRL_PIN(45, "MIITXD[0]"), /* C12 */ + PINCTRL_PIN(46, "CLD"), /* C13 */ + PINCTRL_PIN(47, "EGPIO[13]"), /* C14 */ + PINCTRL_PIN(48, "TRSTn"), /* C15 */ + PINCTRL_PIN(49, "Xp"), /* C16 */ + PINCTRL_PIN(50, "Xm"), /* C17 */ + /* Row D */ + PINCTRL_PIN(51, "SDCSn[3]"), /* D1 */ + PINCTRL_PIN(52, "DA[23]"), /* D2 */ + PINCTRL_PIN(53, "SDCLK"), /* D3 */ + PINCTRL_PIN(54, "DA[24]"), /* D4 */ + PINCTRL_PIN(55, "HGPIO[7]"), /* D5 */ + PINCTRL_PIN(56, "HGPIO[6]"), /* D6 */ + PINCTRL_PIN(57, "A[28]"), /* D7 */ + PINCTRL_PIN(58, "HGPIO[4]"), /* D8 */ + PINCTRL_PIN(59, "AD[16]"), /* D9 */ + PINCTRL_PIN(60, "MDC"), /* D10 */ + PINCTRL_PIN(61, "RXERR"), /* D11 */ + PINCTRL_PIN(62, "MIITXD[3]"), /* D12 */ + PINCTRL_PIN(63, "EGPIO[12]"), /* D13 */ + PINCTRL_PIN(64, "EGPIO[1]"), /* D14 */ + PINCTRL_PIN(65, "EGPIO[0]"), /* D15 */ + PINCTRL_PIN(66, "Ym"), /* D16 */ + PINCTRL_PIN(67, "Yp"), /* D17 */ + /* Row E */ + PINCTRL_PIN(68, "SDCSn[2]"), /* E1 */ + PINCTRL_PIN(69, "SDWEN"), /* E2 */ + PINCTRL_PIN(70, "DA[22]"), /* E3 */ + PINCTRL_PIN(71, "AD[3]"), /* E4 */ + PINCTRL_PIN(72, "DA[15]"), /* E5 */ + PINCTRL_PIN(73, "AD[21]"), /* E6 */ + PINCTRL_PIN(74, "DA[17]"), /* E7 */ + PINCTRL_PIN(75, "vddr"), /* E8 */ + PINCTRL_PIN(76, "vddr"), /* E9 */ + PINCTRL_PIN(77, "vddr"), /* E10 */ + PINCTRL_PIN(78, "MIIRXD[0]"), /* E11 */ + PINCTRL_PIN(79, "TXERR"), /* E12 */ + PINCTRL_PIN(80, "EGPIO[2]"), /* E13 */ + PINCTRL_PIN(81, "EGPIO[4]"), /* E14 */ + PINCTRL_PIN(82, "EGPIO[3]"), /* E15 */ + PINCTRL_PIN(83, "sXp"), /* E16 */ + PINCTRL_PIN(84, "sXm"), /* E17 */ + /* Row F */ + PINCTRL_PIN(85, "RASn"), /* F1 */ + PINCTRL_PIN(86, "SDCSn[1]"), /* F2 */ + PINCTRL_PIN(87, "SDCSn[0]"), /* F3 */ + PINCTRL_PIN(88, "DQMn[3]"), /* F4 */ + PINCTRL_PIN(89, "AD[5]"), /* F5 */ + PINCTRL_PIN(90, "gndr"), /* F6 */ + PINCTRL_PIN(91, "gndr"), /* F7 */ + PINCTRL_PIN(92, "gndr"), /* F8 */ + PINCTRL_PIN(93, "vddc"), /* F9 */ + PINCTRL_PIN(94, "vddc"), /* F10 */ + PINCTRL_PIN(95, "gndr"), /* F11 */ + PINCTRL_PIN(96, "EGPIO[7]"), /* F12 */ + PINCTRL_PIN(97, "EGPIO[5]"), /* F13 */ + PINCTRL_PIN(98, "ADC GND"), /* F14 */ + PINCTRL_PIN(99, "EGPIO[6]"), /* F15 */ + PINCTRL_PIN(100, "sYm"), /* F16 */ + PINCTRL_PIN(101, "syp"), /* F17 */ + /* Row G */ + PINCTRL_PIN(102, "DQMn[0]"), /* G1 */ + PINCTRL_PIN(103, "CASn"), /* G2 */ + PINCTRL_PIN(104, "DA[21]"), /* G3 */ + PINCTRL_PIN(105, "AD[22]"), /* G4 */ + PINCTRL_PIN(106, "vddr"), /* G5 */ + PINCTRL_PIN(107, "gndr"), /* G6 */ + PINCTRL_PIN(108, "gndr"), /* G12 */ + PINCTRL_PIN(109, "EGPIO[9]"), /* G13 */ + PINCTRL_PIN(110, "EGPIO[10]"), /* G14 */ + PINCTRL_PIN(111, "EGPIO[11]"), /* G15 */ + PINCTRL_PIN(112, "RTCXTALO"), /* G16 */ + PINCTRL_PIN(113, "RTCXTALI"), /* G17 */ + /* Row H */ + PINCTRL_PIN(114, "DA[18]"), /* H1 */ + PINCTRL_PIN(115, "DA[20]"), /* H2 */ + PINCTRL_PIN(116, "DA[19]"), /* H3 */ + PINCTRL_PIN(117, "DA[16]"), /* H4 */ + PINCTRL_PIN(118, "vddr"), /* H5 */ + PINCTRL_PIN(119, "vddc"), /* H6 */ + PINCTRL_PIN(120, "gndc"), /* H7 */ + PINCTRL_PIN(121, "gndc"), /* H9 */ + PINCTRL_PIN(122, "gndc"), /* H10 */ + PINCTRL_PIN(123, "gndr"), /* H12 */ + PINCTRL_PIN(124, "vddr"), /* H13 */ + PINCTRL_PIN(125, "EGPIO[8]"), /* H14 */ + PINCTRL_PIN(126, "PRSTN"), /* H15 */ + PINCTRL_PIN(127, "COL[7]"), /* H16 */ + PINCTRL_PIN(128, "RSTON"), /* H17 */ + /* Row J */ + PINCTRL_PIN(129, "AD[6]"), /* J1 */ + PINCTRL_PIN(130, "DA[14]"), /* J2 */ + PINCTRL_PIN(131, "AD[7]"), /* J3 */ + PINCTRL_PIN(132, "DA[13]"), /* J4 */ + PINCTRL_PIN(133, "vddr"), /* J5 */ + PINCTRL_PIN(134, "vddc"), /* J6 */ + PINCTRL_PIN(135, "gndc"), /* J8 */ + PINCTRL_PIN(136, "gndc"), /* J10 */ + PINCTRL_PIN(137, "vddc"), /* J12 */ + PINCTRL_PIN(138, "vddr"), /* J13 */ + PINCTRL_PIN(139, "COL[5]"), /* J14 */ + PINCTRL_PIN(140, "COL[6]"), /* J15 */ + PINCTRL_PIN(141, "CSn[0]"), /* J16 */ + PINCTRL_PIN(142, "COL[3]"), /* J17 */ + /* Row K */ + PINCTRL_PIN(143, "AD[4]"), /* K1 */ + PINCTRL_PIN(144, "DA[12]"), /* K2 */ + PINCTRL_PIN(145, "DA[10]"), /* K3 */ + PINCTRL_PIN(146, "DA[11]"), /* K4 */ + PINCTRL_PIN(147, "vddr"), /* K5 */ + PINCTRL_PIN(148, "gndr"), /* K6 */ + PINCTRL_PIN(149, "gndc"), /* K8 */ + PINCTRL_PIN(150, "gndc"), /* K9 */ + PINCTRL_PIN(151, "gndc"), /* K10 */ + PINCTRL_PIN(152, "vddc"), /* K12 */ + PINCTRL_PIN(153, "COL[4]"), /* K13 */ + PINCTRL_PIN(154, "PLL_VDD"), /* K14 */ + PINCTRL_PIN(155, "COL[2]"), /* K15 */ + PINCTRL_PIN(156, "COL[1]"), /* K16 */ + PINCTRL_PIN(157, "COL[0]"), /* K17 */ + /* Row L */ + PINCTRL_PIN(158, "DA[9]"), /* L1 */ + PINCTRL_PIN(159, "AD[2]"), /* L2 */ + PINCTRL_PIN(160, "AD[1]"), /* L3 */ + PINCTRL_PIN(161, "DA[8]"), /* L4 */ + PINCTRL_PIN(162, "BLANK"), /* L5 */ + PINCTRL_PIN(163, "gndr"), /* L6 */ + PINCTRL_PIN(164, "gndr"), /* L7 */ + PINCTRL_PIN(165, "ROW[7]"), /* L8 */ + PINCTRL_PIN(166, "ROW[5]"), /* L9 */ + PINCTRL_PIN(167, "PLL GND"), /* L10 */ + PINCTRL_PIN(168, "XTALI"), /* L11 */ + PINCTRL_PIN(169, "XTALO"), /* L12 */ + /* Row M */ + PINCTRL_PIN(170, "BRIGHT"), /* M1 */ + PINCTRL_PIN(171, "AD[0]"), /* M2 */ + PINCTRL_PIN(172, "DQMn[1]"), /* M3 */ + PINCTRL_PIN(173, "DQMn[2]"), /* M4 */ + PINCTRL_PIN(174, "P[17]"), /* M5 */ + PINCTRL_PIN(175, "gndr"), /* M6 */ + PINCTRL_PIN(176, "gndr"), /* M7 */ + PINCTRL_PIN(177, "vddc"), /* M8 */ + PINCTRL_PIN(178, "vddc"), /* M9 */ + PINCTRL_PIN(179, "gndr"), /* M10 */ + PINCTRL_PIN(180, "gndr"), /* M11 */ + PINCTRL_PIN(181, "ROW[6]"), /* M12 */ + PINCTRL_PIN(182, "ROW[4]"), /* M13 */ + PINCTRL_PIN(183, "ROW[1]"), /* M14 */ + PINCTRL_PIN(184, "ROW[0]"), /* M15 */ + PINCTRL_PIN(185, "ROW[3]"), /* M16 */ + PINCTRL_PIN(186, "ROW[2]"), /* M17 */ + /* Row N */ + PINCTRL_PIN(187, "P[14]"), /* N1 */ + PINCTRL_PIN(188, "P[16]"), /* N2 */ + PINCTRL_PIN(189, "P[15]"), /* N3 */ + PINCTRL_PIN(190, "P[13]"), /* N4 */ + PINCTRL_PIN(191, "P[12]"), /* N5 */ + PINCTRL_PIN(192, "DA[5]"), /* N6 */ + PINCTRL_PIN(193, "vddr"), /* N7 */ + PINCTRL_PIN(194, "vddr"), /* N8 */ + PINCTRL_PIN(195, "vddr"), /* N9 */ + PINCTRL_PIN(196, "vddr"), /* N10 */ + PINCTRL_PIN(197, "EECLK"), /* N11 */ + PINCTRL_PIN(198, "ASDO"), /* N12 */ + PINCTRL_PIN(199, "CTSn"), /* N13 */ + PINCTRL_PIN(200, "RXD[0]"), /* N14 */ + PINCTRL_PIN(201, "TXD[0]"), /* N15 */ + PINCTRL_PIN(202, "TXD[1]"), /* N16 */ + PINCTRL_PIN(203, "TXD[2]"), /* N17 */ + /* Row P */ + PINCTRL_PIN(204, "SPCLK"), /* P1 */ + PINCTRL_PIN(205, "P[10]"), /* P2 */ + PINCTRL_PIN(206, "P[11]"), /* P3 */ + PINCTRL_PIN(207, "P[3]"), /* P4 */ + PINCTRL_PIN(208, "AD[15]"), /* P5 */ + PINCTRL_PIN(209, "AD[13]"), /* P6 */ + PINCTRL_PIN(210, "AD[12]"), /* P7 */ + PINCTRL_PIN(211, "DA[2]"), /* P8 */ + PINCTRL_PIN(212, "AD[8]"), /* P9 */ + PINCTRL_PIN(213, "TCK"), /* P10 */ + PINCTRL_PIN(214, "BOOT[1]"), /* P11 */ + PINCTRL_PIN(215, "EEDAT"), /* P12 */ + PINCTRL_PIN(216, "GRLED"), /* P13 */ + PINCTRL_PIN(217, "RDLED"), /* P14 */ + PINCTRL_PIN(218, "GGPIO[2]"), /* P15 */ + PINCTRL_PIN(219, "RXD[1]"), /* P16 */ + PINCTRL_PIN(220, "RXD[2]"), /* P17 */ + /* Row R */ + PINCTRL_PIN(221, "P[9]"), /* R1 */ + PINCTRL_PIN(222, "HSYNC"), /* R2 */ + PINCTRL_PIN(223, "P[6]"), /* R3 */ + PINCTRL_PIN(224, "P[5]"), /* R4 */ + PINCTRL_PIN(225, "P[0]"), /* R5 */ + PINCTRL_PIN(226, "AD[14]"), /* R6 */ + PINCTRL_PIN(227, "DA[4]"), /* R7 */ + PINCTRL_PIN(228, "DA[1]"), /* R8 */ + PINCTRL_PIN(229, "DTRn"), /* R9 */ + PINCTRL_PIN(230, "TDI"), /* R10 */ + PINCTRL_PIN(231, "BOOT[0]"), /* R11 */ + PINCTRL_PIN(232, "ASYNC"), /* R12 */ + PINCTRL_PIN(233, "SSPTX[1]"), /* R13 */ + PINCTRL_PIN(234, "PWMOUT"), /* R14 */ + PINCTRL_PIN(235, "USBm[0]"), /* R15 */ + PINCTRL_PIN(236, "ABITCLK"), /* R16 */ + PINCTRL_PIN(237, "USBp[0]"), /* R17 */ + /* Row T */ + PINCTRL_PIN(238, "NC"), /* T1 */ + PINCTRL_PIN(239, "NC"), /* T2 */ + PINCTRL_PIN(240, "V_CSYNC"), /* T3 */ + PINCTRL_PIN(241, "P[7]"), /* T4 */ + PINCTRL_PIN(242, "P[2]"), /* T5 */ + PINCTRL_PIN(243, "DA[7]"), /* T6 */ + PINCTRL_PIN(244, "AD[11]"), /* T7 */ + PINCTRL_PIN(245, "AD[9]"), /* T8 */ + PINCTRL_PIN(246, "DSRn"), /* T9 */ + PINCTRL_PIN(247, "TMS"), /* T10 */ + PINCTRL_PIN(248, "gndr"), /* T11 */ + PINCTRL_PIN(249, "SFRM[1]"), /* T12 */ + PINCTRL_PIN(250, "INT[2]"), /* T13 */ + PINCTRL_PIN(251, "INT[0]"), /* T14 */ + PINCTRL_PIN(252, "USBp[1]"), /* T15 */ + PINCTRL_PIN(253, "NC"), /* T16 */ + PINCTRL_PIN(254, "NC"), /* T17 */ + /* Row U */ + PINCTRL_PIN(255, "NC"), /* U1 */ + PINCTRL_PIN(256, "NC"), /* U2 */ + PINCTRL_PIN(257, "P[8]"), /* U3 */ + PINCTRL_PIN(258, "P[4]"), /* U4 */ + PINCTRL_PIN(259, "P[1]"), /* U5 */ + PINCTRL_PIN(260, "DA[6]"), /* U6 */ + PINCTRL_PIN(261, "DA[3]"), /* U7 */ + PINCTRL_PIN(262, "AD[10]"), /* U8 */ + PINCTRL_PIN(263, "DA[0]"), /* U9 */ + PINCTRL_PIN(264, "TDO"), /* U10 */ + PINCTRL_PIN(265, "NC"), /* U11 */ + PINCTRL_PIN(266, "SCLK[1]"), /* U12 */ + PINCTRL_PIN(267, "SSPRX[1]"), /* U13 */ + PINCTRL_PIN(268, "INT[1]"), /* U14 */ + PINCTRL_PIN(269, "RTSn"), /* U15 */ + PINCTRL_PIN(270, "USBm[1]"), /* U16 */ + PINCTRL_PIN(271, "NC"), /* U17 */ +}; + +static const unsigned int ssp_ep9307_pins[] = { + 233, 249, 266, 267, +}; + +static const unsigned int ac97_ep9307_pins[] = { + 16, 32, 198, 232, 236, +}; + +/* I can't find info on those - it's some internal state */ +static const unsigned int raster_on_sdram0_pins[] = { +}; + +static const unsigned int raster_on_sdram3_pins[] = { +}; + +/* ROW[N] */ +static const unsigned int gpio2a_9307_pins[] = { + 165, 166, 181, 182, 183, 184, 185, 186, +}; + +/* COL[N] */ +static const unsigned int gpio3a_9307_pins[] = { + 127, 139, 140, 142, 153, 155, 156, 157, +}; + +static const unsigned int keypad_9307_pins[] = { + 127, 139, 140, 142, 153, 155, 156, 157, + 165, 166, 181, 182, 183, 184, 185, 186, +}; + +/* ep9307 have only 4,5 pin of GPIO E Port exposed */ +static const unsigned int gpio4a_9307_pins[] = { 216, 217 }; + +/* ep9307 have only 2 pin of GPIO G Port exposed */ +static const unsigned int gpio6a_9307_pins[] = { 219 }; + +static const unsigned int gpio7a_9307_pins[] = { 7, 24, 41, 56, 57, 59 }; + +static const struct ep93xx_pin_group ep9307_pin_groups[] = { + PMX_GROUP("ssp", ssp_ep9307_pins, EP93XX_SYSCON_DEVCFG_I2SONSSP, 0), + PMX_GROUP("i2s_on_ssp", ssp_ep9307_pins, EP93XX_SYSCON_DEVCFG_I2SONSSP, + EP93XX_SYSCON_DEVCFG_I2SONSSP), + PMX_GROUP("ac97", ac97_ep9307_pins, EP93XX_SYSCON_DEVCFG_I2SONAC97, 0), + PMX_GROUP("i2s_on_ac97", ac97_ep9301_pins, EP93XX_SYSCON_DEVCFG_I2SONAC97, + EP93XX_SYSCON_DEVCFG_I2SONAC97), + PMX_GROUP("rasteronsdram0grp", raster_on_sdram0_pins, EP93XX_SYSCON_DEVCFG_RASONP3, 0), + PMX_GROUP("rasteronsdram3grp", raster_on_sdram3_pins, EP93XX_SYSCON_DEVCFG_RASONP3, + EP93XX_SYSCON_DEVCFG_RASONP3), + PMX_GROUP("gpio2agrp", gpio2a_9307_pins, EP93XX_SYSCON_DEVCFG_GONK, + EP93XX_SYSCON_DEVCFG_GONK), + PMX_GROUP("gpio3agrp", gpio3a_9307_pins, EP93XX_SYSCON_DEVCFG_GONK, + EP93XX_SYSCON_DEVCFG_GONK), + PMX_GROUP("keypadgrp", keypad_9307_pins, EP93XX_SYSCON_DEVCFG_GONK, 0), + PMX_GROUP("gpio4agrp", gpio4a_9307_pins, EP93XX_SYSCON_DEVCFG_EONIDE, + EP93XX_SYSCON_DEVCFG_EONIDE), + PMX_GROUP("gpio6agrp", gpio6a_9307_pins, EP93XX_SYSCON_DEVCFG_GONIDE, + EP93XX_SYSCON_DEVCFG_GONIDE), + PMX_GROUP("gpio7agrp", gpio7a_9307_pins, EP93XX_SYSCON_DEVCFG_HONIDE, + EP93XX_SYSCON_DEVCFG_HONIDE), +}; + +/* ep9312, ep9315 */ +static const struct pinctrl_pin_desc ep9312_pins[] = { + /* Row A */ + PINCTRL_PIN(0, "CSN[7]"), /* A1 */ + PINCTRL_PIN(1, "DA[28]"), /* A2 */ + PINCTRL_PIN(2, "AD[18]"), /* A3 */ + PINCTRL_PIN(3, "DD[8]"), /* A4 */ + PINCTRL_PIN(4, "DD[4]"), /* A5 */ + PINCTRL_PIN(5, "AD[17]"), /* A6 */ + PINCTRL_PIN(6, "RDN"), /* A7 */ + PINCTRL_PIN(7, "RXCLK"), /* A8 */ + PINCTRL_PIN(8, "MIIRXD[0]"), /* A9 */ + PINCTRL_PIN(9, "RXDVAL"), /* A10 */ + PINCTRL_PIN(10, "MIITXD[2]"), /* A11 */ + PINCTRL_PIN(11, "TXERR"), /* A12 */ + PINCTRL_PIN(12, "CLD"), /* A13 */ + PINCTRL_PIN(13, "NC"), /* A14 */ + PINCTRL_PIN(14, "NC"), /* A15 */ + PINCTRL_PIN(15, "NC"), /* A16 */ + PINCTRL_PIN(16, "EGPIO[12]"), /* A17 */ + PINCTRL_PIN(17, "EGPIO[15]"), /* A18 */ + PINCTRL_PIN(18, "NC"), /* A19 */ + PINCTRL_PIN(19, "NC"), /* A20 */ + /* Row B */ + PINCTRL_PIN(20, "CSN[2]"), /* B1 */ + PINCTRL_PIN(21, "DA[31]"), /* B2 */ + PINCTRL_PIN(22, "DA[30]"), /* B3 */ + PINCTRL_PIN(23, "DA[27]"), /* B4 */ + PINCTRL_PIN(24, "DD[7]"), /* B5 */ + PINCTRL_PIN(25, "DD[3]"), /* B6 */ + PINCTRL_PIN(26, "WRN"), /* B7 */ + PINCTRL_PIN(27, "MDIO"), /* B8 */ + PINCTRL_PIN(28, "MIIRXD[1]"), /* B9 */ + PINCTRL_PIN(29, "RXERR"), /* B10 */ + PINCTRL_PIN(30, "MIITXD[1]"), /* B11 */ + PINCTRL_PIN(31, "CRS"), /* B12 */ + PINCTRL_PIN(32, "NC"), /* B13 */ + PINCTRL_PIN(33, "NC"), /* B14 */ + PINCTRL_PIN(34, "NC"), /* B15 */ + PINCTRL_PIN(35, "NC"), /* B16 */ + PINCTRL_PIN(36, "EGPIO[13]"), /* B17 */ + PINCTRL_PIN(37, "NC"), /* B18 */ + PINCTRL_PIN(38, "WAITN"), /* B19 */ + PINCTRL_PIN(39, "TRSTN"), /* B20 */ + /* Row C */ + PINCTRL_PIN(40, "CSN[1]"), /* C1 */ + PINCTRL_PIN(41, "CSN[3]"), /* C2 */ + PINCTRL_PIN(42, "AD[20]"), /* C3 */ + PINCTRL_PIN(43, "DA[29]"), /* C4 */ + PINCTRL_PIN(44, "DD[10]"), /* C5 */ + PINCTRL_PIN(45, "DD[6]"), /* C6 */ + PINCTRL_PIN(46, "DD[2]"), /* C7 */ + PINCTRL_PIN(47, "MDC"), /* C8 */ + PINCTRL_PIN(48, "MIIRXD[3]"), /* C9 */ + PINCTRL_PIN(49, "TXCLK"), /* C10 */ + PINCTRL_PIN(50, "MIITXD[0]"), /* C11 */ + PINCTRL_PIN(51, "NC"), /* C12 */ + PINCTRL_PIN(52, "NC"), /* C13 */ + PINCTRL_PIN(53, "NC"), /* C14 */ + PINCTRL_PIN(54, "NC"), /* C15 */ + PINCTRL_PIN(55, "NC"), /* C16 */ + PINCTRL_PIN(56, "NC"), /* C17 */ + PINCTRL_PIN(57, "USBP[2]"), /* C18 */ + PINCTRL_PIN(58, "IORDY"), /* C19 */ + PINCTRL_PIN(59, "DMACKN"), /* C20 */ + /* Row D */ + PINCTRL_PIN(60, "AD[24]"), /* D1 */ + PINCTRL_PIN(61, "DA[25]"), /* D2 */ + PINCTRL_PIN(62, "DD[11]"), /* D3 */ + PINCTRL_PIN(63, "SDCLKEN"), /* D4 */ + PINCTRL_PIN(64, "AD[19]"), /* D5 */ + PINCTRL_PIN(65, "DD[9]"), /* D6 */ + PINCTRL_PIN(66, "DD[5]"), /* D7 */ + PINCTRL_PIN(67, "AD[16]"), /* D8 */ + PINCTRL_PIN(68, "MIIRXD[2]"), /* D9 */ + PINCTRL_PIN(69, "MIITXD[3]"), /* D10 */ + PINCTRL_PIN(70, "TXEN"), /* D11 */ + PINCTRL_PIN(71, "NC"), /* D12 */ + PINCTRL_PIN(72, "NC"), /* D13 */ + PINCTRL_PIN(73, "NC"), /* D14 */ + PINCTRL_PIN(74, "EGPIO[14]"), /* D15 */ + PINCTRL_PIN(75, "NC"), /* D16 */ + PINCTRL_PIN(76, "USBM[2]"), /* D17 */ + PINCTRL_PIN(77, "ARSTN"), /* D18 */ + PINCTRL_PIN(78, "DIORN"), /* D19 */ + PINCTRL_PIN(79, "EGPIO[1]"), /* D20 */ + /* Row E */ + PINCTRL_PIN(80, "AD[23]"), /* E1 */ + PINCTRL_PIN(81, "DA[23]"), /* E2 */ + PINCTRL_PIN(82, "DA[26]"), /* E3 */ + PINCTRL_PIN(83, "CSN[6]"), /* E4 */ + PINCTRL_PIN(84, "GND"), /* E5 */ + PINCTRL_PIN(85, "GND"), /* E6 */ + PINCTRL_PIN(86, "CVDD"), /* E7 */ + PINCTRL_PIN(87, "CVDD"), /* E8 */ + PINCTRL_PIN(88, "RVDD"), /* E9 */ + PINCTRL_PIN(89, "GND"), /* E10 */ + PINCTRL_PIN(90, "GND"), /* E11 */ + PINCTRL_PIN(91, "RVDD"), /* E12 */ + PINCTRL_PIN(92, "CVDD"), /* E13 */ + PINCTRL_PIN(93, "CVDD"), /* E14 */ + PINCTRL_PIN(94, "GND"), /* E15 */ + PINCTRL_PIN(95, "ASDI"), /* E16 */ + PINCTRL_PIN(96, "DIOWN"), /* E17 */ + PINCTRL_PIN(97, "EGPIO[0]"), /* E18 */ + PINCTRL_PIN(98, "EGPIO[3]"), /* E19 */ + PINCTRL_PIN(99, "EGPIO[5]"), /* E20 */ + /* Row F */ + PINCTRL_PIN(100, "SDCSN[3]"), /* F1 */ + PINCTRL_PIN(101, "DA[22]"), /* F2 */ + PINCTRL_PIN(102, "DA[24]"), /* F3 */ + PINCTRL_PIN(103, "AD[25]"), /* F4 */ + PINCTRL_PIN(104, "RVDD"), /* F5 */ + PINCTRL_PIN(105, "GND"), /* F6 */ + PINCTRL_PIN(106, "CVDD"), /* F7 */ + PINCTRL_PIN(107, "CVDD"), /* F14 */ + PINCTRL_PIN(108, "GND"), /* F15 */ + PINCTRL_PIN(109, "GND"), /* F16 */ + PINCTRL_PIN(110, "EGPIO[2]"), /* F17 */ + PINCTRL_PIN(111, "EGPIO[4]"), /* F18 */ + PINCTRL_PIN(112, "EGPIO[6]"), /* F19 */ + PINCTRL_PIN(113, "EGPIO[8]"), /* F20 */ + /* Row G */ + PINCTRL_PIN(114, "SDCSN[0]"), /* G1 */ + PINCTRL_PIN(115, "SDCSN[1]"), /* G2 */ + PINCTRL_PIN(116, "SDWEN"), /* G3 */ + PINCTRL_PIN(117, "SDCLK"), /* G4 */ + PINCTRL_PIN(118, "RVDD"), /* G5 */ + PINCTRL_PIN(119, "RVDD"), /* G6 */ + PINCTRL_PIN(120, "RVDD"), /* G15 */ + PINCTRL_PIN(121, "RVDD"), /* G16 */ + PINCTRL_PIN(122, "EGPIO[7]"), /* G17 */ + PINCTRL_PIN(123, "EGPIO[9]"), /* G18 */ + PINCTRL_PIN(124, "EGPIO[10]"), /* G19 */ + PINCTRL_PIN(125, "EGPIO[11]"), /* G20 */ + /* Row H */ + PINCTRL_PIN(126, "DQMN[3]"), /* H1 */ + PINCTRL_PIN(127, "CASN"), /* H2 */ + PINCTRL_PIN(128, "RASN"), /* H3 */ + PINCTRL_PIN(129, "SDCSN[2]"), /* H4 */ + PINCTRL_PIN(130, "CVDD"), /* H5 */ + PINCTRL_PIN(131, "GND"), /* H8 */ + PINCTRL_PIN(132, "GND"), /* H9 */ + PINCTRL_PIN(133, "GND"), /* H10 */ + PINCTRL_PIN(134, "GND"), /* H11 */ + PINCTRL_PIN(135, "GND"), /* H12 */ + PINCTRL_PIN(136, "GND"), /* H13 */ + PINCTRL_PIN(137, "RVDD"), /* H16 */ + PINCTRL_PIN(138, "RTCXTALO"), /* H17 */ + PINCTRL_PIN(139, "ADC_VDD"), /* H18 */ + PINCTRL_PIN(140, "ADC_GND"), /* H19 */ + PINCTRL_PIN(141, "XP"), /* H20 */ + /* Row J */ + PINCTRL_PIN(142, "DA[21]"), /* J1 */ + PINCTRL_PIN(143, "DQMN[0]"), /* J2 */ + PINCTRL_PIN(144, "DQMN[1]"), /* J3 */ + PINCTRL_PIN(145, "DQMN[2]"), /* J4 */ + PINCTRL_PIN(146, "GND"), /* J5 */ + PINCTRL_PIN(147, "GND"), /* J8 */ + PINCTRL_PIN(148, "GND"), /* J9 */ + PINCTRL_PIN(149, "GND"), /* J10 */ + PINCTRL_PIN(150, "GND"), /* J11 */ + PINCTRL_PIN(151, "GND"), /* J12 */ + PINCTRL_PIN(152, "GND"), /* J13 */ + PINCTRL_PIN(153, "CVDD"), /* J16 */ + PINCTRL_PIN(154, "RTCXTALI"), /* J17 */ + PINCTRL_PIN(155, "XM"), /* J18 */ + PINCTRL_PIN(156, "YP"), /* J19 */ + PINCTRL_PIN(157, "YM"), /* J20 */ + /* Row K */ + PINCTRL_PIN(158, "AD[22]"), /* K1 */ + PINCTRL_PIN(159, "DA[20]"), /* K2 */ + PINCTRL_PIN(160, "AD[21]"), /* K3 */ + PINCTRL_PIN(161, "DA[19]"), /* K4 */ + PINCTRL_PIN(162, "RVDD"), /* K5 */ + PINCTRL_PIN(163, "GND"), /* K8 */ + PINCTRL_PIN(164, "GND"), /* K9 */ + PINCTRL_PIN(165, "GND"), /* K10 */ + PINCTRL_PIN(166, "GND"), /* K11 */ + PINCTRL_PIN(167, "GND"), /* K12 */ + PINCTRL_PIN(168, "GND"), /* K13 */ + PINCTRL_PIN(169, "CVDD"), /* K16 */ + PINCTRL_PIN(170, "SYM"), /* K17 */ + PINCTRL_PIN(171, "SYP"), /* K18 */ + PINCTRL_PIN(172, "SXM"), /* K19 */ + PINCTRL_PIN(173, "SXP"), /* K20 */ + /* Row L */ + PINCTRL_PIN(174, "DA[18]"), /* L1 */ + PINCTRL_PIN(175, "DA[17]"), /* L2 */ + PINCTRL_PIN(176, "DA[16]"), /* L3 */ + PINCTRL_PIN(177, "DA[15]"), /* L4 */ + PINCTRL_PIN(178, "GND"), /* L5 */ + PINCTRL_PIN(179, "GND"), /* L8 */ + PINCTRL_PIN(180, "GND"), /* L9 */ + PINCTRL_PIN(181, "GND"), /* L10 */ + PINCTRL_PIN(182, "GND"), /* L11 */ + PINCTRL_PIN(183, "GND"), /* L12 */ + PINCTRL_PIN(184, "GND"), /* L13 */ + PINCTRL_PIN(185, "CVDD"), /* L16 */ + PINCTRL_PIN(186, "COL[5]"), /* L17 */ + PINCTRL_PIN(187, "COL[7]"), /* L18 */ + PINCTRL_PIN(188, "RSTON"), /* L19 */ + PINCTRL_PIN(189, "PRSTN"), /* L20 */ + /* Row M */ + PINCTRL_PIN(190, "AD[7]"), /* M1 */ + PINCTRL_PIN(191, "DA[14]"), /* M2 */ + PINCTRL_PIN(192, "AD[6]"), /* M3 */ + PINCTRL_PIN(193, "AD[5]"), /* M4 */ + PINCTRL_PIN(194, "CVDD"), /* M5 */ + PINCTRL_PIN(195, "GND"), /* M8 */ + PINCTRL_PIN(196, "GND"), /* M9 */ + PINCTRL_PIN(197, "GND"), /* M10 */ + PINCTRL_PIN(198, "GND"), /* M11 */ + PINCTRL_PIN(199, "GND"), /* M12 */ + PINCTRL_PIN(200, "GND"), /* M13 */ + PINCTRL_PIN(201, "GND"), /* M16 */ + PINCTRL_PIN(202, "COL[4]"), /* M17 */ + PINCTRL_PIN(203, "COL[3]"), /* M18 */ + PINCTRL_PIN(204, "COL[6]"), /* M19 */ + PINCTRL_PIN(205, "CSN[0]"), /* M20 */ + /* Row N */ + PINCTRL_PIN(206, "DA[13]"), /* N1 */ + PINCTRL_PIN(207, "DA[12]"), /* N2 */ + PINCTRL_PIN(208, "DA[11]"), /* N3 */ + PINCTRL_PIN(209, "AD[3]"), /* N4 */ + PINCTRL_PIN(210, "CVDD"), /* N5 */ + PINCTRL_PIN(211, "CVDD"), /* N6 */ + PINCTRL_PIN(212, "GND"), /* N8 */ + PINCTRL_PIN(213, "GND"), /* N9 */ + PINCTRL_PIN(214, "GND"), /* N10 */ + PINCTRL_PIN(215, "GND"), /* N11 */ + PINCTRL_PIN(216, "GND"), /* N12 */ + PINCTRL_PIN(217, "GND"), /* N13 */ + PINCTRL_PIN(218, "GND"), /* N15 */ + PINCTRL_PIN(219, "GND"), /* N16 */ + PINCTRL_PIN(220, "XTALO"), /* N17 */ + PINCTRL_PIN(221, "COL[0]"), /* N18 */ + PINCTRL_PIN(222, "COL[1]"), /* N19 */ + PINCTRL_PIN(223, "COL[2]"), /* N20 */ + /* Row P */ + PINCTRL_PIN(224, "AD[4]"), /* P1 */ + PINCTRL_PIN(225, "DA[10]"), /* P2 */ + PINCTRL_PIN(226, "DA[9]"), /* P3 */ + PINCTRL_PIN(227, "BRIGHT"), /* P4 */ + PINCTRL_PIN(228, "RVDD"), /* P5 */ + PINCTRL_PIN(229, "RVDD"), /* P6 */ + PINCTRL_PIN(230, "RVDD"), /* P15 */ + PINCTRL_PIN(231, "RVDD"), /* P16 */ + PINCTRL_PIN(232, "XTALI"), /* P17 */ + PINCTRL_PIN(233, "PLL_VDD"), /* P18 */ + PINCTRL_PIN(234, "ROW[6]"), /* P19 */ + PINCTRL_PIN(235, "ROW[7]"), /* P20 */ + /* Row R */ + PINCTRL_PIN(236, "AD[2]"), /* R1 */ + PINCTRL_PIN(237, "AD[1]"), /* R2 */ + PINCTRL_PIN(238, "P[17]"), /* R3 */ + PINCTRL_PIN(239, "P[14]"), /* R4 */ + PINCTRL_PIN(240, "RVDD"), /* R5 */ + PINCTRL_PIN(241, "RVDD"), /* R6 */ + PINCTRL_PIN(242, "GND"), /* R7 */ + PINCTRL_PIN(243, "CVDD"), /* R8 */ + PINCTRL_PIN(244, "CVDD"), /* R13 */ + PINCTRL_PIN(245, "GND"), /* R14 */ + PINCTRL_PIN(246, "RVDD"), /* R15 */ + PINCTRL_PIN(247, "RVDD"), /* R16 */ + PINCTRL_PIN(248, "ROW[0]"), /* R17 */ + PINCTRL_PIN(249, "ROW[3]"), /* R18 */ + PINCTRL_PIN(250, "PLL_GND"), /* R19 */ + PINCTRL_PIN(251, "ROW[5]"), /* R20 */ + /* Row T */ + PINCTRL_PIN(252, "DA[8]"), /* T1 */ + PINCTRL_PIN(253, "BLANK"), /* T2 */ + PINCTRL_PIN(254, "P[13]"), /* T3 */ + PINCTRL_PIN(255, "SPCLK"), /* T4 */ + PINCTRL_PIN(256, "V_CSYNC"), /* T5 */ + PINCTRL_PIN(257, "DD[14]"), /* T6 */ + PINCTRL_PIN(258, "GND"), /* T7 */ + PINCTRL_PIN(259, "CVDD"), /* T8 */ + PINCTRL_PIN(260, "RVDD"), /* T9 */ + PINCTRL_PIN(261, "GND"), /* T10 */ + PINCTRL_PIN(262, "GND"), /* T11 */ + PINCTRL_PIN(263, "RVDD"), /* T12 */ + PINCTRL_PIN(264, "CVDD"), /* T13 */ + PINCTRL_PIN(265, "GND"), /* T14 */ + PINCTRL_PIN(266, "INT[0]"), /* T15 */ + PINCTRL_PIN(267, "USBM[1]"), /* T16 */ + PINCTRL_PIN(268, "RXD[0]"), /* T17 */ + PINCTRL_PIN(269, "TXD[2]"), /* T18 */ + PINCTRL_PIN(270, "ROW[2]"), /* T19 */ + PINCTRL_PIN(271, "ROW[4]"), /* T20 */ + /* Row U */ + PINCTRL_PIN(272, "AD[0]"), /* U1 */ + PINCTRL_PIN(273, "P[15]"), /* U2 */ + PINCTRL_PIN(274, "P[10]"), /* U3 */ + PINCTRL_PIN(275, "P[7]"), /* U4 */ + PINCTRL_PIN(276, "P[6]"), /* U5 */ + PINCTRL_PIN(277, "P[4]"), /* U6 */ + PINCTRL_PIN(278, "P[0]"), /* U7 */ + PINCTRL_PIN(279, "AD[13]"), /* U8 */ + PINCTRL_PIN(280, "DA[3]"), /* U9 */ + PINCTRL_PIN(281, "DA[0]"), /* U10 */ + PINCTRL_PIN(282, "DSRN"), /* U11 */ + PINCTRL_PIN(283, "BOOT[1]"), /* U12 */ + PINCTRL_PIN(284, "NC"), /* U13 */ + PINCTRL_PIN(285, "SSPRX1"), /* U14 */ + PINCTRL_PIN(286, "INT[1]"), /* U15 */ + PINCTRL_PIN(287, "PWMOUT"), /* U16 */ + PINCTRL_PIN(288, "USBM[0]"), /* U17 */ + PINCTRL_PIN(289, "RXD[1]"), /* U18 */ + PINCTRL_PIN(290, "TXD[1]"), /* U19 */ + PINCTRL_PIN(291, "ROW[1]"), /* U20 */ + /* Row V */ + PINCTRL_PIN(292, "P[16]"), /* V1 */ + PINCTRL_PIN(293, "P[11]"), /* V2 */ + PINCTRL_PIN(294, "P[8]"), /* V3 */ + PINCTRL_PIN(295, "DD[15]"), /* V4 */ + PINCTRL_PIN(296, "DD[13]"), /* V5 */ + PINCTRL_PIN(297, "P[1]"), /* V6 */ + PINCTRL_PIN(298, "AD[14]"), /* V7 */ + PINCTRL_PIN(299, "AD[12]"), /* V8 */ + PINCTRL_PIN(300, "DA[2]"), /* V9 */ + PINCTRL_PIN(301, "IDECS0N"), /* V10 */ + PINCTRL_PIN(302, "IDEDA[2]"), /* V11 */ + PINCTRL_PIN(303, "TDI"), /* V12 */ + PINCTRL_PIN(304, "GND"), /* V13 */ + PINCTRL_PIN(305, "ASYNC"), /* V14 */ + PINCTRL_PIN(306, "SSPTX1"), /* V15 */ + PINCTRL_PIN(307, "INT[2]"), /* V16 */ + PINCTRL_PIN(308, "RTSN"), /* V17 */ + PINCTRL_PIN(309, "USBP[0]"), /* V18 */ + PINCTRL_PIN(310, "CTSN"), /* V19 */ + PINCTRL_PIN(311, "TXD[0]"), /* V20 */ + /* Row W */ + PINCTRL_PIN(312, "P[12]"), /* W1 */ + PINCTRL_PIN(313, "P[9]"), /* W2 */ + PINCTRL_PIN(314, "DD[0]"), /* W3 */ + PINCTRL_PIN(315, "P[5]"), /* W4 */ + PINCTRL_PIN(316, "P[3]"), /* W5 */ + PINCTRL_PIN(317, "DA[7]"), /* W6 */ + PINCTRL_PIN(318, "DA[5]"), /* W7 */ + PINCTRL_PIN(319, "AD[11]"), /* W8 */ + PINCTRL_PIN(320, "AD[9]"), /* W9 */ + PINCTRL_PIN(321, "IDECS1N"), /* W10 */ + PINCTRL_PIN(322, "IDEDA[1]"), /* W11 */ + PINCTRL_PIN(323, "TCK"), /* W12 */ + PINCTRL_PIN(324, "TMS"), /* W13 */ + PINCTRL_PIN(325, "EECLK"), /* W14 */ + PINCTRL_PIN(326, "SCLK1"), /* W15 */ + PINCTRL_PIN(327, "GRLED"), /* W16 */ + PINCTRL_PIN(328, "INT[3]"), /* W17 */ + PINCTRL_PIN(329, "SLA[1]"), /* W18 */ + PINCTRL_PIN(330, "SLA[0]"), /* W19 */ + PINCTRL_PIN(331, "RXD[2]"), /* W20 */ + /* Row Y */ + PINCTRL_PIN(332, "HSYNC"), /* Y1 */ + PINCTRL_PIN(333, "DD[1]"), /* Y2 */ + PINCTRL_PIN(334, "DD[12]"), /* Y3 */ + PINCTRL_PIN(335, "P[2]"), /* Y4 */ + PINCTRL_PIN(336, "AD[15]"), /* Y5 */ + PINCTRL_PIN(337, "DA[6]"), /* Y6 */ + PINCTRL_PIN(338, "DA[4]"), /* Y7 */ + PINCTRL_PIN(339, "AD[10]"), /* Y8 */ + PINCTRL_PIN(340, "DA[1]"), /* Y9 */ + PINCTRL_PIN(341, "AD[8]"), /* Y10 */ + PINCTRL_PIN(342, "IDEDA[0]"), /* Y11 */ + PINCTRL_PIN(343, "DTRN"), /* Y12 */ + PINCTRL_PIN(344, "TDO"), /* Y13 */ + PINCTRL_PIN(345, "BOOT[0]"), /* Y14 */ + PINCTRL_PIN(346, "EEDAT"), /* Y15 */ + PINCTRL_PIN(347, "ASDO"), /* Y16 */ + PINCTRL_PIN(348, "SFRM1"), /* Y17 */ + PINCTRL_PIN(349, "RDLED"), /* Y18 */ + PINCTRL_PIN(350, "USBP[1]"), /* Y19 */ + PINCTRL_PIN(351, "ABITCLK"), /* Y20 */ +}; + +static const unsigned int ssp_ep9312_pins[] = { + 285, 306, 326, 348, +}; + +static const unsigned int ac97_ep9312_pins[] = { + 77, 95, 305, 347, 351, +}; + +static const unsigned int pwm_ep9312_pins[] = { 74 }; + +static const unsigned int gpio1a_ep9312_pins[] = { 74 }; + +static const unsigned int gpio2a_9312_pins[] = { + 234, 235, 248, 249, 251, 270, 271, 291, +}; + +static const unsigned int gpio3a_9312_pins[] = { + 186, 187, 202, 203, 204, 221, 222, 223, +}; + +static const unsigned int keypad_9312_pins[] = { + 186, 187, 202, 203, 204, 221, 222, 223, + 234, 235, 248, 249, 251, 270, 271, 291, +}; + +static const unsigned int gpio4a_9312_pins[] = { + 78, 301, 302, 321, 322, 342, +}; + +static const unsigned int gpio6a_9312_pins[] = { + 257, 295, 296, 334, +}; + +static const unsigned int gpio7a_9312_pins[] = { + 4, 24, 25, 45, 46, 66, 314, 333, +}; + +static const unsigned int ide_9312_pins[] = { + 78, 301, 302, 321, 322, 342, 257, 295, + 296, 334, 4, 24, 25, 45, 46, 66, + 314, 333, +}; + +static const struct ep93xx_pin_group ep9312_pin_groups[] = { + PMX_GROUP("ssp", ssp_ep9312_pins, EP93XX_SYSCON_DEVCFG_I2SONSSP, 0), + PMX_GROUP("i2s_on_ssp", ssp_ep9312_pins, EP93XX_SYSCON_DEVCFG_I2SONSSP, + EP93XX_SYSCON_DEVCFG_I2SONSSP), + PMX_GROUP("pwm1", pwm_ep9312_pins, EP93XX_SYSCON_DEVCFG_PONG, + EP93XX_SYSCON_DEVCFG_PONG), + PMX_GROUP("gpio1agrp", gpio1a_ep9312_pins, EP93XX_SYSCON_DEVCFG_PONG, 0), + PMX_GROUP("ac97", ac97_ep9312_pins, EP93XX_SYSCON_DEVCFG_I2SONAC97, 0), + PMX_GROUP("i2s_on_ac97", ac97_ep9312_pins, EP93XX_SYSCON_DEVCFG_I2SONAC97, + EP93XX_SYSCON_DEVCFG_I2SONAC97), + PMX_GROUP("rasteronsdram0grp", raster_on_sdram0_pins, EP93XX_SYSCON_DEVCFG_RASONP3, 0), + PMX_GROUP("rasteronsdram3grp", raster_on_sdram3_pins, EP93XX_SYSCON_DEVCFG_RASONP3, + EP93XX_SYSCON_DEVCFG_RASONP3), + PMX_GROUP("gpio2agrp", gpio2a_9312_pins, EP93XX_SYSCON_DEVCFG_GONK, + EP93XX_SYSCON_DEVCFG_GONK), + PMX_GROUP("gpio3agrp", gpio3a_9312_pins, EP93XX_SYSCON_DEVCFG_GONK, + EP93XX_SYSCON_DEVCFG_GONK), + PMX_GROUP("keypadgrp", keypad_9312_pins, EP93XX_SYSCON_DEVCFG_GONK, 0), + PMX_GROUP("gpio4agrp", gpio4a_9312_pins, EP93XX_SYSCON_DEVCFG_EONIDE, + EP93XX_SYSCON_DEVCFG_EONIDE), + PMX_GROUP("gpio6agrp", gpio6a_9312_pins, EP93XX_SYSCON_DEVCFG_GONIDE, + EP93XX_SYSCON_DEVCFG_GONIDE), + PMX_GROUP("gpio7agrp", gpio7a_9312_pins, EP93XX_SYSCON_DEVCFG_HONIDE, + EP93XX_SYSCON_DEVCFG_HONIDE), + PMX_GROUP("idegrp", ide_9312_pins, EP93XX_SYSCON_DEVCFG_EONIDE | + EP93XX_SYSCON_DEVCFG_GONIDE | EP93XX_SYSCON_DEVCFG_HONIDE, 0), +}; + +static int ep93xx_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct ep93xx_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + + switch (pmx->model) { + case EP93XX_9301_PINCTRL: + return ARRAY_SIZE(ep9301_pin_groups); + case EP93XX_9307_PINCTRL: + return ARRAY_SIZE(ep9307_pin_groups); + case EP93XX_9312_PINCTRL: + return ARRAY_SIZE(ep9312_pin_groups); + default: + return 0; + } +} + +static const char *ep93xx_get_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct ep93xx_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + + switch (pmx->model) { + case EP93XX_9301_PINCTRL: + return ep9301_pin_groups[selector].grp.name; + case EP93XX_9307_PINCTRL: + return ep9307_pin_groups[selector].grp.name; + case EP93XX_9312_PINCTRL: + return ep9312_pin_groups[selector].grp.name; + default: + return NULL; + } +} + +static int ep93xx_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int selector, + const unsigned int **pins, + unsigned int *num_pins) +{ + struct ep93xx_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + + switch (pmx->model) { + case EP93XX_9301_PINCTRL: + *pins = ep9301_pin_groups[selector].grp.pins; + *num_pins = ep9301_pin_groups[selector].grp.npins; + break; + case EP93XX_9307_PINCTRL: + *pins = ep9307_pin_groups[selector].grp.pins; + *num_pins = ep9307_pin_groups[selector].grp.npins; + break; + case EP93XX_9312_PINCTRL: + *pins = ep9312_pin_groups[selector].grp.pins; + *num_pins = ep9312_pin_groups[selector].grp.npins; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct pinctrl_ops ep93xx_pctrl_ops = { + .get_groups_count = ep93xx_get_groups_count, + .get_group_name = ep93xx_get_group_name, + .get_group_pins = ep93xx_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_all, + .dt_free_map = pinconf_generic_dt_free_map, +}; + +static const char * const spigrps[] = { "ssp" }; +static const char * const ac97grps[] = { "ac97" }; +static const char * const i2sgrps[] = { "i2s_on_ssp", "i2s_on_ac97" }; +static const char * const pwm1grps[] = { "pwm1" }; +static const char * const gpiogrps[] = { "gpio1agrp", "gpio2agrp", "gpio3agrp", + "gpio4agrp", "gpio6agrp", "gpio7agrp" }; +static const char * const rastergrps[] = { "rasteronsdram0grp", "rasteronsdram3grp"}; +static const char * const keypadgrps[] = { "keypadgrp"}; +static const char * const idegrps[] = { "idegrp"}; + +static const struct pinfunction ep93xx_pmx_functions[] = { + PINCTRL_PINFUNCTION("spi", spigrps, ARRAY_SIZE(spigrps)), + PINCTRL_PINFUNCTION("ac97", ac97grps, ARRAY_SIZE(ac97grps)), + PINCTRL_PINFUNCTION("i2s", i2sgrps, ARRAY_SIZE(i2sgrps)), + PINCTRL_PINFUNCTION("pwm", pwm1grps, ARRAY_SIZE(pwm1grps)), + PINCTRL_PINFUNCTION("keypad", keypadgrps, ARRAY_SIZE(keypadgrps)), + PINCTRL_PINFUNCTION("pata", idegrps, ARRAY_SIZE(idegrps)), + PINCTRL_PINFUNCTION("lcd", rastergrps, ARRAY_SIZE(rastergrps)), + PINCTRL_PINFUNCTION("gpio", gpiogrps, ARRAY_SIZE(gpiogrps)), +}; + +static int ep93xx_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned int group) +{ + struct ep93xx_pmx *pmx; + const struct pinfunction *func; + const struct ep93xx_pin_group *grp; + u32 before, after, expected; + unsigned long tmp; + int i; + + pmx = pinctrl_dev_get_drvdata(pctldev); + + switch (pmx->model) { + case EP93XX_9301_PINCTRL: + grp = &ep9301_pin_groups[group]; + break; + case EP93XX_9307_PINCTRL: + grp = &ep9307_pin_groups[group]; + break; + case EP93XX_9312_PINCTRL: + grp = &ep9312_pin_groups[group]; + break; + default: + dev_err(pmx->dev, "invalid SoC type\n"); + return -ENODEV; + } + + func = &ep93xx_pmx_functions[selector]; + + dev_dbg(pmx->dev, + "ACTIVATE function \"%s\" with group \"%s\" (mask=0x%x, value=0x%x)\n", + func->name, grp->grp.name, grp->mask, grp->value); + + regmap_read(pmx->map, EP93XX_SYSCON_DEVCFG, &before); + ep93xx_pinctrl_update_bits(pmx, EP93XX_SYSCON_DEVCFG, + grp->mask, grp->value); + regmap_read(pmx->map, EP93XX_SYSCON_DEVCFG, &after); + + dev_dbg(pmx->dev, "before=0x%x, after=0x%x, mask=0x%lx\n", + before, after, PADS_MASK); + + /* Which bits changed */ + before &= PADS_MASK; + after &= PADS_MASK; + expected = before & ~grp->mask; + expected |= grp->value; + expected &= PADS_MASK; + + /* Print changed states */ + tmp = expected ^ after; + for_each_set_bit(i, &tmp, PADS_MAXBIT) { + bool enabled = expected & BIT(i); + + dev_err(pmx->dev, + "pin group %s could not be %s: probably a hardware limitation\n", + ep93xx_padgroups[i], str_enabled_disabled(enabled)); + dev_err(pmx->dev, + "DeviceCfg before: %08x, after %08x, expected %08x\n", + before, after, expected); + } + + return tmp ? -EINVAL : 0; +}; + +static int ep93xx_pmx_get_funcs_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(ep93xx_pmx_functions); +} + +static const char *ep93xx_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + return ep93xx_pmx_functions[selector].name; +} + +static int ep93xx_pmx_get_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **groups, + unsigned int * const num_groups) +{ + *groups = ep93xx_pmx_functions[selector].groups; + *num_groups = ep93xx_pmx_functions[selector].ngroups; + return 0; +} + +static const struct pinmux_ops ep93xx_pmx_ops = { + .get_functions_count = ep93xx_pmx_get_funcs_count, + .get_function_name = ep93xx_pmx_get_func_name, + .get_function_groups = ep93xx_pmx_get_groups, + .set_mux = ep93xx_pmx_set_mux, +}; + +static struct pinctrl_desc ep93xx_pmx_desc = { + .name = DRIVER_NAME, + .pctlops = &ep93xx_pctrl_ops, + .pmxops = &ep93xx_pmx_ops, + .owner = THIS_MODULE, +}; + +static int ep93xx_pmx_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct ep93xx_regmap_adev *rdev = to_ep93xx_regmap_adev(adev); + struct device *dev = &adev->dev; + struct ep93xx_pmx *pmx; + + /* Create state holders etc for this driver */ + pmx = devm_kzalloc(dev, sizeof(*pmx), GFP_KERNEL); + if (!pmx) + return -ENOMEM; + + pmx->dev = dev; + pmx->map = rdev->map; + pmx->aux_dev = rdev; + pmx->model = (enum ep93xx_pinctrl_model)(uintptr_t)id->driver_data; + switch (pmx->model) { + case EP93XX_9301_PINCTRL: + ep93xx_pmx_desc.pins = ep9301_pins; + ep93xx_pmx_desc.npins = ARRAY_SIZE(ep9301_pins); + dev_info(dev, "detected 9301/9302 chip variant\n"); + break; + case EP93XX_9307_PINCTRL: + ep93xx_pmx_desc.pins = ep9307_pins; + ep93xx_pmx_desc.npins = ARRAY_SIZE(ep9307_pins); + dev_info(dev, "detected 9307 chip variant\n"); + break; + case EP93XX_9312_PINCTRL: + ep93xx_pmx_desc.pins = ep9312_pins; + ep93xx_pmx_desc.npins = ARRAY_SIZE(ep9312_pins); + dev_info(dev, "detected 9312/9315 chip variant\n"); + break; + default: + return dev_err_probe(dev, -EINVAL, "unknown pin control model: %u\n", pmx->model); + } + + /* using parent of_node to match in get_pinctrl_dev_from_of_node() */ + device_set_node(dev, dev_fwnode(adev->dev.parent)); + pmx->pctl = devm_pinctrl_register(dev, &ep93xx_pmx_desc, pmx); + if (IS_ERR(pmx->pctl)) + return dev_err_probe(dev, PTR_ERR(pmx->pctl), "could not register pinmux driver\n"); + + return 0; +}; + +static const struct auxiliary_device_id ep93xx_pinctrl_ids[] = { + { + .name = "soc_ep93xx.pinctrl-ep9301", + .driver_data = (kernel_ulong_t)EP93XX_9301_PINCTRL, + }, + { + .name = "soc_ep93xx.pinctrl-ep9307", + .driver_data = (kernel_ulong_t)EP93XX_9307_PINCTRL, + }, + { + .name = "soc_ep93xx.pinctrl-ep9312", + .driver_data = (kernel_ulong_t)EP93XX_9312_PINCTRL, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(auxiliary, ep93xx_pinctrl_ids); + +static struct auxiliary_driver ep93xx_pmx_driver = { + .probe = ep93xx_pmx_probe, + .id_table = ep93xx_pinctrl_ids, +}; +module_auxiliary_driver(ep93xx_pmx_driver); diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index fece990af4a7..389d5a193e5d 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -75,6 +75,16 @@ config POWER_RESET_BRCMSTB Say Y here if you have a Broadcom STB board and you wish to have restart support. +config POWER_RESET_EP93XX + bool "Cirrus EP93XX reset driver" if COMPILE_TEST + depends on MFD_SYSCON + default ARCH_EP93XX + help + This driver provides restart support for Cirrus EP93XX SoC. + + Say Y here if you have a Cirrus EP93XX SoC and you wish + to have restart support. + config POWER_RESET_GEMINI_POWEROFF bool "Cortina Gemini power-off driver" depends on ARCH_GEMINI || COMPILE_TEST diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index a95d1bd275d1..10782d32e1da 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_POWER_RESET_ATC260X) += atc260x-poweroff.o obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o obj-$(CONFIG_POWER_RESET_BRCMKONA) += brcm-kona-reset.o obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o +obj-$(CONFIG_POWER_RESET_EP93XX) += ep93xx-restart.o obj-$(CONFIG_POWER_RESET_GEMINI_POWEROFF) += gemini-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o diff --git a/drivers/power/reset/ep93xx-restart.c b/drivers/power/reset/ep93xx-restart.c new file mode 100644 index 000000000000..57cfb8620faf --- /dev/null +++ b/drivers/power/reset/ep93xx-restart.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Cirrus EP93xx SoC reset driver + * + * Copyright (C) 2021 Nikita Shubin <nikita.shubin@maquefel.me> + */ + +#include <linux/bits.h> +#include <linux/container_of.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/notifier.h> +#include <linux/reboot.h> +#include <linux/slab.h> + +#include <linux/soc/cirrus/ep93xx.h> + +#define EP93XX_SYSCON_DEVCFG 0x80 +#define EP93XX_SYSCON_DEVCFG_SWRST BIT(31) + +struct ep93xx_restart { + struct ep93xx_regmap_adev *aux_dev; + struct notifier_block restart_handler; +}; + +static int ep93xx_restart_handle(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + struct ep93xx_restart *priv = + container_of(this, struct ep93xx_restart, restart_handler); + struct ep93xx_regmap_adev *aux = priv->aux_dev; + + /* Issue the reboot */ + aux->update_bits(aux->map, aux->lock, EP93XX_SYSCON_DEVCFG, + EP93XX_SYSCON_DEVCFG_SWRST, EP93XX_SYSCON_DEVCFG_SWRST); + aux->update_bits(aux->map, aux->lock, EP93XX_SYSCON_DEVCFG, + EP93XX_SYSCON_DEVCFG_SWRST, 0); + + return NOTIFY_DONE; +} + +static int ep93xx_reboot_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct ep93xx_regmap_adev *rdev = to_ep93xx_regmap_adev(adev); + struct device *dev = &adev->dev; + struct ep93xx_restart *priv; + int err; + + if (!rdev->update_bits) + return -ENODEV; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->aux_dev = rdev; + + priv->restart_handler.notifier_call = ep93xx_restart_handle; + priv->restart_handler.priority = 128; + + err = register_restart_handler(&priv->restart_handler); + if (err) + return dev_err_probe(dev, err, "can't register restart notifier\n"); + + return 0; +} + +static const struct auxiliary_device_id ep93xx_reboot_ids[] = { + { + .name = "soc_ep93xx.reset-ep93xx", + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(auxiliary, ep93xx_reboot_ids); + +static struct auxiliary_driver ep93xx_reboot_driver = { + .probe = ep93xx_reboot_probe, + .id_table = ep93xx_reboot_ids, +}; +module_auxiliary_driver(ep93xx_reboot_driver); diff --git a/drivers/pwm/pwm-ep93xx.c b/drivers/pwm/pwm-ep93xx.c index 666f2954133c..994f89ac43b4 100644 --- a/drivers/pwm/pwm-ep93xx.c +++ b/drivers/pwm/pwm-ep93xx.c @@ -17,6 +17,7 @@ */ #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/clk.h> @@ -26,8 +27,6 @@ #include <asm/div64.h> -#include <linux/soc/cirrus/ep93xx.h> /* for ep93xx_pwm_{acquire,release}_gpio() */ - #define EP93XX_PWMx_TERM_COUNT 0x00 #define EP93XX_PWMx_DUTY_CYCLE 0x04 #define EP93XX_PWMx_ENABLE 0x08 @@ -43,20 +42,6 @@ static inline struct ep93xx_pwm *to_ep93xx_pwm(struct pwm_chip *chip) return pwmchip_get_drvdata(chip); } -static int ep93xx_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct platform_device *pdev = to_platform_device(pwmchip_parent(chip)); - - return ep93xx_pwm_acquire_gpio(pdev); -} - -static void ep93xx_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct platform_device *pdev = to_platform_device(pwmchip_parent(chip)); - - ep93xx_pwm_release_gpio(pdev); -} - static int ep93xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state) { @@ -155,8 +140,6 @@ static int ep93xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, } static const struct pwm_ops ep93xx_pwm_ops = { - .request = ep93xx_pwm_request, - .free = ep93xx_pwm_free, .apply = ep93xx_pwm_apply, }; @@ -188,9 +171,16 @@ static int ep93xx_pwm_probe(struct platform_device *pdev) return 0; } +static const struct of_device_id ep93xx_pwm_of_ids[] = { + { .compatible = "cirrus,ep9301-pwm" }, + { /* sentinel */} +}; +MODULE_DEVICE_TABLE(of, ep93xx_pwm_of_ids); + static struct platform_driver ep93xx_pwm_driver = { .driver = { .name = "ep93xx-pwm", + .of_match_table = ep93xx_pwm_of_ids, }, .probe = ep93xx_pwm_probe, }; diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index 5d924e946507..6a8daeb8c4b9 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -7,6 +7,7 @@ source "drivers/soc/aspeed/Kconfig" source "drivers/soc/atmel/Kconfig" source "drivers/soc/bcm/Kconfig" source "drivers/soc/canaan/Kconfig" +source "drivers/soc/cirrus/Kconfig" source "drivers/soc/fsl/Kconfig" source "drivers/soc/fujitsu/Kconfig" source "drivers/soc/hisilicon/Kconfig" diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 56f476a12847..2037a8695cb2 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -8,6 +8,7 @@ obj-y += aspeed/ obj-$(CONFIG_ARCH_AT91) += atmel/ obj-y += bcm/ obj-$(CONFIG_ARCH_CANAAN) += canaan/ +obj-$(CONFIG_EP93XX_SOC) += cirrus/ obj-$(CONFIG_ARCH_DOVE) += dove/ obj-$(CONFIG_MACH_DOVE) += dove/ obj-y += fsl/ diff --git a/drivers/soc/cirrus/Kconfig b/drivers/soc/cirrus/Kconfig new file mode 100644 index 000000000000..d8b3b1e68998 --- /dev/null +++ b/drivers/soc/cirrus/Kconfig @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only + +if ARCH_EP93XX + +config EP93XX_SOC + bool "Cirrus EP93xx chips SoC" + select SOC_BUS + select AUXILIARY_BUS + default y + help + Enable support SoC for Cirrus EP93xx chips. + + Cirrus EP93xx chips have several swlocked registers, + this driver provides locked access for reset, pinctrl + and clk devices implemented as auxiliary devices. + +endif diff --git a/drivers/soc/cirrus/Makefile b/drivers/soc/cirrus/Makefile new file mode 100644 index 000000000000..9e6608b67f76 --- /dev/null +++ b/drivers/soc/cirrus/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-y += soc-ep93xx.o diff --git a/drivers/soc/cirrus/soc-ep93xx.c b/drivers/soc/cirrus/soc-ep93xx.c new file mode 100644 index 000000000000..3e79b3b13aef --- /dev/null +++ b/drivers/soc/cirrus/soc-ep93xx.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * SoC driver for Cirrus EP93xx chips. + * Copyright (C) 2022 Nikita Shubin <nikita.shubin@maquefel.me> + * + * Based on a rewrite of arch/arm/mach-ep93xx/core.c + * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> + * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org> + * + * Thanks go to Michael Burian and Ray Lehtiniemi for their key + * role in the ep93xx Linux community. + */ + +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/init.h> +#include <linux/mfd/syscon.h> +#include <linux/of.h> +#include <linux/of_fdt.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/sys_soc.h> + +#include <linux/soc/cirrus/ep93xx.h> + +#define EP93XX_SYSCON_DEVCFG 0x80 + +#define EP93XX_SWLOCK_MAGICK 0xaa +#define EP93XX_SYSCON_SWLOCK 0xc0 +#define EP93XX_SYSCON_SYSCFG 0x9c +#define EP93XX_SYSCON_SYSCFG_REV_MASK GENMASK(31, 28) +#define EP93XX_SYSCON_SYSCFG_REV_SHIFT 28 + +struct ep93xx_map_info { + spinlock_t lock; + void __iomem *base; + struct regmap *map; +}; + +/* + * EP93xx System Controller software locked register write + * + * Logic safeguards are included to condition the control signals for + * power connection to the matrix to prevent part damage. In addition, a + * software lock register is included that must be written with 0xAA + * before each register write to change the values of the four switch + * matrix control registers. + */ +static void ep93xx_regmap_write(struct regmap *map, spinlock_t *lock, + unsigned int reg, unsigned int val) +{ + guard(spinlock_irqsave)(lock); + + regmap_write(map, EP93XX_SYSCON_SWLOCK, EP93XX_SWLOCK_MAGICK); + regmap_write(map, reg, val); +} + +static void ep93xx_regmap_update_bits(struct regmap *map, spinlock_t *lock, + unsigned int reg, unsigned int mask, + unsigned int val) +{ + guard(spinlock_irqsave)(lock); + + regmap_write(map, EP93XX_SYSCON_SWLOCK, EP93XX_SWLOCK_MAGICK); + /* force write is required to clear swlock if no changes are made */ + regmap_update_bits_base(map, reg, mask, val, NULL, false, true); +} + +static void ep93xx_unregister_adev(void *_adev) +{ + struct auxiliary_device *adev = _adev; + + auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); +} + +static void ep93xx_adev_release(struct device *dev) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + struct ep93xx_regmap_adev *rdev = to_ep93xx_regmap_adev(adev); + + kfree(rdev); +} + +static struct auxiliary_device __init *ep93xx_adev_alloc(struct device *parent, + const char *name, + struct ep93xx_map_info *info) +{ + struct ep93xx_regmap_adev *rdev __free(kfree) = NULL; + struct auxiliary_device *adev; + int ret; + + rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); + if (!rdev) + return ERR_PTR(-ENOMEM); + + rdev->map = info->map; + rdev->base = info->base; + rdev->lock = &info->lock; + rdev->write = ep93xx_regmap_write; + rdev->update_bits = ep93xx_regmap_update_bits; + + adev = &rdev->adev; + adev->name = name; + adev->dev.parent = parent; + adev->dev.release = ep93xx_adev_release; + + ret = auxiliary_device_init(adev); + if (ret) + return ERR_PTR(ret); + + return &no_free_ptr(rdev)->adev; +} + +static int __init ep93xx_controller_register(struct device *parent, const char *name, + struct ep93xx_map_info *info) +{ + struct auxiliary_device *adev; + int ret; + + adev = ep93xx_adev_alloc(parent, name, info); + if (IS_ERR(adev)) + return PTR_ERR(adev); + + ret = auxiliary_device_add(adev); + if (ret) { + auxiliary_device_uninit(adev); + return ret; + } + + return devm_add_action_or_reset(parent, ep93xx_unregister_adev, adev); +} + +static unsigned int __init ep93xx_soc_revision(struct regmap *map) +{ + unsigned int val; + + regmap_read(map, EP93XX_SYSCON_SYSCFG, &val); + val &= EP93XX_SYSCON_SYSCFG_REV_MASK; + val >>= EP93XX_SYSCON_SYSCFG_REV_SHIFT; + return val; +} + +static const char __init *ep93xx_get_soc_rev(unsigned int rev) +{ + switch (rev) { + case EP93XX_CHIP_REV_D0: + return "D0"; + case EP93XX_CHIP_REV_D1: + return "D1"; + case EP93XX_CHIP_REV_E0: + return "E0"; + case EP93XX_CHIP_REV_E1: + return "E1"; + case EP93XX_CHIP_REV_E2: + return "E2"; + default: + return "unknown"; + } +} + +static const char *pinctrl_names[] __initconst = { + "pinctrl-ep9301", /* EP93XX_9301_SOC */ + "pinctrl-ep9307", /* EP93XX_9307_SOC */ + "pinctrl-ep9312", /* EP93XX_9312_SOC */ +}; + +static int __init ep93xx_syscon_probe(struct platform_device *pdev) +{ + enum ep93xx_soc_model model; + struct ep93xx_map_info *map_info; + struct soc_device_attribute *attrs; + struct soc_device *soc_dev; + struct device *dev = &pdev->dev; + struct regmap *map; + void __iomem *base; + unsigned int rev; + int ret; + + model = (enum ep93xx_soc_model)(uintptr_t)device_get_match_data(dev); + + map = device_node_to_regmap(dev->of_node); + if (IS_ERR(map)) + return PTR_ERR(map); + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + attrs = devm_kzalloc(dev, sizeof(*attrs), GFP_KERNEL); + if (!attrs) + return -ENOMEM; + + rev = ep93xx_soc_revision(map); + + attrs->machine = of_flat_dt_get_machine_name(); + attrs->family = "Cirrus Logic EP93xx"; + attrs->revision = ep93xx_get_soc_rev(rev); + + soc_dev = soc_device_register(attrs); + if (IS_ERR(soc_dev)) + return PTR_ERR(soc_dev); + + map_info = devm_kzalloc(dev, sizeof(*map_info), GFP_KERNEL); + if (!map_info) + return -ENOMEM; + + spin_lock_init(&map_info->lock); + map_info->map = map; + map_info->base = base; + + ret = ep93xx_controller_register(dev, pinctrl_names[model], map_info); + if (ret) + dev_err(dev, "registering pinctrl controller failed\n"); + + /* + * EP93xx SSP clock rate was doubled in version E2. For more information + * see section 6 "2x SSP (Synchronous Serial Port) Clock – Revision E2 only": + * http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf + */ + if (rev == EP93XX_CHIP_REV_E2) + ret = ep93xx_controller_register(dev, "clk-ep93xx.e2", map_info); + else + ret = ep93xx_controller_register(dev, "clk-ep93xx", map_info); + if (ret) + dev_err(dev, "registering clock controller failed\n"); + + ret = ep93xx_controller_register(dev, "reset-ep93xx", map_info); + if (ret) + dev_err(dev, "registering reset controller failed\n"); + + return 0; +} + +static const struct of_device_id ep9301_syscon_of_device_ids[] = { + { .compatible = "cirrus,ep9301-syscon", .data = (void *)EP93XX_9301_SOC }, + { .compatible = "cirrus,ep9302-syscon", .data = (void *)EP93XX_9301_SOC }, + { .compatible = "cirrus,ep9307-syscon", .data = (void *)EP93XX_9307_SOC }, + { .compatible = "cirrus,ep9312-syscon", .data = (void *)EP93XX_9312_SOC }, + { .compatible = "cirrus,ep9315-syscon", .data = (void *)EP93XX_9312_SOC }, + { /* sentinel */ } +}; + +static struct platform_driver ep9301_syscon_driver = { + .driver = { + .name = "ep9301-syscon", + .of_match_table = ep9301_syscon_of_device_ids, + }, +}; +builtin_platform_driver_probe(ep9301_syscon_driver, ep93xx_syscon_probe); diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index a1d60e51c053..dc6bdc74643d 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -18,18 +18,18 @@ #include <linux/err.h> #include <linux/delay.h> #include <linux/device.h> +#include <linux/dma-direction.h> +#include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/bitops.h> #include <linux/interrupt.h> #include <linux/module.h> +#include <linux/property.h> #include <linux/platform_device.h> #include <linux/sched.h> #include <linux/scatterlist.h> #include <linux/spi/spi.h> -#include <linux/platform_data/dma-ep93xx.h> -#include <linux/platform_data/spi-ep93xx.h> - #define SSPCR0 0x0000 #define SSPCR0_SPO BIT(6) #define SSPCR0_SPH BIT(7) @@ -76,8 +76,6 @@ * frame decreases this level and sending one frame increases it. * @dma_rx: RX DMA channel * @dma_tx: TX DMA channel - * @dma_rx_data: RX parameters passed to the DMA engine - * @dma_tx_data: TX parameters passed to the DMA engine * @rx_sgt: sg table for RX transfers * @tx_sgt: sg table for TX transfers * @zeropage: dummy page used as RX buffer when only TX buffer is passed in by @@ -92,8 +90,6 @@ struct ep93xx_spi { size_t fifo_level; struct dma_chan *dma_rx; struct dma_chan *dma_tx; - struct ep93xx_dma_data dma_rx_data; - struct ep93xx_dma_data dma_tx_data; struct sg_table rx_sgt; struct sg_table tx_sgt; void *zeropage; @@ -575,46 +571,23 @@ static int ep93xx_spi_unprepare_hardware(struct spi_controller *host) return 0; } -static bool ep93xx_spi_dma_filter(struct dma_chan *chan, void *filter_param) +static int ep93xx_spi_setup_dma(struct device *dev, struct ep93xx_spi *espi) { - if (ep93xx_dma_chan_is_m2p(chan)) - return false; - - chan->private = filter_param; - return true; -} - -static int ep93xx_spi_setup_dma(struct ep93xx_spi *espi) -{ - dma_cap_mask_t mask; int ret; espi->zeropage = (void *)get_zeroed_page(GFP_KERNEL); if (!espi->zeropage) return -ENOMEM; - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - espi->dma_rx_data.port = EP93XX_DMA_SSP; - espi->dma_rx_data.direction = DMA_DEV_TO_MEM; - espi->dma_rx_data.name = "ep93xx-spi-rx"; - - espi->dma_rx = dma_request_channel(mask, ep93xx_spi_dma_filter, - &espi->dma_rx_data); - if (!espi->dma_rx) { - ret = -ENODEV; + espi->dma_rx = dma_request_chan(dev, "rx"); + if (IS_ERR(espi->dma_rx)) { + ret = dev_err_probe(dev, PTR_ERR(espi->dma_rx), "rx DMA setup failed"); goto fail_free_page; } - espi->dma_tx_data.port = EP93XX_DMA_SSP; - espi->dma_tx_data.direction = DMA_MEM_TO_DEV; - espi->dma_tx_data.name = "ep93xx-spi-tx"; - - espi->dma_tx = dma_request_channel(mask, ep93xx_spi_dma_filter, - &espi->dma_tx_data); - if (!espi->dma_tx) { - ret = -ENODEV; + espi->dma_tx = dma_request_chan(dev, "tx"); + if (IS_ERR(espi->dma_tx)) { + ret = dev_err_probe(dev, PTR_ERR(espi->dma_tx), "tx DMA setup failed"); goto fail_release_rx; } @@ -647,18 +620,11 @@ static void ep93xx_spi_release_dma(struct ep93xx_spi *espi) static int ep93xx_spi_probe(struct platform_device *pdev) { struct spi_controller *host; - struct ep93xx_spi_info *info; struct ep93xx_spi *espi; struct resource *res; int irq; int error; - info = dev_get_platdata(&pdev->dev); - if (!info) { - dev_err(&pdev->dev, "missing platform data\n"); - return -EINVAL; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -713,12 +679,17 @@ static int ep93xx_spi_probe(struct platform_device *pdev) goto fail_release_host; } - if (info->use_dma && ep93xx_spi_setup_dma(espi)) + error = ep93xx_spi_setup_dma(&pdev->dev, espi); + if (error == -EPROBE_DEFER) + goto fail_release_host; + + if (error) dev_warn(&pdev->dev, "DMA setup failed. Falling back to PIO\n"); /* make sure that the hardware is disabled */ writel(0, espi->mmio + SSPCR1); + device_set_node(&host->dev, dev_fwnode(&pdev->dev)); error = devm_spi_register_controller(&pdev->dev, host); if (error) { dev_err(&pdev->dev, "failed to register SPI host\n"); @@ -746,9 +717,16 @@ static void ep93xx_spi_remove(struct platform_device *pdev) ep93xx_spi_release_dma(espi); } +static const struct of_device_id ep93xx_spi_of_ids[] = { + { .compatible = "cirrus,ep9301-spi" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ep93xx_spi_of_ids); + static struct platform_driver ep93xx_spi_driver = { .driver = { .name = "ep93xx-spi", + .of_match_table = ep93xx_spi_of_ids, }, .probe = ep93xx_spi_probe, .remove_new = ep93xx_spi_remove, diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c index 3d57670befe1..ac709dc31a65 100644 --- a/drivers/watchdog/ts72xx_wdt.c +++ b/drivers/watchdog/ts72xx_wdt.c @@ -12,6 +12,7 @@ */ #include <linux/platform_device.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/watchdog.h> #include <linux/io.h> @@ -160,10 +161,17 @@ static int ts72xx_wdt_probe(struct platform_device *pdev) return 0; } +static const struct of_device_id ts72xx_wdt_of_ids[] = { + { .compatible = "technologic,ts7200-wdt" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ts72xx_wdt_of_ids); + static struct platform_driver ts72xx_wdt_driver = { .probe = ts72xx_wdt_probe, .driver = { .name = "ts72xx-wdt", + .of_match_table = ts72xx_wdt_of_ids, }, }; |