Hi everyone,
This series fixes up generic pinconf support for the sunxi pinctrl driver
library. The driver was doing some bits wrong, like a) storing the pinconf
config value in its struct, and not actually reading the hardware to get
the current config, and b) not using the right arguments for the bias
parameters.
Patch 1 fixes the pin bias parameter arguments.
Patch 2 makes the driver read out pinconf settings from the hardware, and
returns the correct value for unsupported features and disable features.
With this in place it also declares itself as generic pinconf compatible,
which enables us to read the config through the debugfs pinconf interface.
Patch 3 makes the sunxi_pconf_group_set callback use the helper function
introduced in patch 1.
Changes since v1:
- Rebased onto the updated sunxi pinctrl driver with support for the
generic pinconf bindings
- Use separate value for what is written to the register in the pinconf
set function, as Maxime requested.
Regards
ChenYu
Chen-Yu Tsai (3):
pinctrl: sunxi: Fix PIN_CONFIG_BIAS_PULL_{DOWN,UP} argument
pinctrl: sunxi: Add support for fetching pinconf settings from
hardware
pinctrl: sunxi: Make sunxi_pconf_group_set use sunxi_pconf_reg helper
drivers/pinctrl/sunxi/pinctrl-sunxi.c | 156 +++++++++++++++++++++++++---------
drivers/pinctrl/sunxi/pinctrl-sunxi.h | 1 -
2 files changed, 118 insertions(+), 39 deletions(-)
--
2.10.2
According to pinconf-generic.h, the argument for
PIN_CONFIG_BIAS_PULL_{DOWN,UP} is non-zero if the bias is enabled
with a pull up/down resistor, zero if it is directly connected
to VDD or ground.
Since Allwinner hardware uses a weak pull resistor internally,
the argument should be 1.
Signed-off-by: Chen-Yu Tsai <redacted>
---
drivers/pinctrl/sunxi/pinctrl-sunxi.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
From: Maxime Ripard <hidden> Date: 2016-11-11 08:34:43
On Fri, Nov 11, 2016 at 10:44:53AM +0800, Chen-Yu Tsai wrote:
According to pinconf-generic.h, the argument for
PIN_CONFIG_BIAS_PULL_{DOWN,UP} is non-zero if the bias is enabled
with a pull up/down resistor, zero if it is directly connected
to VDD or ground.
Since Allwinner hardware uses a weak pull resistor internally,
the argument should be 1.
Signed-off-by: Chen-Yu Tsai <redacted>
On Fri, Nov 11, 2016 at 3:44 AM, Chen-Yu Tsai [off-list ref] wrote:
According to pinconf-generic.h, the argument for
PIN_CONFIG_BIAS_PULL_{DOWN,UP} is non-zero if the bias is enabled
with a pull up/down resistor, zero if it is directly connected
to VDD or ground.
Since Allwinner hardware uses a weak pull resistor internally,
the argument should be 1.
Signed-off-by: Chen-Yu Tsai <redacted>
Patch applied with Maxime's ACK.
Yours,
Linus Walleij
The sunxi pinctrl driver only caches whatever pinconf setting was last
set on a given pingroup. This is not particularly helpful, nor is it
correct.
Fix this by actually reading the hardware registers and returning
the correct results or error codes. Also filter out unsupported
pinconf settings. Since this driver has a peculiar setup of 1 pin
per group, we can support both pin and pingroup pinconf setting
read back with the same code. The sunxi_pconf_reg helper and code
structure is inspired by pinctrl-msm.
With this done we can also claim to support generic pinconf, by
setting .is_generic = true in pinconf_ops.
Signed-off-by: Chen-Yu Tsai <redacted>
---
drivers/pinctrl/sunxi/pinctrl-sunxi.c | 84 +++++++++++++++++++++++++++++++++--
1 file changed, 81 insertions(+), 3 deletions(-)
@@ -438,15 +438,91 @@ static const struct pinctrl_ops sunxi_pctrl_ops = {.get_group_pins=sunxi_pctrl_get_group_pins,};+staticintsunxi_pconf_reg(unsignedpin,enumpin_config_paramparam,+u32*offset,u32*shift,u32*mask)+{+switch(param){+casePIN_CONFIG_DRIVE_STRENGTH:+*offset=sunxi_dlevel_reg(pin);+*shift=sunxi_dlevel_offset(pin);+*mask=DLEVEL_PINS_MASK;+break;++casePIN_CONFIG_BIAS_PULL_UP:+casePIN_CONFIG_BIAS_PULL_DOWN:+casePIN_CONFIG_BIAS_DISABLE:+*offset=sunxi_pull_reg(pin);+*shift=sunxi_pull_offset(pin);+*mask=PULL_PINS_MASK;+break;++default:+return-ENOTSUPP;+}++return0;+}++staticintsunxi_pconf_get(structpinctrl_dev*pctldev,unsignedpin,+unsignedlong*config)+{+structsunxi_pinctrl*pctl=pinctrl_dev_get_drvdata(pctldev);+enumpin_config_paramparam=pinconf_to_config_param(*config);+u32offset,shift,mask,val;+u16arg;+intret;++pin-=pctl->desc->pin_base;++ret=sunxi_pconf_reg(pin,param,&offset,&shift,&mask);+if(ret<0)+returnret;++val=(readl(pctl->membase+offset)>>shift)&mask;++switch(pinconf_to_config_param(*config)){+casePIN_CONFIG_DRIVE_STRENGTH:+arg=(val+1)*10;+break;++casePIN_CONFIG_BIAS_PULL_UP:+if(val!=SUN4I_PINCTRL_PULL_UP)+return-EINVAL;+arg=1;/* hardware is weak pull-up */+break;++casePIN_CONFIG_BIAS_PULL_DOWN:+if(val!=SUN4I_PINCTRL_PULL_DOWN)+return-EINVAL;+arg=1;/* hardware is weak pull-down */+break;++casePIN_CONFIG_BIAS_DISABLE:+if(val!=SUN4I_PINCTRL_NO_PULL)+return-EINVAL;+arg=0;+break;++default:+/* sunxi_pconf_reg should catch anything unsupported */+WARN_ON(1);+return-ENOTSUPP;+}++*config=pinconf_to_config_packed(param,arg);++return0;+}+staticintsunxi_pconf_group_get(structpinctrl_dev*pctldev,unsignedgroup,unsignedlong*config){structsunxi_pinctrl*pctl=pinctrl_dev_get_drvdata(pctldev);+structsunxi_pinctrl_group*g=&pctl->groups[group];-*config=pctl->groups[group].config;--return0;+/* We only support 1 pin per group. Chain it to the pin callback */+returnsunxi_pconf_get(pctldev,g->pin,config);}staticintsunxi_pconf_group_set(structpinctrl_dev*pctldev,
@@ -518,6 +594,8 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,}staticconststructpinconf_opssunxi_pconf_ops={+.is_generic=true,+.pin_config_get=sunxi_pconf_get,.pin_config_group_get=sunxi_pconf_group_get,.pin_config_group_set=sunxi_pconf_group_set,};
From: Maxime Ripard <hidden> Date: 2016-11-11 08:36:31
On Fri, Nov 11, 2016 at 10:44:54AM +0800, Chen-Yu Tsai wrote:
quoted hunk
The sunxi pinctrl driver only caches whatever pinconf setting was last
set on a given pingroup. This is not particularly helpful, nor is it
correct.
Fix this by actually reading the hardware registers and returning
the correct results or error codes. Also filter out unsupported
pinconf settings. Since this driver has a peculiar setup of 1 pin
per group, we can support both pin and pingroup pinconf setting
read back with the same code. The sunxi_pconf_reg helper and code
structure is inspired by pinctrl-msm.
With this done we can also claim to support generic pinconf, by
setting .is_generic = true in pinconf_ops.
Signed-off-by: Chen-Yu Tsai <redacted>
---
drivers/pinctrl/sunxi/pinctrl-sunxi.c | 84 +++++++++++++++++++++++++++++++++--
1 file changed, 81 insertions(+), 3 deletions(-)
@@ -438,15 +438,91 @@ static const struct pinctrl_ops sunxi_pctrl_ops = {.get_group_pins=sunxi_pctrl_get_group_pins,};+staticintsunxi_pconf_reg(unsignedpin,enumpin_config_paramparam,+u32*offset,u32*shift,u32*mask)+{+switch(param){+casePIN_CONFIG_DRIVE_STRENGTH:+*offset=sunxi_dlevel_reg(pin);+*shift=sunxi_dlevel_offset(pin);+*mask=DLEVEL_PINS_MASK;+break;++casePIN_CONFIG_BIAS_PULL_UP:+casePIN_CONFIG_BIAS_PULL_DOWN:+casePIN_CONFIG_BIAS_DISABLE:+*offset=sunxi_pull_reg(pin);+*shift=sunxi_pull_offset(pin);+*mask=PULL_PINS_MASK;+break;++default:+return-ENOTSUPP;+}++return0;+}++staticintsunxi_pconf_get(structpinctrl_dev*pctldev,unsignedpin,+unsignedlong*config)+{+structsunxi_pinctrl*pctl=pinctrl_dev_get_drvdata(pctldev);+enumpin_config_paramparam=pinconf_to_config_param(*config);+u32offset,shift,mask,val;+u16arg;+intret;++pin-=pctl->desc->pin_base;++ret=sunxi_pconf_reg(pin,param,&offset,&shift,&mask);+if(ret<0)+returnret;++val=(readl(pctl->membase+offset)>>shift)&mask;++switch(pinconf_to_config_param(*config)){+casePIN_CONFIG_DRIVE_STRENGTH:+arg=(val+1)*10;+break;++casePIN_CONFIG_BIAS_PULL_UP:+if(val!=SUN4I_PINCTRL_PULL_UP)+return-EINVAL;+arg=1;/* hardware is weak pull-up */+break;++casePIN_CONFIG_BIAS_PULL_DOWN:+if(val!=SUN4I_PINCTRL_PULL_DOWN)+return-EINVAL;+arg=1;/* hardware is weak pull-down */+break;++casePIN_CONFIG_BIAS_DISABLE:+if(val!=SUN4I_PINCTRL_NO_PULL)+return-EINVAL;+arg=0;+break;++default:+/* sunxi_pconf_reg should catch anything unsupported */+WARN_ON(1);+return-ENOTSUPP;+}++*config=pinconf_to_config_packed(param,arg);++return0;+}+staticintsunxi_pconf_group_get(structpinctrl_dev*pctldev,unsignedgroup,unsignedlong*config){structsunxi_pinctrl*pctl=pinctrl_dev_get_drvdata(pctldev);+structsunxi_pinctrl_group*g=&pctl->groups[group];-*config=pctl->groups[group].config;
Do we still need this variable? Looking at the code, it doesn't look
that way, and we can remove the caching in the _group_set function and
the variable itslef in the sunxi_pincttrl_group structure.
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161111/c66f592a/attachment-0001.sig>
On Fri, Nov 11, 2016 at 4:36 PM, Maxime Ripard
[off-list ref] wrote:
On Fri, Nov 11, 2016 at 10:44:54AM +0800, Chen-Yu Tsai wrote:
quoted
The sunxi pinctrl driver only caches whatever pinconf setting was last
set on a given pingroup. This is not particularly helpful, nor is it
correct.
Fix this by actually reading the hardware registers and returning
the correct results or error codes. Also filter out unsupported
pinconf settings. Since this driver has a peculiar setup of 1 pin
per group, we can support both pin and pingroup pinconf setting
read back with the same code. The sunxi_pconf_reg helper and code
structure is inspired by pinctrl-msm.
With this done we can also claim to support generic pinconf, by
setting .is_generic = true in pinconf_ops.
Signed-off-by: Chen-Yu Tsai <redacted>
---
drivers/pinctrl/sunxi/pinctrl-sunxi.c | 84 +++++++++++++++++++++++++++++++++--
1 file changed, 81 insertions(+), 3 deletions(-)
@@ -438,15 +438,91 @@ static const struct pinctrl_ops sunxi_pctrl_ops = {.get_group_pins=sunxi_pctrl_get_group_pins,};+staticintsunxi_pconf_reg(unsignedpin,enumpin_config_paramparam,+u32*offset,u32*shift,u32*mask)+{+switch(param){+casePIN_CONFIG_DRIVE_STRENGTH:+*offset=sunxi_dlevel_reg(pin);+*shift=sunxi_dlevel_offset(pin);+*mask=DLEVEL_PINS_MASK;+break;++casePIN_CONFIG_BIAS_PULL_UP:+casePIN_CONFIG_BIAS_PULL_DOWN:+casePIN_CONFIG_BIAS_DISABLE:+*offset=sunxi_pull_reg(pin);+*shift=sunxi_pull_offset(pin);+*mask=PULL_PINS_MASK;+break;++default:+return-ENOTSUPP;+}++return0;+}++staticintsunxi_pconf_get(structpinctrl_dev*pctldev,unsignedpin,+unsignedlong*config)+{+structsunxi_pinctrl*pctl=pinctrl_dev_get_drvdata(pctldev);+enumpin_config_paramparam=pinconf_to_config_param(*config);+u32offset,shift,mask,val;+u16arg;+intret;++pin-=pctl->desc->pin_base;++ret=sunxi_pconf_reg(pin,param,&offset,&shift,&mask);+if(ret<0)+returnret;++val=(readl(pctl->membase+offset)>>shift)&mask;++switch(pinconf_to_config_param(*config)){+casePIN_CONFIG_DRIVE_STRENGTH:+arg=(val+1)*10;+break;++casePIN_CONFIG_BIAS_PULL_UP:+if(val!=SUN4I_PINCTRL_PULL_UP)+return-EINVAL;+arg=1;/* hardware is weak pull-up */+break;++casePIN_CONFIG_BIAS_PULL_DOWN:+if(val!=SUN4I_PINCTRL_PULL_DOWN)+return-EINVAL;+arg=1;/* hardware is weak pull-down */+break;++casePIN_CONFIG_BIAS_DISABLE:+if(val!=SUN4I_PINCTRL_NO_PULL)+return-EINVAL;+arg=0;+break;++default:+/* sunxi_pconf_reg should catch anything unsupported */+WARN_ON(1);+return-ENOTSUPP;+}++*config=pinconf_to_config_packed(param,arg);++return0;+}+staticintsunxi_pconf_group_get(structpinctrl_dev*pctldev,unsignedgroup,unsignedlong*config){structsunxi_pinctrl*pctl=pinctrl_dev_get_drvdata(pctldev);+structsunxi_pinctrl_group*g=&pctl->groups[group];-*config=pctl->groups[group].config;
Do we still need this variable? Looking at the code, it doesn't look
that way, and we can remove the caching in the _group_set function and
the variable itslef in the sunxi_pincttrl_group structure.
It's actually removed in the next patch. :)
ChenYu
The sunxi_pconf_reg helper introduced in the last patch gives us the
chance to rework sunxi_pconf_group_set to have it match the structure
of sunxi_pconf_(group_)get and make it easier to understand.
For each config to set, it:
1. checks if the parameter is supported.
2. checks if the argument is within limits.
3. converts argument to the register value.
4. writes to the register with spinlock held.
As a result the function now blocks unsupported config parameters,
instead of silently ignoring them.
Signed-off-by: Chen-Yu Tsai <redacted>
---
drivers/pinctrl/sunxi/pinctrl-sunxi.c | 66 +++++++++++++++++------------------
drivers/pinctrl/sunxi/pinctrl-sunxi.h | 1 -
2 files changed, 32 insertions(+), 35 deletions(-)
@@ -532,23 +532,27 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,{structsunxi_pinctrl*pctl=pinctrl_dev_get_drvdata(pctldev);structsunxi_pinctrl_group*g=&pctl->groups[group];-unsignedlongflags;unsignedpin=g->pin-pctl->desc->pin_base;-u32val,mask;-u16strength;-u8dlevel;inti;-spin_lock_irqsave(&pctl->lock,flags);-for(i=0;i<num_configs;i++){-switch(pinconf_to_config_param(configs[i])){+enumpin_config_paramparam;+unsignedlongflags;+u32offset,shift,mask,reg;+u16arg,val;+intret;++param=pinconf_to_config_param(configs[i]);+arg=pinconf_to_config_argument(configs[i]);++ret=sunxi_pconf_reg(pin,param,&offset,&shift,&mask);+if(ret<0)+returnret;++switch(param){casePIN_CONFIG_DRIVE_STRENGTH:-strength=pinconf_to_config_argument(configs[i]);-if(strength>40){-spin_unlock_irqrestore(&pctl->lock,flags);+if(arg<10||arg>40)return-EINVAL;-}/**WeconvertfrommAtowhattheregisterexpects:*0:10mA
@@ -556,39 +560,33 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,*2:30mA*3:40mA*/-dlevel=strength/10-1;-val=readl(pctl->membase+sunxi_dlevel_reg(pin));-mask=DLEVEL_PINS_MASK<<sunxi_dlevel_offset(pin);-writel((val&~mask)-|dlevel<<sunxi_dlevel_offset(pin),-pctl->membase+sunxi_dlevel_reg(pin));+val=arg/10-1;break;casePIN_CONFIG_BIAS_DISABLE:-val=readl(pctl->membase+sunxi_pull_reg(pin));-mask=PULL_PINS_MASK<<sunxi_pull_offset(pin);-writel((val&~mask),-pctl->membase+sunxi_pull_reg(pin));+val=0;break;casePIN_CONFIG_BIAS_PULL_UP:-val=readl(pctl->membase+sunxi_pull_reg(pin));-mask=PULL_PINS_MASK<<sunxi_pull_offset(pin);-writel((val&~mask)|1<<sunxi_pull_offset(pin),-pctl->membase+sunxi_pull_reg(pin));+if(arg==0)+return-EINVAL;+val=1;break;casePIN_CONFIG_BIAS_PULL_DOWN:-val=readl(pctl->membase+sunxi_pull_reg(pin));-mask=PULL_PINS_MASK<<sunxi_pull_offset(pin);-writel((val&~mask)|2<<sunxi_pull_offset(pin),-pctl->membase+sunxi_pull_reg(pin));+if(arg==0)+return-EINVAL;+val=2;break;default:-break;+/* sunxi_pconf_reg should catch anything unsupported */+WARN_ON(1);+return-ENOTSUPP;}-/* cache the config value */-g->config=configs[i];-}/* for each config */-spin_unlock_irqrestore(&pctl->lock,flags);+spin_lock_irqsave(&pctl->lock,flags);+reg=readl(pctl->membase+offset);+reg&=~(mask<<shift);+writel(reg|val<<shift,pctl->membase+offset);+spin_unlock_irqrestore(&pctl->lock,flags);+}/* for each config */return0;}
From: Maxime Ripard <hidden> Date: 2016-11-11 08:38:56
On Fri, Nov 11, 2016 at 10:44:55AM +0800, Chen-Yu Tsai wrote:
The sunxi_pconf_reg helper introduced in the last patch gives us the
chance to rework sunxi_pconf_group_set to have it match the structure
of sunxi_pconf_(group_)get and make it easier to understand.
For each config to set, it:
1. checks if the parameter is supported.
2. checks if the argument is within limits.
3. converts argument to the register value.
4. writes to the register with spinlock held.
As a result the function now blocks unsupported config parameters,
instead of silently ignoring them.
Signed-off-by: Chen-Yu Tsai <redacted>
Acked-by: Maxime Ripard <redacted>
But I think the config variable removal should be part of patch 2, as
discussed there.
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161111/67b851bb/attachment.sig>
On Fri, Nov 11, 2016 at 4:38 PM, Maxime Ripard
[off-list ref] wrote:
On Fri, Nov 11, 2016 at 10:44:55AM +0800, Chen-Yu Tsai wrote:
quoted
The sunxi_pconf_reg helper introduced in the last patch gives us the
chance to rework sunxi_pconf_group_set to have it match the structure
of sunxi_pconf_(group_)get and make it easier to understand.
For each config to set, it:
1. checks if the parameter is supported.
2. checks if the argument is within limits.
3. converts argument to the register value.
4. writes to the register with spinlock held.
As a result the function now blocks unsupported config parameters,
instead of silently ignoring them.
Signed-off-by: Chen-Yu Tsai <redacted>
Acked-by: Maxime Ripard <redacted>
But I think the config variable removal should be part of patch 2, as
discussed there.
OK. I think that makes sense. Re-reading my patches, I can't figure out,
which patch I meant for it to go in. :(
I'll send out a v3.
ChenYu