Hi Lucas,

On Fri, May 10, 2013 at 08:28:57PM +0200, Lucas Stach wrote:
> This adds a pinctrl driver for the Tegra 20 line of SoCs. It only
> supports the three basic pinconfiguration settings function mux,
> tristate control and pullup/down control.
> 
> The driver understands the same devicetree bindings as the Linux one,
> unimplemented pinconfiguration options will be ignored.
> 
> Signed-off-by: Lucas Stach <d...@lynxeye.de>
> ---
> v2:
> - use named regs
> - check for return value of request_mem_region
> ---
>  arch/arm/dts/tegra20.dtsi         |   8 +
>  arch/arm/mach-tegra/Kconfig       |   1 +
>  drivers/pinctrl/Kconfig           |   6 +
>  drivers/pinctrl/Makefile          |   1 +
>  drivers/pinctrl/pinctrl-tegra20.c | 346 
> ++++++++++++++++++++++++++++++++++++++
>  5 files changed, 362 insertions(+)
>  create mode 100644 drivers/pinctrl/pinctrl-tegra20.c
> 
> diff --git a/arch/arm/dts/tegra20.dtsi b/arch/arm/dts/tegra20.dtsi
> index b7d1e27..f63ead8 100644
> --- a/arch/arm/dts/tegra20.dtsi
> +++ b/arch/arm/dts/tegra20.dtsi
> @@ -34,6 +34,14 @@
>               interrupt-controller;
>       };
>  
> +     pinmux: pinmux {
> +     compatible = "nvidia,tegra20-pinmux";
> +     reg = <0x70000014 0x10   /* Tri-state registers */
> +            0x70000080 0x20   /* Mux registers */
> +            0x700000a0 0x14   /* Pull-up/down registers */
> +            0x70000868 0xa8>; /* Pad control registers */
> +     };
> +
>       pmc {
>               compatible = "nvidia,tegra20-pmc";
>               reg = <0x7000e400 0x400>;
> diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
> index 965e7ab..53ae070 100644
> --- a/arch/arm/mach-tegra/Kconfig
> +++ b/arch/arm/mach-tegra/Kconfig
> @@ -5,6 +5,7 @@ choice
>  
>  config ARCH_TEGRA_2x_SOC
>       bool "Tegra 20"
> +     select PINCTRL_TEGRA20
>  
>  endchoice
>  
> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
> index e6aee50..0b859b8 100644
> --- a/drivers/pinctrl/Kconfig
> +++ b/drivers/pinctrl/Kconfig
> @@ -25,4 +25,10 @@ config PINCTRL_IMX_IOMUX_V3
>       help
>         This iomux controller is found on i.MX25,35,51,53,6.
>  
> +config PINCTRL_TEGRA20
> +     select PINCTRL
> +     bool "Tegra 20 pinmux"
> +     help
> +       The pinmux controller found on the Tegra 20 line of SoCs.
> +
>  endmenu
> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
> index e9272d0..169ed18 100644
> --- a/drivers/pinctrl/Makefile
> +++ b/drivers/pinctrl/Makefile
> @@ -2,3 +2,4 @@ obj-$(CONFIG_PINCTRL) += pinctrl.o
>  obj-$(CONFIG_PINCTRL_IMX_IOMUX_V1) += imx-iomux-v1.o
>  obj-$(CONFIG_PINCTRL_IMX_IOMUX_V2) += imx-iomux-v2.o
>  obj-$(CONFIG_PINCTRL_IMX_IOMUX_V3) += imx-iomux-v3.o
> +obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o
> diff --git a/drivers/pinctrl/pinctrl-tegra20.c 
> b/drivers/pinctrl/pinctrl-tegra20.c
> new file mode 100644
> index 0000000..053981f
> --- /dev/null
> +++ b/drivers/pinctrl/pinctrl-tegra20.c
> @@ -0,0 +1,346 @@
> +/*
> + * Copyright (C) 2013 Lucas Stach <l.st...@pengutronix.de>
> + *
> + * Partly based on code
> + * Copyright (C) 2011-2012 NVIDIA Corporation <www.nvidia.com>
> + * Copyright (C) 2010 Google, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/**
> + * @file
> + * @brief Device driver for the Tegra 20 pincontrol hardware module.
> + */
> +
> +#include <common.h>
> +#include <init.h>
> +#include <io.h>
> +#include <malloc.h>
> +#include <pinctrl.h>
> +
> +struct pinctrl_tegra20 {
> +     struct {
> +             u32 __iomem *tri;
> +             u32 __iomem *mux;
> +             u32 __iomem *pull;
> +     } regs;
> +     struct pinctrl_device pinctrl;
> +};
> +
> +struct tegra20_pingroup {
> +     const char *name;
> +     const char *funcs[4];
> +     s16 trictrl_id;
> +     s16 muxctrl_id;
> +     s16 pullctrl_id;
> +};
> +
> +#define PG(pg_name, f0, f1, f2, f3, tri, mux, pull)  \
> +     {                                               \
> +             .name = #pg_name,                       \
> +             .funcs = { #f0, #f1, #f2, #f3, },       \
> +             .trictrl_id = tri,                      \
> +             .muxctrl_id = mux,                      \
> +             .pullctrl_id = pull                     \
> +     }
> +
> +static const struct tegra20_pingroup tegra20_groups[] = {
> +     /* name,   f0,        f1,        f2,        f3,            tri,     
> mux,     pull */
> +     PG(ata,    ide,       nand,      gmi,       rsvd4,         0,       12, 
>      0  ),
> +     PG(atb,    ide,       nand,      gmi,       sdio4,         1,       8,  
>      1  ),
> +     PG(atc,    ide,       nand,      gmi,       sdio4,         2,       11, 
>      2  ),
> +     PG(atd,    ide,       nand,      gmi,       sdio4,         3,       10, 
>      3  ),
> +     PG(ate,    ide,       nand,      gmi,       rsvd4,         57,      6,  
>      4  ),
> +     PG(cdev1,  osc,       plla_out,  pllm_out1, audio_sync,    4,       33, 
>      32 ),
> +     PG(cdev2,  osc,       ahb_clk,   apb_clk,   pllp_out4,     5,       34, 
>      33 ),
> +     PG(crtp,   crt,       rsvd2,     rsvd3,     rsvd4,         110,     
> 105,     28 ),
> +     PG(csus,   pllc_out1, pllp_out2, pllp_out3, vi_sensor_clk, 6,       35, 
>      60 ),
> +     PG(dap1,   dap1,      rsvd2,     gmi,       sdio2,         7,       42, 
>      5  ),
> +     PG(dap2,   dap2,      twc,       rsvd3,     gmi,           8,       43, 
>      6  ),
> +     PG(dap3,   dap3,      rsvd2,     rsvd3,     rsvd4,         9,       44, 
>      7  ),
> +     PG(dap4,   dap4,      rsvd2,     gmi,       rsvd4,         10,      45, 
>      8  ),
> +     PG(ddc,    i2c2,      rsvd2,     rsvd3,     rsvd4,         63,      32, 
>      78 ),
> +     PG(dta,    rsvd1,     sdio2,     vi,        rsvd4,         11,      26, 
>      9  ),
> +     PG(dtb,    rsvd1,     rsvd2,     vi,        spi1,          12,      27, 
>      10 ),
> +     PG(dtc,    rsvd1,     rsvd2,     vi,        rsvd4,         13,      29, 
>      11 ),
> +     PG(dtd,    rsvd1,     sdio2,     vi,        rsvd4,         14,      30, 
>      12 ),
> +     PG(dte,    rsvd1,     rsvd2,     vi,        spi1,          15,      31, 
>      13 ),
> +     PG(dtf,    i2c3,      rsvd2,     vi,        rsvd4,         108,     
> 110,     14 ),
> +     PG(gma,    uarte,     spi3,      gmi,       sdio4,         28,      16, 
>      74 ),
> +     PG(gmb,    ide,       nand,      gmi,       gmi_int,       61,      46, 
>      75 ),
> +     PG(gmc,    uartd,     spi4,      gmi,       sflash,        29,      17, 
>      76 ),
> +     PG(gmd,    rsvd1,     nand,      gmi,       sflash,        62,      47, 
>      77 ),
> +     PG(gme,    rsvd1,     dap5,      gmi,       sdio4,         32,      48, 
>      44 ),
> +     PG(gpu,    pwm,       uarta,     gmi,       rsvd4,         16,      50, 
>      26 ),
> +     PG(gpu7,   rtck,      rsvd2,     rsvd3,     rsvd4,         107,     
> 109,     19 ),
> +     PG(gpv,    pcie,      rsvd2,     rsvd3,     rsvd4,         17,      49, 
>      15 ),
> +     PG(hdint,  hdmi,      rsvd2,     rsvd3,     rsvd4,         87,      18, 
>      -1 ),
> +     PG(i2cp,   i2cp,      rsvd2,     rsvd3,     rsvd4,         18,      36, 
>      17 ),
> +     PG(irrx,   uarta,     uartb,     gmi,       spi4,          20,      41, 
>      43 ),
> +     PG(irtx,   uarta,     uartb,     gmi,       spi4,          19,      40, 
>      42 ),
> +     PG(kbca,   kbc,       nand,      sdio2,     emc_test0_dll, 22,      37, 
>      20 ),
> +     PG(kbcb,   kbc,       nand,      sdio2,     mio,           21,      38, 
>      21 ),
> +     PG(kbcc,   kbc,       nand,      trace,     emc_test1_dll, 58,      39, 
>      22 ),
> +     PG(kbcd,   kbc,       nand,      sdio2,     mio,           106,     
> 108,     23 ),
> +     PG(kbce,   kbc,       nand,      owr,       rsvd4,         26,      14, 
>      65 ),
> +     PG(kbcf,   kbc,       nand,      trace,     mio,           27,      13, 
>      64 ),
> +     PG(lcsn,   displaya,  displayb,  spi3,      rsvd4,         95,      70, 
>      -1 ),
> +     PG(ld0,    displaya,  displayb,  xio,       rsvd4,         64,      80, 
>      -1 ),
> +     PG(ld1,    displaya,  displayb,  xio,       rsvd4,         65,      81, 
>      -1 ),
> +     PG(ld2,    displaya,  displayb,  xio,       rsvd4,         66,      82, 
>      -1 ),
> +     PG(ld3,    displaya,  displayb,  xio,       rsvd4,         67,      83, 
>      -1 ),
> +     PG(ld4,    displaya,  displayb,  xio,       rsvd4,         68,      84, 
>      -1 ),
> +     PG(ld5,    displaya,  displayb,  xio,       rsvd4,         69,      85, 
>      -1 ),
> +     PG(ld6,    displaya,  displayb,  xio,       rsvd4,         70,      86, 
>      -1 ),
> +     PG(ld7,    displaya,  displayb,  xio,       rsvd4,         71,      87, 
>      -1 ),
> +     PG(ld8,    displaya,  displayb,  xio,       rsvd4,         72,      88, 
>      -1 ),
> +     PG(ld9,    displaya,  displayb,  xio,       rsvd4,         73,      89, 
>      -1 ),
> +     PG(ld10,   displaya,  displayb,  xio,       rsvd4,         74,      90, 
>      -1 ),
> +     PG(ld11,   displaya,  displayb,  xio,       rsvd4,         75,      91, 
>      -1 ),
> +     PG(ld12,   displaya,  displayb,  xio,       rsvd4,         76,      92, 
>      -1 ),
> +     PG(ld13,   displaya,  displayb,  xio,       rsvd4,         77,      93, 
>      -1 ),
> +     PG(ld14,   displaya,  displayb,  xio,       rsvd4,         78,      94, 
>      -1 ),
> +     PG(ld15,   displaya,  displayb,  xio,       rsvd4,         79,      95, 
>      -1 ),
> +     PG(ld16,   displaya,  displayb,  xio,       rsvd4,         80,      96, 
>      -1 ),
> +     PG(ld17,   displaya,  displayb,  rsvd3,     rsvd4,         81,      97, 
>      -1 ),
> +     PG(ldc,    displaya,  displayb,  rsvd3,     rsvd4,         94,      71, 
>      -1 ),
> +     PG(ldi,    displaya,  displayb,  rsvd3,     rsvd4,         102,     
> 104,     -1 ),
> +     PG(lhp0,   displaya,  displayb,  rsvd3,     rsvd4,         82,      
> 101,     -1 ),
> +     PG(lhp1,   displaya,  displayb,  rsvd3,     rsvd4,         83,      98, 
>      -1 ),
> +     PG(lhp2,   displaya,  displayb,  rsvd3,     rsvd4,         84,      99, 
>      -1 ),
> +     PG(lhs,    displaya,  displayb,  xio,       rsvd4,         103,     75, 
>      -1 ),
> +     PG(lm0,    displaya,  displayb,  spi3,      rsvd4,         88,      77, 
>      -1 ),
> +     PG(lm1,    displaya,  displayb,  rsvd3,     CRT,           89,      78, 
>      -1 ),
> +     PG(lpp,    displaya,  displayb,  rsvd3,     rsvd4,         104,     
> 103,     -1 ),
> +     PG(lpw0,   displaya,  displayb,  spi3,      hdmi,          99,      64, 
>      -1 ),
> +     PG(lpw1,   displaya,  displayb,  rsvd3,     rsvd4,         100,     65, 
>      -1 ),
> +     PG(lpw2,   displaya,  displayb,  spi3,      hdmi,          101,     66, 
>      -1 ),
> +     PG(lsc0,   displaya,  displayb,  xio,       rsvd4,         91,      73, 
>      -1 ),
> +     PG(lsc1,   displaya,  displayb,  spi3,      hdmi,          92,      74, 
>      -1 ),
> +     PG(lsck,   displaya,  displayb,  spi3,      hdmi,          93,      72, 
>      -1 ),
> +     PG(lsda,   displaya,  displayb,  spi3,      hdmi,          97,      68, 
>      -1 ),
> +     PG(lsdi,   displaya,  displayb,  spi3,      rsvd4,         98,      67, 
>      -1 ),
> +     PG(lspi,   displaya,  displayb,  xio,       hdmi,          96,      69, 
>      -1 ),
> +     PG(lvp0,   displaya,  displayb,  rsvd3,     rsvd4,         85,      79, 
>      -1 ),
> +     PG(lvp1,   displaya,  displayb,  rsvd3,     rsvd4,         86,      
> 100,     -1 ),
> +     PG(lvs,    displaya,  displayb,  xio,       rsvd4,         90,      76, 
>      -1 ),
> +     PG(owc,    owr,       rsvd2,     rsvd3,     rsvd4,         31,      20, 
>      79 ),
> +     PG(pmc,    pwr_on,    pwr_intr,  rsvd3,     rsvd4,         23,      
> 105,     -1 ),
> +     PG(pta,    i2c2,      hdmi,      gmi,       rsvd4,         24,      
> 107,     18 ),
> +     PG(rm,     i2c1,      rsvd2,     rsvd3,     rsvd4,         25,      7,  
>      16 ),
> +     PG(sdb,    uarta,     pwm,       sdio3,     spi2,          111,     53, 
>      -1 ),
> +     PG(sdc,    pwm,       twc,       sdio3,     spi3,          33,      54, 
>      62 ),
> +     PG(sdd,    uarta,     pwm,       sdio3,     spi3,          34,      55, 
>      63 ),
> +     PG(sdio1,  sdio1,     rsvd2,     uarte,     uarta,         30,      15, 
>      73 ),
> +     PG(slxa,   pcie,      spi4,      sdio3,     spi2,          36,      19, 
>      27 ),
> +     PG(slxc,   spdif,     spi4,      sdio3,     spi2,          37,      21, 
>      29 ),
> +     PG(slxd,   spdif,     spi4,      sdio3,     spi2,          38,      22, 
>      30 ),
> +     PG(slxk,   pcie,      spi4,      sdio3,     spi2,          39,      23, 
>      31 ),
> +     PG(spdi,   spdif,     rsvd2,     i2c1,      sdio2,         40,      52, 
>      24 ),
> +     PG(spdo,   spdif,     rsvd2,     i2c1,      sdio2,         41,      51, 
>      25 ),
> +     PG(spia,   spi1,      spi2,      spi3,      gmi,           42,      63, 
>      34 ),
> +     PG(spib,   spi1,      spi2,      spi3,      gmi,           43,      62, 
>      35 ),
> +     PG(spic,   spi1,      spi2,      spi3,      gmi,           44,      61, 
>      36 ),
> +     PG(spid,   spi2,      spi1,      spi2_alt,  gmi,           45,      60, 
>      37 ),
> +     PG(spie,   spi2,      spi1,      spi2_alt,  gmi,           46,      59, 
>      38 ),
> +     PG(spif,   spi3,      spi1,      spi2,      rsvd4,         47,      58, 
>      39 ),
> +     PG(spig,   spi3,      spi2,      spi2_alt,  i2c1,          48,      57, 
>      40 ),
> +     PG(spih,   spi3,      spi2,      spi2_alt,  i2c1,          49,      56, 
>      41 ),
> +     PG(uaa,    spi3,      mipi_hs,   uarta,     ulpi,          50,      0,  
>      48 ),
> +     PG(uab,    spi2,      mipi_hs,   uarta,     ulpi,          51,      1,  
>      49 ),
> +     PG(uac,    owr,       rsvd2,     rsvd3,     rsvd4,         52,      2,  
>      50 ),
> +     PG(uad,    irda,      spdif,     uarta,     spi4,          53,      3,  
>      51 ),
> +     PG(uca,    uartc,     rsvd2,     gmi,       rsvd4,         54,      24, 
>      52 ),
> +     PG(ucb,    uartc,     pwm,       gmi,       rsvd4,         55,      25, 
>      53 ),
> +     PG(uda,    spi1,      rsvd2,     uartd,     ulpi,          109,     4,  
>      72 ),
> +};
> +
> +static void pinctrl_tegra20_set_func(struct pinctrl_tegra20 *ctrl,
> +                                  int muxctrl_id, int func)
> +{
> +     u32 __iomem *regaddr = ctrl->regs.mux;
> +     u32 reg;
> +     int maskbit;
> +
> +     regaddr += muxctrl_id >> 4;
> +     maskbit = (muxctrl_id << 1) & 0x1f;
> +
> +     reg = readl(regaddr);
> +     reg &= ~(0x3 << maskbit);
> +     reg |= func << maskbit;
> +     writel(reg, regaddr);
> +}
> +
> +static void pinctrl_tegra20_set_pull(struct pinctrl_tegra20 *ctrl,
> +                                  int pullctrl_id, int pull)
> +{
> +     u32 __iomem *regaddr = ctrl->regs.pull;
> +     u32 reg;
> +     int maskbit;
> +
> +     regaddr += pullctrl_id >> 4;
> +     maskbit = (pullctrl_id << 1) & 0x1f;
> +
> +     reg = readl(regaddr);
> +     reg &= ~(0x3 << maskbit);
> +     reg |= pull << maskbit;
> +     writel(reg, regaddr);
> +}
> +
> +static void pinctrl_tegra20_set_tristate(struct pinctrl_tegra20 *ctrl,
> +                                      int trictrl_id, int tristate)
> +{
> +     u32 __iomem *regaddr = ctrl->regs.tri;
> +     u32 reg;
> +     int maskbit;
> +
> +     regaddr += trictrl_id >> 5;
> +     maskbit = trictrl_id & 0x1f;
> +
> +     reg = readl(regaddr);
> +     reg &= ~(1 << maskbit);
> +     reg |= tristate << maskbit;
> +     writel(reg, regaddr);
> +}
> +
> +static int pinctrl_tegra20_set_state(struct pinctrl_device *pdev,
> +                                  struct device_node *np)
> +{
> +     struct pinctrl_tegra20 *ctrl =
> +                     container_of(pdev, struct pinctrl_tegra20, pinctrl);
> +     struct device_node *childnode;
> +     int pull = -1, tri = -1, i, j, k;
> +     const char *pins, *func = NULL;
> +     const struct tegra20_pingroup *group;
> +
> +     /*
> +      * At first look if the node we are pointed at has children,
> +      * which we may want to visit.
> +      */
> +     list_for_each_entry(childnode, &np->children, parent_list)
> +             pinctrl_tegra20_set_state(pdev, childnode);
> +
> +     /* read relevant state from devicetree */
> +     of_property_read_string(np, "nvidia,function", &func);
> +     of_property_read_u32_array(np, "nvidia,pull", &pull, 1);
> +     of_property_read_u32_array(np, "nvidia,tristate", &tri, 1);
> +
> +     /* iterate over all pingroups referenced in the dt node */
> +     for (i = 0; ; i++) {
> +             if (of_property_read_string_index(np, "nvidia,pins", i, &pins))
> +                     break;
> +
> +             for (j = 0; j < ARRAY_SIZE(tegra20_groups); j++) {
> +                     if (!strcmp(pins, tegra20_groups[j].name)) {
> +                             group = &tegra20_groups[j];
> +                             break;
> +                     }
> +             }
> +             /* if no matching pingroup is found bail out */
> +             if (j == ARRAY_SIZE(tegra20_groups)) {
> +                     dev_warn(ctrl->pinctrl.dev,
> +                              "invalid pingroup %s referenced in node %s\n",
> +                              pins, np->name);
> +                     continue;
> +             }
> +
> +             if (func) {
> +                     for (k = 0; k < 4; k++) {
> +                             if (!strcmp(func, group->funcs[k]))
> +                                     break;
> +                     }
> +                     if (k < 4)
> +                             pinctrl_tegra20_set_func(ctrl,
> +                                                      group->muxctrl_id, k);
> +                     else
> +                             dev_warn(ctrl->pinctrl.dev,
> +                                      "invalid function %s for pingroup %s 
> in node %s\n",
> +                                      func, group->name, np->name);
> +             }
> +
> +             if (pull >= 0) {
> +                     if (group->pullctrl_id >= 0)
> +                             pinctrl_tegra20_set_pull(ctrl,
> +                                                      group->pullctrl_id,
> +                                                      pull);
> +                     else
> +                             dev_warn(ctrl->pinctrl.dev,
> +                                      "pingroup %s in node %s doesn't 
> support pull configuration\n",
> +                                      group->name, np->name);
> +             }
> +
> +             if (tri >= 0)
> +                     pinctrl_tegra20_set_tristate(ctrl,
> +                                                  group->trictrl_id, tri);
> +     }
> +
> +     return 0;
> +}
> +
> +static struct pinctrl_ops pinctrl_tegra20_ops = {
> +     .set_state = pinctrl_tegra20_set_state,
> +};
> +
> +static int pinctrl_tegra20_probe(struct device_d *dev)
> +{
> +     struct pinctrl_tegra20 *ctrl;
> +     int i, ret;
> +     u32 **regs;
> +
> +     ctrl = xzalloc(sizeof(*ctrl));
> +
> +     /*
> +      * Tegra pincontrol is split out into four independent memory ranges:
> +      * tristate control, function mux, pullup/down control, pad control
> +      * (from lowest to highest hardware address).
> +      * We are only interested in the first three for now.
> +      */
> +     regs = (u32 **)&ctrl->regs;
> +     for (i = 0; i <= 2; i++) {
> +             regs[i] = dev_request_mem_region(dev, i);
> +             if (!regs[i]) {
> +                     dev_err(dev, "Could not get iomem region %d\n", i);
Do we need a free(ctrl); here?

Regards
Alex

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

Reply via email to