summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2017-12-02 12:23:09 +0100
committerLinus Walleij <linus.walleij@linaro.org>2017-12-07 09:59:26 +0100
commitad63da85f45fa55c270e5681e9b985605ec51f8d (patch)
tree004fb4c10fa490e08713dde7118cff5ed45e24b8 /drivers
parent3881c4a56e5941c21c08d9476c68d2cc65005f68 (diff)
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pinctrl/pinctrl-gemini.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/drivers/pinctrl/pinctrl-gemini.c b/drivers/pinctrl/pinctrl-gemini.c
index 10f8f3a35fe1..5e789753f945 100644
--- a/drivers/pinctrl/pinctrl-gemini.c
+++ b/drivers/pinctrl/pinctrl-gemini.c
@@ -67,6 +67,9 @@ struct gemini_pmx {
* elements in .pins so we can iterate over that array
* @mask: bits to clear to enable this when doing pin muxing
* @value: bits to set to enable this when doing pin muxing
+ * @driving_mask: bitmask for the IO Pad driving register for this
+ * group, if it supports altering the driving strength of
+ * its lines.
*/
struct gemini_pin_group {
const char *name;
@@ -74,12 +77,14 @@ struct gemini_pin_group {
const unsigned int num_pins;
u32 mask;
u32 value;
+ u32 driving_mask;
};
/* Some straight-forward control registers */
#define GLOBAL_WORD_ID 0x00
#define GLOBAL_STATUS 0x04
#define GLOBAL_STATUS_FLPIN BIT(20)
+#define GLOBAL_IODRIVE 0x10
#define GLOBAL_GMAC_CTRL_SKEW 0x1c
#define GLOBAL_GMAC0_DATA_SKEW 0x20
#define GLOBAL_GMAC1_DATA_SKEW 0x24
@@ -738,6 +743,7 @@ static const struct gemini_pin_group gemini_3512_pin_groups[] = {
/* Conflict with all flash usage */
.value = IDE_PADS_ENABLE | NAND_PADS_DISABLE |
PFLASH_PADS_DISABLE | SFLASH_PADS_DISABLE,
+ .driving_mask = GENMASK(21, 20),
},
{
.name = "satagrp",
@@ -753,6 +759,7 @@ static const struct gemini_pin_group gemini_3512_pin_groups[] = {
.name = "gmii_gmac0_grp",
.pins = gmii_gmac0_3512_pins,
.num_pins = ARRAY_SIZE(gmii_gmac0_3512_pins),
+ .driving_mask = GENMASK(17, 16),
},
{
.name = "gmii_gmac1_grp",
@@ -760,6 +767,7 @@ static const struct gemini_pin_group gemini_3512_pin_groups[] = {
.num_pins = ARRAY_SIZE(gmii_gmac1_3512_pins),
/* Bring out RGMII on the GMAC1 pins */
.value = GEMINI_GMAC_IOSEL_GMAC0_GMAC1_RGMII,
+ .driving_mask = GENMASK(19, 18),
},
{
.name = "pcigrp",
@@ -767,6 +775,7 @@ static const struct gemini_pin_group gemini_3512_pin_groups[] = {
.num_pins = ARRAY_SIZE(pci_3512_pins),
/* Conflict only with GPIO2 */
.value = PCI_PADS_ENABLE | PCI_CLK_PAD_ENABLE,
+ .driving_mask = GENMASK(23, 22),
},
{
.name = "lpcgrp",
@@ -1671,6 +1680,7 @@ static const struct gemini_pin_group gemini_3516_pin_groups[] = {
/* Conflict with all flash usage */
.value = IDE_PADS_ENABLE | NAND_PADS_DISABLE |
PFLASH_PADS_DISABLE | SFLASH_PADS_DISABLE,
+ .driving_mask = GENMASK(21, 20),
},
{
.name = "satagrp",
@@ -1686,6 +1696,7 @@ static const struct gemini_pin_group gemini_3516_pin_groups[] = {
.name = "gmii_gmac0_grp",
.pins = gmii_gmac0_3516_pins,
.num_pins = ARRAY_SIZE(gmii_gmac0_3516_pins),
+ .driving_mask = GENMASK(17, 16),
},
{
.name = "gmii_gmac1_grp",
@@ -1693,6 +1704,7 @@ static const struct gemini_pin_group gemini_3516_pin_groups[] = {
.num_pins = ARRAY_SIZE(gmii_gmac1_3516_pins),
/* Bring out RGMII on the GMAC1 pins */
.value = GEMINI_GMAC_IOSEL_GMAC0_GMAC1_RGMII,
+ .driving_mask = GENMASK(19, 18),
},
{
.name = "pcigrp",
@@ -1700,6 +1712,7 @@ static const struct gemini_pin_group gemini_3516_pin_groups[] = {
.num_pins = ARRAY_SIZE(pci_3516_pins),
/* Conflict only with GPIO2 */
.value = PCI_PADS_ENABLE | PCI_CLK_PAD_ENABLE,
+ .driving_mask = GENMASK(23, 22),
},
{
.name = "lpcgrp",
@@ -2394,9 +2407,77 @@ static int gemini_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
return ret;
}
+static int gemini_pinconf_group_set(struct pinctrl_dev *pctldev,
+ unsigned selector,
+ unsigned long *configs,
+ unsigned num_configs)
+{
+ struct gemini_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ const struct gemini_pin_group *grp = NULL;
+ enum pin_config_param param;
+ u32 arg;
+ u32 val;
+ int i;
+
+ if (pmx->is_3512)
+ grp = &gemini_3512_pin_groups[selector];
+ if (pmx->is_3516)
+ grp = &gemini_3516_pin_groups[selector];
+
+ /* First figure out if this group supports configs */
+ if (!grp->driving_mask) {
+ dev_err(pmx->dev, "pin config group \"%s\" does "
+ "not support drive strength setting\n",
+ grp->name);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_configs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ switch (arg) {
+ case 4:
+ val = 0;
+ break;
+ case 8:
+ val = 1;
+ break;
+ case 12:
+ val = 2;
+ break;
+ case 16:
+ val = 3;
+ break;
+ default:
+ dev_err(pmx->dev,
+ "invalid drive strength %d mA\n",
+ arg);
+ return -ENOTSUPP;
+ }
+ val <<= (ffs(grp->driving_mask) - 1);
+ regmap_update_bits(pmx->map, GLOBAL_IODRIVE,
+ grp->driving_mask,
+ val);
+ dev_info(pmx->dev,
+ "set group %s to %d mA drive strength mask %08x val %08x\n",
+ grp->name, arg, grp->driving_mask, val);
+ break;
+ default:
+ dev_err(pmx->dev, "invalid config param %04x\n", param);
+ return -ENOTSUPP;
+ }
+ }
+
+ return 0;
+}
+
static const struct pinconf_ops gemini_pinconf_ops = {
.pin_config_get = gemini_pinconf_get,
.pin_config_set = gemini_pinconf_set,
+ .pin_config_group_set = gemini_pinconf_group_set,
.is_generic = true,
};