From mboxrd@z Thu Jan 1 00:00:00 1970 From: zonque@gmail.com (Daniel Mack) Date: Sat, 28 Jul 2012 12:22:31 +0200 Subject: [PATCH 2/6] pinctrl: add pinconf support in pxa3xx In-Reply-To: <1343458722-17127-3-git-send-email-haojian.zhuang@gmail.com> References: <1343458722-17127-1-git-send-email-haojian.zhuang@gmail.com> <1343458722-17127-3-git-send-email-haojian.zhuang@gmail.com> Message-ID: <5013BD67.7020907@gmail.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org On 28.07.2012 08:58, Haojian Zhuang wrote: > Signed-off-by: Haojian Zhuang > --- > drivers/pinctrl/pinctrl-pxa3xx.c | 189 ++++++++++++++++++++++++++++++++++++++ > drivers/pinctrl/pinctrl-pxa3xx.h | 17 ++++ > 2 files changed, 206 insertions(+) As I'm working on a PXA3xx platform currently that already fully boots from DT, I'd like to give this series a try. But I wonder if this is supposed to be fully working yet, because that code won't be compiled for PXA3xx as long as PINCTRL isn't set for that platform (arch/arm/mach-pxa/Kconfig). Daniel > > diff --git a/drivers/pinctrl/pinctrl-pxa3xx.c b/drivers/pinctrl/pinctrl-pxa3xx.c > index f14cd6b..cae74db 100644 > --- a/drivers/pinctrl/pinctrl-pxa3xx.c > +++ b/drivers/pinctrl/pinctrl-pxa3xx.c > @@ -16,6 +16,8 @@ > #include > #include > #include > +#include > +#include > #include "pinctrl-pxa3xx.h" > > static struct pinctrl_gpio_range pxa3xx_pinctrl_gpio_range = { > @@ -168,6 +170,192 @@ static struct pinmux_ops pxa3xx_pmx_ops = { > .gpio_request_enable = pxa3xx_pmx_request_gpio, > }; > > +static int pxa3xx_pinconf_get(struct pinctrl_dev *pctrldev, > + unsigned pin, unsigned long *config) > +{ > + struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); > + unsigned int data, mask; > + int mfpr; > + > + mfpr = info->mfp[pin].mfpr; > + data = readl_relaxed(info->virt_base + mfpr); > + > + *config = 0; > + mask = PXA3XX_MFPR_PULL_SEL | PXA3XX_MFPR_PULL_UP; > + if ((data & mask) == mask) > + *config |= PXA3XX_PINCONF_PULL_UP; > + mask = PXA3XX_MFPR_PULL_SEL | PXA3XX_MFPR_PULL_DOWN; > + if ((data & mask) == mask) > + *config |= PXA3XX_PINCONF_PULL_DOWN; > + mask = info->ds_mask; > + if (data & mask) { > + *config |= PXA3XX_PINCONF_DRIVE_STRENGTH; > + *config |= ((data & mask) >> info->ds_shift) > + << PXA3XX_PINCONF_DS_SHIFT; > + } > + mask = info->slp_mask; > + if (data & mask) { > + if (data & info->slp_input_low) > + *config |= PXA3XX_PINCONF_LOWPOWER_PULL_DOWN; > + if (data & info->slp_input_high) > + *config |= PXA3XX_PINCONF_LOWPOWER_PULL_UP; > + if (data & info->slp_output_low) > + *config |= PXA3XX_PINCONF_LOWPOWER_DRIVE_LOW; > + if (data & info->slp_output_high) > + *config |= PXA3XX_PINCONF_LOWPOWER_DRIVE_HIGH; > + if (data & info->slp_float) > + *config |= PXA3XX_PINCONF_LOWPOWER_FLOAT; > + } else > + *config |= PXA3XX_PINCONF_LOWPOWER_ZERO; > + return 0; > +} > + > +static int pxa3xx_pinconf_set(struct pinctrl_dev *pctrldev, > + unsigned pin, unsigned long config) > +{ > + struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); > + unsigned int data; > + int mfpr; > + > + mfpr = info->mfp[pin].mfpr; > + data = readl_relaxed(info->virt_base + mfpr); > + switch (config & PXA3XX_PINCONF_MASK) { > + case PXA3XX_PINCONF_PULL_DOWN: > + data |= PXA3XX_MFPR_PULL_SEL | PXA3XX_MFPR_PULL_DOWN; > + break; > + case PXA3XX_PINCONF_PULL_UP: > + data |= PXA3XX_MFPR_PULL_SEL | PXA3XX_MFPR_PULL_UP; > + break; > + case PXA3XX_PINCONF_DRIVE_STRENGTH: > + data &= ~info->ds_mask; > + data |= (config >> PXA3XX_PINCONF_DS_SHIFT) << info->ds_shift; > + break; > + case PXA3XX_PINCONF_LOWPOWER_DRIVE_HIGH: > + data &= ~info->slp_mask; > + data |= info->slp_output_high; > + break; > + case PXA3XX_PINCONF_LOWPOWER_DRIVE_LOW: > + data &= ~info->slp_mask; > + data |= info->slp_output_low; > + break; > + case PXA3XX_PINCONF_LOWPOWER_PULL_UP: > + data &= ~info->slp_mask; > + data |= info->slp_input_high; > + break; > + case PXA3XX_PINCONF_LOWPOWER_PULL_DOWN: > + data &= ~info->slp_mask; > + data |= info->slp_input_low; > + break; > + case PXA3XX_PINCONF_LOWPOWER_FLOAT: > + data &= ~info->slp_mask; > + data |= info->slp_float; > + break; > + case PXA3XX_PINCONF_LOWPOWER_ZERO: > + data &= ~info->slp_mask; > + break; > + default: > + return -ENOTSUPP; > + } > + writel_relaxed(data, info->virt_base + mfpr); > + return 0; > +} > + > +static int pxa3xx_pinconf_group_get(struct pinctrl_dev *pctrldev, > + unsigned group, unsigned long *config) > +{ > + struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); > + const unsigned *pins = info->grps[group].pins; > + int npins, i; > + unsigned long conf, match = 0; > + > + npins = info->grps[group].npins; > + for (i = 0; i < npins; i++) { > + pxa3xx_pinconf_get(pctrldev, pins[i], &conf); > + if (!match) > + match = conf; > + else if (match != conf) { > + *config = conf; > + return -EINVAL; > + } > + } > + *config = conf; > + return 0; > +} > + > +static int pxa3xx_pinconf_group_set(struct pinctrl_dev *pctrldev, > + unsigned group, unsigned long config) > +{ > + struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); > + const unsigned *pins = info->grps[group].pins; > + int npins, i; > + > + npins = info->grps[group].npins; > + for (i = 0; i < npins; i++) > + pxa3xx_pinconf_set(pctrldev, pins[i], config); > + return 0; > +} > + > +static void pxa3xx_pinconf_dbg_show(struct pinctrl_dev *pctrldev, > + struct seq_file *s, unsigned offset) > +{ > + struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); > + unsigned long config; > + char buf[80]; > + int i = 0, mfpr; > + > + pxa3xx_pinconf_get(pctrldev, offset, &config); > + memset(buf, 0, 80); > + if (config & PXA3XX_PINCONF_PULL_UP) > + i += sprintf(buf + i, "PULL UP, "); > + if (config & PXA3XX_PINCONF_PULL_DOWN) > + i += sprintf(buf + i, "PULL DOWN, "); > + if (config & PXA3XX_PINCONF_DRIVE_STRENGTH) > + i += sprintf(buf + i, "DRIVE STRENGTH (%ld), ", > + config >> PXA3XX_PINCONF_DS_SHIFT); > + if (config & PXA3XX_PINCONF_LOWPOWER_PULL_UP) > + i += sprintf(buf + i, "LP PULL UP, "); > + if (config & PXA3XX_PINCONF_LOWPOWER_PULL_DOWN) > + i += sprintf(buf + i, "LP PULL DOWN, "); > + if (config & PXA3XX_PINCONF_LOWPOWER_DRIVE_HIGH) > + i += sprintf(buf + i, "LP DRIVE HIGH, "); > + if (config & PXA3XX_PINCONF_LOWPOWER_DRIVE_LOW) > + i += sprintf(buf + i, "LP DRIVE LOW, "); > + if (config & PXA3XX_PINCONF_LOWPOWER_FLOAT) > + i += sprintf(buf + i, "LP FLOAT, "); > + if (config & PXA3XX_PINCONF_LOWPOWER_ZERO) > + i += sprintf(buf + i, "LP ZERO, "); > + seq_printf(s, "%s\n", buf); > + > + mfpr = info->mfp[offset].mfpr; > + seq_printf(s, "reg[0x%x]:0x%x\n", info->phy_base + mfpr, > + readl_relaxed(info->virt_base + mfpr)); > +} > + > +static void pxa3xx_pinconf_group_dbg_show(struct pinctrl_dev *pctrldev, > + struct seq_file *s, unsigned group) > +{ > + struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); > + const unsigned *pins = info->grps[group].pins; > + int ret; > + unsigned long config; > + > + ret = pxa3xx_pinconf_group_get(pctrldev, group, &config); > + if (ret < 0) { > + seq_printf(s, "group config is not consistent\n"); > + return; > + } > + pxa3xx_pinconf_dbg_show(pctrldev, s, pins[0]); > +} > + > +static struct pinconf_ops pxa3xx_pinconf_ops = { > + .pin_config_get = pxa3xx_pinconf_get, > + .pin_config_set = pxa3xx_pinconf_set, > + .pin_config_group_get = pxa3xx_pinconf_group_get, > + .pin_config_group_set = pxa3xx_pinconf_group_set, > + .pin_config_dbg_show = pxa3xx_pinconf_dbg_show, > + .pin_config_group_dbg_show = pxa3xx_pinconf_group_dbg_show, > +}; > + > int pxa3xx_pinctrl_register(struct platform_device *pdev, > struct pxa3xx_pinmux_info *info) > { > @@ -182,6 +370,7 @@ int pxa3xx_pinctrl_register(struct platform_device *pdev, > desc->npins = info->num_pads; > desc->pctlops = &pxa3xx_pctrl_ops; > desc->pmxops = &pxa3xx_pmx_ops; > + desc->confops = &pxa3xx_pinconf_ops; > info->dev = &pdev->dev; > pxa3xx_pinctrl_gpio_range.npins = info->num_gpio; > > diff --git a/drivers/pinctrl/pinctrl-pxa3xx.h b/drivers/pinctrl/pinctrl-pxa3xx.h > index 8135744..fdcf805 100644 > --- a/drivers/pinctrl/pinctrl-pxa3xx.h > +++ b/drivers/pinctrl/pinctrl-pxa3xx.h > @@ -12,6 +12,7 @@ > */ > > #ifndef __PINCTRL_PXA3XX_H > +#define __PINCTRL_PXA3XX_H > > #include > #include > @@ -23,6 +24,22 @@ > #define PXA3xx_MAX_MUX 8 > #define MFPR_FUNC_MASK 0x7 > > +#define PXA3XX_PINCONF_PULL_UP (1 << 0) > +#define PXA3XX_PINCONF_PULL_DOWN (1 << 1) > +#define PXA3XX_PINCONF_DRIVE_STRENGTH (1 << 2) > +#define PXA3XX_PINCONF_LOWPOWER_PULL_UP (1 << 3) > +#define PXA3XX_PINCONF_LOWPOWER_PULL_DOWN (1 << 4) > +#define PXA3XX_PINCONF_LOWPOWER_DRIVE_HIGH (1 << 5) > +#define PXA3XX_PINCONF_LOWPOWER_DRIVE_LOW (1 << 6) > +#define PXA3XX_PINCONF_LOWPOWER_FLOAT (1 << 7) > +#define PXA3XX_PINCONF_LOWPOWER_ZERO (1 << 8) /* lowpower bits: 0 */ > +#define PXA3XX_PINCONF_MASK 0xffff > +#define PXA3XX_PINCONF_DS_SHIFT 16 > + > +#define PXA3XX_MFPR_PULL_SEL (1 << 15) > +#define PXA3XX_MFPR_PULL_UP (1 << 14) > +#define PXA3XX_MFPR_PULL_DOWN (1 << 13) > + > enum pxa_cpu_type { > PINCTRL_INVALID = 0, > PINCTRL_PXA300, >