Re: [PATCH 1/6] ARM: sunxi: Add pinctrl driver for Allwinner SoCs
From: Linus Walleij <hidden>
Date: 2012-12-11 00:28:20
Also in:
linux-arm-kernel
Possibly related (same subject, not in this thread)
- 2013-01-17 · Re: [PATCH 1/6] ARM: sunxi: Add pinctrl driver for Allwinner SoCs · Linus Walleij <hidden>
- 2013-01-07 · Re: [PATCH 1/6] ARM: sunxi: Add pinctrl driver for Allwinner SoCs · Maxime Ripard <hidden>
- 2013-01-06 · Re: [PATCH 1/6] ARM: sunxi: Add pinctrl driver for Allwinner SoCs · Linus Walleij <hidden>
- 2012-12-19 · [PATCH 1/6] ARM: sunxi: Add pinctrl driver for Allwinner SoCs · Maxime Ripard <hidden>
On Mon, Dec 10, 2012 at 11:08 PM, Maxime Ripard [off-list ref] wrote:
This IP has 8 banks of 32 bits, with a number of pins actually useful for each of these banks varying from one to another, and depending on the SoC used on the board. This driver only implements the pinctrl part, the gpio part will come eventually.
It's looking pretty nice already :-) Of course I have some comments... OK will it be a combined driver so the same file implement both pinctrl and gpio? (...)
+- allwinner,pin-ids: An integer array. Each integer in the array + specify a pin with given mux function, with bank, pin and mux packed + as below. + + [15..12] : bank number + [11..4] : pin number + [3..0] : mux selection
Why are you using this scheme instead of just open-coding the three things? Well maybe I'm not getting it... Device Trees are usually for reading, not for bitstuffing, that's why I ask. You should pass all this DT stuff to the devicetree-discuss list because I'm not any good at this (paging Stephen Warren.)
+- allwinner,pull: Integer. + 0: No resistor + 1: Pull-up resistor + 2: Pull-down resistor
This seems legit.
+config PINCTRL_SUNXI + bool + select PINMUX + select PINCONF
If your SoC is only simple pinconfig like pull-up/pull-down, why are you not using PINCONF_GENERIC and <linux/pinctrl/pinconf-generic.h>? (...)
+ ret = of_property_read_u32(node, "allwinner,drive", &val); + if (!ret) + config |= val << DLEVEL_SHIFT | DLEVEL_PRESENT; + + ret = of_property_read_u32(node, "allwinner,pull", &val); + if (!ret) + config |= val << PULL_SHIFT | PULL_PRESENT;
So looks nice... but can you use generic pinconfig?
+static void sunxi_pmx_set_config(struct pinctrl_dev *pctldev,
+ unsigned pin,
+ u8 config)
+{
+ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ u32 val = readl(pctl->membase + CFG_REG(pin));
+ u32 mask = ((1 << CFG_PINS_BITS) - 1) << CFG_OFFSET(pin);
+ writel((val & ~mask) | config << CFG_OFFSET(pin),
+ pctl->membase + CFG_REG(pin));
+}There is something a bit confusing with the naming here, this is configuring the multiplexing (mux) but named config and CFG, which makes for great misunderstandings... can it be changed to eg just pmx_set() and MUX_OFFSET and MUX_REG() for example?
+static struct of_device_id sunxi_pinctrl_match[] __devinitconst = {
+ {}
+};
+MODULE_DEVICE_TABLE(of, sunxi_pinctrl_match);This table will not match very much :-/ You should put one example in atleast? Something must have been used to test this...
+static int __devinit sunxi_pinctrl_parse_group(struct platform_device *pdev,
+ struct device_node *node,
+ int idx,
+ const char **out_name)
+{
+ struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev);
+ struct sunxi_pinctrl_group *group = pctl->groups + idx;
+ struct property *prop;
+ char *group_name;
+ int i;
+ u32 val, proplen;
+
+ group_name = devm_kzalloc(&pdev->dev, strlen(node->name) + 4,
+ GFP_KERNEL);
+ if (!group_name)
+ return -ENOMEM;
+ if (of_property_read_u32(node, "reg", &val))
+ snprintf(group_name, strlen(node->name), "%s", node->name);
+ else
+ snprintf(group_name, strlen(node->name) + 4,
+ "%s.%d", node->name, val);
+ group->name = group_name;
+
+ prop = of_find_property(node, "allwinner,pin-ids", &proplen);
+ if (!prop)
+ return -EINVAL;
+ group->npins = proplen / sizeof(u32);So storing one u32 for every pin I guess.
+ group->pins = devm_kzalloc(&pdev->dev,
+ group->npins * sizeof(*group->pins),
+ GFP_KERNEL);
+ if (!group->pins)
+ return -ENOMEM;
+
+ group->muxcfg = devm_kzalloc(&pdev->dev,
+ group->npins * sizeof(*group->muxcfg),
+ GFP_KERNEL);
+ if (!group->muxcfg)
+ return -ENOMEM;
+
+ of_property_read_u32_array(node, "allwinner,pin-ids", group->pins,
+ group->npins);
+ for (i = 0; i < group->npins; i++) {
+ group->muxcfg[i] = MUXID_TO_MUXCFG(group->pins[i]);
+ group->pins[i] = MUXID_TO_PIN(group->pins[i]);
+ }This loop is rather awkward I mean, instead of bitstuffing muxcfg and pin ID into a single u32 why not just have them as separate attributes. Then there was somthing about bank ID which I guess is just discarded here? (...)
+static int __devinit sunxi_pinctrl_probe(struct platform_device *pdev)
+{
+ struct sunxi_pinctrl *pctl;
+ int i, ret;
+
+ pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
+ if (!pctl)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, pctl);
+
+ ret = sunxi_pinctrl_probe_dt(pdev, pctl);
+ if (ret) {
+ dev_err(&pdev->dev, "dt probe failed: %d\n", ret);
+ return ret;
+ }
+
+ pctl->data = (struct sunxi_pinctrl_data *)of_match_device(sunxi_pinctrl_match, &pdev->dev)->data;I can't parse this, what is going on here? Can you break this statement apart somehow? (...)
quoted hunk
+++ b/drivers/pinctrl/pinctrl-sunxi.h
+#define PINS_PER_BANK 32 + +#define CFG_REG(pin) (round_down( \ + (pin / PINS_PER_BANK) * 0x24 + \ + ((pin % PINS_PER_BANK) / 8) * 0x04, 4)) +#define CFG_OFFSET(pin) ((pin % 8) * 4) + +#define DLEVEL_REG(pin) (round_down( \ + (pin / PINS_PER_BANK) * 0x24 + \ + ((pin % PINS_PER_BANK) / 16) * 0x04 + \ + 0x14, 4)) +#define DLEVEL_OFFSET(pin) ((pin % 16) * 2) + +#define PULL_REG(pin) (round_down( \ + (pin / PINS_PER_BANK) * 0x24 + \ + ((pin % PINS_PER_BANK) / 16) * 0x04 + \ + 0x1c, 4)) +#define PULL_OFFSET(pin) ((pin % 16) * 2)
These are impossible to understand. Please convert these to documented static inline functions instead so the code can be maintained in the future.
+#define CFG_PINS_PER_REG 8 +#define CFG_PINS_BITS 4 +#define DLEVEL_PINS_PER_REG 16 +#define DLEVEL_PINS_BITS 2 +#define PULL_PINS_PER_REG 16 +#define PULL_PINS_BITS 2 + +#define MUXID_TO_PIN(id) ((((id) >> 12 & 0xf) * 32) + ((id) >> 4 & 0xff)) +#define MUXID_TO_MUXCFG(id) ((id) & 0xf)
Same here.
+#define SUNXI_PINCTRL_PIN_PA0 PINCTRL_PIN(0 + 0, "PA0") +#define SUNXI_PINCTRL_PIN_PA1 PINCTRL_PIN(0 + 1, "PA1") +#define SUNXI_PINCTRL_PIN_PA2 PINCTRL_PIN(0 + 2, "PA2") +#define SUNXI_PINCTRL_PIN_PA3 PINCTRL_PIN(0 + 3, "PA3") +#define SUNXI_PINCTRL_PIN_PA4 PINCTRL_PIN(0 + 4, "PA4") +#define SUNXI_PINCTRL_PIN_PA5 PINCTRL_PIN(0 + 5, "PA5") +#define SUNXI_PINCTRL_PIN_PA6 PINCTRL_PIN(0 + 6, "PA6") +#define SUNXI_PINCTRL_PIN_PA7 PINCTRL_PIN(0 + 7, "PA7") +#define SUNXI_PINCTRL_PIN_PA8 PINCTRL_PIN(0 + 8, "PA8") +#define SUNXI_PINCTRL_PIN_PA9 PINCTRL_PIN(0 + 9, "PA9") +#define SUNXI_PINCTRL_PIN_PA10 PINCTRL_PIN(0 + 10, "PA10") +#define SUNXI_PINCTRL_PIN_PA11 PINCTRL_PIN(0 + 11, "PA11") +#define SUNXI_PINCTRL_PIN_PA12 PINCTRL_PIN(0 + 12, "PA12") +#define SUNXI_PINCTRL_PIN_PA13 PINCTRL_PIN(0 + 13, "PA13") +#define SUNXI_PINCTRL_PIN_PA14 PINCTRL_PIN(0 + 14, "PA14") +#define SUNXI_PINCTRL_PIN_PA15 PINCTRL_PIN(0 + 15, "PA15") +#define SUNXI_PINCTRL_PIN_PA16 PINCTRL_PIN(0 + 16, "PA16") +#define SUNXI_PINCTRL_PIN_PA17 PINCTRL_PIN(0 + 17, "PA17") +#define SUNXI_PINCTRL_PIN_PA18 PINCTRL_PIN(0 + 18, "PA18") +#define SUNXI_PINCTRL_PIN_PA19 PINCTRL_PIN(0 + 19, "PA19") +#define SUNXI_PINCTRL_PIN_PA20 PINCTRL_PIN(0 + 20, "PA20") +#define SUNXI_PINCTRL_PIN_PA21 PINCTRL_PIN(0 + 21, "PA21") +#define SUNXI_PINCTRL_PIN_PA22 PINCTRL_PIN(0 + 22, "PA22") +#define SUNXI_PINCTRL_PIN_PA23 PINCTRL_PIN(0 + 23, "PA23") +#define SUNXI_PINCTRL_PIN_PA24 PINCTRL_PIN(0 + 24, "PA24") +#define SUNXI_PINCTRL_PIN_PA25 PINCTRL_PIN(0 + 25, "PA25") +#define SUNXI_PINCTRL_PIN_PA26 PINCTRL_PIN(0 + 26, "PA26") +#define SUNXI_PINCTRL_PIN_PA27 PINCTRL_PIN(0 + 27, "PA27") +#define SUNXI_PINCTRL_PIN_PA28 PINCTRL_PIN(0 + 28, "PA28") +#define SUNXI_PINCTRL_PIN_PA29 PINCTRL_PIN(0 + 29, "PA29") +#define SUNXI_PINCTRL_PIN_PA30 PINCTRL_PIN(0 + 30, "PA30") +#define SUNXI_PINCTRL_PIN_PA31 PINCTRL_PIN(0 + 31, "PA31")
0+0, 0+1, 0+2 .... why not just use the scalar? 0, 1, 2, ... 31? I understand that the zero denotes bank 0 or bank A or somtheing (PA, PB etc) so if you need to keep that, use something like #define PA_BASE 0 Then #define SUNXI_PINCTRL_PIN_PA28 PINCTRL_PIN(PA_BASE + 28, "PA28") which makes more sense.
+#define SUNXI_PINCTRL_PIN_PB0 PINCTRL_PIN(32 + 0, "PB0") +#define SUNXI_PINCTRL_PIN_PB1 PINCTRL_PIN(32 + 1, "PB1")
(...) Dito for C, D, E, F, G... Yours, Linus Walleij