Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pinctrl: gemini: Support drive strength setting

The Gemini pin controller can set drive strength for a few
select groups of pins (not individually). Implement this
for GMAC0 and 1 (ethernet ports), IDE and PCI.

Cc: devicetree@vger.kernel.org
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

+84
+3
Documentation/devicetree/bindings/pinctrl/cortina,gemini-pinctrl.txt
··· 17 17 18 18 Supported configurations: 19 19 - skew-delay is supported on the Ethernet pins 20 + - drive-strength with 4, 8, 12 or 16 mA as argument is supported for 21 + entire groups on the groups "idegrp", "gmii_gmac0_grp", "gmii_gmac1_grp" 22 + and "pcigrp". 20 23 21 24 Example: 22 25
+81
drivers/pinctrl/pinctrl-gemini.c
··· 67 67 * elements in .pins so we can iterate over that array 68 68 * @mask: bits to clear to enable this when doing pin muxing 69 69 * @value: bits to set to enable this when doing pin muxing 70 + * @driving_mask: bitmask for the IO Pad driving register for this 71 + * group, if it supports altering the driving strength of 72 + * its lines. 70 73 */ 71 74 struct gemini_pin_group { 72 75 const char *name; ··· 77 74 const unsigned int num_pins; 78 75 u32 mask; 79 76 u32 value; 77 + u32 driving_mask; 80 78 }; 81 79 82 80 /* Some straight-forward control registers */ 83 81 #define GLOBAL_WORD_ID 0x00 84 82 #define GLOBAL_STATUS 0x04 85 83 #define GLOBAL_STATUS_FLPIN BIT(20) 84 + #define GLOBAL_IODRIVE 0x10 86 85 #define GLOBAL_GMAC_CTRL_SKEW 0x1c 87 86 #define GLOBAL_GMAC0_DATA_SKEW 0x20 88 87 #define GLOBAL_GMAC1_DATA_SKEW 0x24 ··· 743 738 /* Conflict with all flash usage */ 744 739 .value = IDE_PADS_ENABLE | NAND_PADS_DISABLE | 745 740 PFLASH_PADS_DISABLE | SFLASH_PADS_DISABLE, 741 + .driving_mask = GENMASK(21, 20), 746 742 }, 747 743 { 748 744 .name = "satagrp", ··· 759 753 .name = "gmii_gmac0_grp", 760 754 .pins = gmii_gmac0_3512_pins, 761 755 .num_pins = ARRAY_SIZE(gmii_gmac0_3512_pins), 756 + .driving_mask = GENMASK(17, 16), 762 757 }, 763 758 { 764 759 .name = "gmii_gmac1_grp", ··· 767 760 .num_pins = ARRAY_SIZE(gmii_gmac1_3512_pins), 768 761 /* Bring out RGMII on the GMAC1 pins */ 769 762 .value = GEMINI_GMAC_IOSEL_GMAC0_GMAC1_RGMII, 763 + .driving_mask = GENMASK(19, 18), 770 764 }, 771 765 { 772 766 .name = "pcigrp", ··· 775 767 .num_pins = ARRAY_SIZE(pci_3512_pins), 776 768 /* Conflict only with GPIO2 */ 777 769 .value = PCI_PADS_ENABLE | PCI_CLK_PAD_ENABLE, 770 + .driving_mask = GENMASK(23, 22), 778 771 }, 779 772 { 780 773 .name = "lpcgrp", ··· 1680 1671 /* Conflict with all flash usage */ 1681 1672 .value = IDE_PADS_ENABLE | NAND_PADS_DISABLE | 1682 1673 PFLASH_PADS_DISABLE | SFLASH_PADS_DISABLE, 1674 + .driving_mask = GENMASK(21, 20), 1683 1675 }, 1684 1676 { 1685 1677 .name = "satagrp", ··· 1696 1686 .name = "gmii_gmac0_grp", 1697 1687 .pins = gmii_gmac0_3516_pins, 1698 1688 .num_pins = ARRAY_SIZE(gmii_gmac0_3516_pins), 1689 + .driving_mask = GENMASK(17, 16), 1699 1690 }, 1700 1691 { 1701 1692 .name = "gmii_gmac1_grp", ··· 1704 1693 .num_pins = ARRAY_SIZE(gmii_gmac1_3516_pins), 1705 1694 /* Bring out RGMII on the GMAC1 pins */ 1706 1695 .value = GEMINI_GMAC_IOSEL_GMAC0_GMAC1_RGMII, 1696 + .driving_mask = GENMASK(19, 18), 1707 1697 }, 1708 1698 { 1709 1699 .name = "pcigrp", ··· 1712 1700 .num_pins = ARRAY_SIZE(pci_3516_pins), 1713 1701 /* Conflict only with GPIO2 */ 1714 1702 .value = PCI_PADS_ENABLE | PCI_CLK_PAD_ENABLE, 1703 + .driving_mask = GENMASK(23, 22), 1715 1704 }, 1716 1705 { 1717 1706 .name = "lpcgrp", ··· 2407 2394 return ret; 2408 2395 } 2409 2396 2397 + static int gemini_pinconf_group_set(struct pinctrl_dev *pctldev, 2398 + unsigned selector, 2399 + unsigned long *configs, 2400 + unsigned num_configs) 2401 + { 2402 + struct gemini_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); 2403 + const struct gemini_pin_group *grp = NULL; 2404 + enum pin_config_param param; 2405 + u32 arg; 2406 + u32 val; 2407 + int i; 2408 + 2409 + if (pmx->is_3512) 2410 + grp = &gemini_3512_pin_groups[selector]; 2411 + if (pmx->is_3516) 2412 + grp = &gemini_3516_pin_groups[selector]; 2413 + 2414 + /* First figure out if this group supports configs */ 2415 + if (!grp->driving_mask) { 2416 + dev_err(pmx->dev, "pin config group \"%s\" does " 2417 + "not support drive strength setting\n", 2418 + grp->name); 2419 + return -EINVAL; 2420 + } 2421 + 2422 + for (i = 0; i < num_configs; i++) { 2423 + param = pinconf_to_config_param(configs[i]); 2424 + arg = pinconf_to_config_argument(configs[i]); 2425 + 2426 + switch (param) { 2427 + case PIN_CONFIG_DRIVE_STRENGTH: 2428 + switch (arg) { 2429 + case 4: 2430 + val = 0; 2431 + break; 2432 + case 8: 2433 + val = 1; 2434 + break; 2435 + case 12: 2436 + val = 2; 2437 + break; 2438 + case 16: 2439 + val = 3; 2440 + break; 2441 + default: 2442 + dev_err(pmx->dev, 2443 + "invalid drive strength %d mA\n", 2444 + arg); 2445 + return -ENOTSUPP; 2446 + } 2447 + val <<= (ffs(grp->driving_mask) - 1); 2448 + regmap_update_bits(pmx->map, GLOBAL_IODRIVE, 2449 + grp->driving_mask, 2450 + val); 2451 + dev_info(pmx->dev, 2452 + "set group %s to %d mA drive strength mask %08x val %08x\n", 2453 + grp->name, arg, grp->driving_mask, val); 2454 + break; 2455 + default: 2456 + dev_err(pmx->dev, "invalid config param %04x\n", param); 2457 + return -ENOTSUPP; 2458 + } 2459 + } 2460 + 2461 + return 0; 2462 + } 2463 + 2410 2464 static const struct pinconf_ops gemini_pinconf_ops = { 2411 2465 .pin_config_get = gemini_pinconf_get, 2412 2466 .pin_config_set = gemini_pinconf_set, 2467 + .pin_config_group_set = gemini_pinconf_group_set, 2413 2468 .is_generic = true, 2414 2469 }; 2415 2470