Skip to content

Commit

Permalink
pinctrl: gemini: Support drive strength setting
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Linus Walleij committed Dec 7, 2017
1 parent 3881c4a commit ad63da8
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ and generic pin config nodes.

Supported configurations:
- skew-delay is supported on the Ethernet pins
- drive-strength with 4, 8, 12 or 16 mA as argument is supported for
entire groups on the groups "idegrp", "gmii_gmac0_grp", "gmii_gmac1_grp"
and "pcigrp".

Example:

Expand Down
81 changes: 81 additions & 0 deletions drivers/pinctrl/pinctrl-gemini.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,24 @@ 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;
const unsigned int *pins;
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
Expand Down Expand Up @@ -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",
Expand All @@ -753,20 +759,23 @@ 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",
.pins = gmii_gmac1_3512_pins,
.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",
.pins = pci_3512_pins,
.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",
Expand Down Expand Up @@ -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",
Expand All @@ -1686,20 +1696,23 @@ 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",
.pins = gmii_gmac1_3516_pins,
.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",
.pins = pci_3516_pins,
.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",
Expand Down Expand Up @@ -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,
};

Expand Down

0 comments on commit ad63da8

Please sign in to comment.