[PATCH 3/7] pinctrl: imx1 core driver

Linus Walleij linus.walleij at linaro.org
Wed Aug 7 15:25:35 EDT 2013


On Fri, Aug 2, 2013 at 12:38 PM, Markus Pargmann <mpa at pengutronix.de> wrote:

> Signed-off-by: Markus Pargmann <mpa at pengutronix.de>

I think you need a bit of patch description here. Zero lines of
commit message is not acceptable for an entire new driver.
Elaborate a bit on the imx27 hardware and so on.

> +/*
> + * Calculates the register offset from a pin_id
> + */
> +static void __iomem *imx1_mem(struct imx1_pinctrl *ipctl, unsigned int pin_id)
> +{
> +       unsigned int port = pin_id / 32;
> +       return ipctl->base + port * 0x100;

Use this:
#define IMX1_PORT_STRIDE 0x100

> +/*
> + * Write to a register with 2 bits per pin. The function will automatically
> + * use the next register if the pin is managed in the second register.
> + */
> +static void imx1_write_2bit(struct imx1_pinctrl *ipctl, unsigned int pin_id,
> +               u32 value, u32 reg_offset)
> +{
> +       void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset;
> +       int shift = (pin_id % 16) * 2;
> +       int mask = ~(0x3 << shift);

I think I understand this, but insert a comment on what this is
anyway.

> +       u32 old_value;
> +
> +       dev_dbg(ipctl->dev, "write: register 0x%p shift %d value 0x%x\n",
> +                       reg, shift, value);
> +
> +       if (pin_id % 32 >= 16)
> +               reg += 0x04;

Comment on what is happening here.

> +
> +       value = (value & 0x11) << shift;

What is this? 0x11? Shall this be #defined or
what does it mean? The "value" argument really needs
some documentation I think.

You're modifying the argument "value" which is confusing.
Try to avoid this.

> +       old_value = readl(reg) & mask;
> +       writel(value | old_value, reg);

This is a bit over-complicating things. Write out
the sequence and let the compiler do the optimization.

val = readl(reg);
val &= mask;
val |= value;
writel(val, reg);


> +static void imx1_write_bit(struct imx1_pinctrl *ipctl, unsigned int pin_id,
> +               u32 value, u32 reg_offset)
> +{
> +       void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset;
> +       int shift = pin_id % 32;
> +       int mask = ~(0x1 << shift);
> +       u32 old_value;
> +
> +       dev_dbg(ipctl->dev, "write: register 0x%p shift %d value 0x%x\n",
> +                       reg, shift, value);
> +
> +       value = (value & 0x1) << shift;
> +       old_value = readl(reg) & mask;
> +       writel(value | old_value, reg);

Same comments here.

> +static int imx1_read_bit(struct imx1_pinctrl *ipctl, unsigned int pin_id,
> +               u32 reg_offset)
> +{
> +       void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset;
> +       int shift = pin_id % 32;
> +
> +       return (readl(reg) >> shift) & 0x1;

Hard to read. Can't you just do this?

#include <linux/bitops.h>

u32 offset = pin_id % 32;

return !!(readl(reg) & BIT(offset));

> +static void imx1_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
> +                  unsigned offset)
> +{
> +       seq_printf(s, "%s", dev_name(pctldev->dev));
> +}

Don't you want to print some other more interesting things about
each pin?

This template is really just an example. The debugfs file is
intended to be helpful.

> +static int imx1_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
> +                          unsigned group)
> +{
> +       struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
> +       const struct imx_pinctrl_soc_info *info = ipctl->info;
> +       const unsigned *pins, *mux;
> +       unsigned int npins;
> +       int i;
> +
> +       /*
> +        * Configure the mux mode for each pin in the group for a specific
> +        * function.
> +        */
> +       pins = info->groups[group].pins;
> +       npins = info->groups[group].npins;
> +       mux = info->groups[group].mux_mode;
> +
> +       WARN_ON(!pins || !npins || !mux);
> +
> +       dev_dbg(ipctl->dev, "enable function %s group %s\n",
> +               info->functions[selector].name, info->groups[group].name);
> +
> +       for (i = 0; i < npins; i++) {
> +               unsigned int pin_id = pins[i];
> +               unsigned int afunction = 0x001 & mux[i];
> +               unsigned int gpio_in_use = (0x002 & mux[i]) >> 1;
> +               unsigned int direction = (0x004 & mux[i]) >> 2;
> +               unsigned int gpio_oconf = (0x030 & mux[i]) >> 4;
> +               unsigned int gpio_iconfa = (0x300 & mux[i]) >> 8;
> +               unsigned int gpio_iconfb = (0xc00 & mux[i]) >> 10;

If you use <linux/bitops.h> this can be made more understandable,
BIT(0), BIT(1), BIT(2) etc.

The shift offsets should be #defined.

> +static void imx1_pinconf_dbg_show(struct pinctrl_dev *pctldev,
> +                                  struct seq_file *s, unsigned pin_id)
> +{
> +       struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
> +       const struct imx_pinctrl_soc_info *info = ipctl->info;
> +       const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
> +       unsigned long config;
> +
> +       if (!pin_reg || !pin_reg->conf_reg) {
> +               seq_puts(s, "N/A");
> +               return;
> +       }
> +
> +       config = readl(ipctl->base + pin_reg->conf_reg);
> +       seq_printf(s, "0x%lx", config);
> +}

That's pretty helpful, nice!

> +static int imx1_pinctrl_parse_gpio(struct platform_device *pdev,
> +               struct imx1_pinctrl *pctl, struct device_node *np, int i,
> +               u32 base)
> +{
> +       int ret;
> +       u32 memoffset;
> +
> +       ret = of_property_read_u32(np, "reg", &memoffset);
> +       if (ret)
> +               return ret;
> +
> +       memoffset -= base;
> +       pctl->gpio_pdata[i].base = pctl->base + memoffset;
> +
> +       pctl->gpio_dev[i] = of_device_alloc(np, NULL, &pdev->dev);
> +       pctl->gpio_dev[i]->dev.platform_data = &pctl->gpio_pdata[i];
> +       pctl->gpio_dev[i]->dev.bus = &platform_bus_type;
> +
> +       ret = of_device_add(pctl->gpio_dev[i]);
> +       if (ret) {
> +               dev_err(&pdev->dev,
> +                               "Failed to add child gpio device\n");
> +               return ret;
> +       }
> +       return 0;
> +}

As mentioned for the other patch I think this is the wrong approach.
Try to make the GPIO driver wholly independent.

Yours,
Linus Walleij



More information about the linux-arm-kernel mailing list