Thread (23 messages) 23 messages, 5 authors, 2013-08-09
STALE4710d
Revisions (7)
  1. v1 [diff vs current]
  2. v1 [diff vs current]
  3. v1 current
  4. v1 [diff vs current]
  5. v1 [diff vs current]
  6. v2 [diff vs current]
  7. v3 [diff vs current]

[PATCH 3/7] pinctrl: imx1 core driver

From: Linus Walleij <hidden>
Date: 2013-08-07 19:25:35

On Fri, Aug 2, 2013 at 12:38 PM, Markus Pargmann [off-list ref] wrote:
Signed-off-by: Markus Pargmann <redacted>
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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help