USB: HSIC SMSC HUB: Add support for pinctrl framework

As the newer targets will be using pinctrl framework for gpio
configuration, our drivers need to be compatible with both set of targets
the one which do not use pinctrl and one which do. Adding support for both
these cases. smsc hub driver can configure reset, refclk, xo-clk and int
gpios

Change-Id: I2517058f92db051cb5a650e930f424d972be16a1
Signed-off-by: Tarun Gupta <tarung@codeaurora.org>
This commit is contained in:
Tarun Gupta 2014-02-12 19:30:29 +05:30 committed by Gerrit - the friendly Code Review server
parent e29cc5ee49
commit a85d52fa33
2 changed files with 97 additions and 31 deletions

View file

@ -162,10 +162,25 @@ Required properties :
Sub node has the required properties mentioned above.
Optional properties :
- pinctrl-names : This should be defined if a target uses pinctrl framework.
See "pinctrl" in Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt.
It should specify the names of the configs that pinctrl can install in driver
Following are the pinctrl configs that can be installed
"smsc_active" : Active configuration of pins, this should specify active
config defined in pin groups of used gpio's from reset, refclk, xo-clk
and int.
"smsc_sleep" : Disabled configuration of pins, this should specify the sleep
config defined in pin groups of used gpio's from reset, refclk, xo-clk
and int.
If pinctrl is being used we need to only define gpio's which drives signals
using gpiolib api's like reset and xo-clk gpio in dt, the node name in such
cases should be msm_gpio as defined in pinctrl-dtsi. For gpio's only
installing active and sleep configs it is not required to specify the gpio
in dt file.
- smsc,int-gpio: this input gpio indicate HUB suspend status and signal remote
wakeup interrupt
- smsc,refclk-gpio: this gpio is used to supply the reference clock
- smsc,xo-clk-gio: this output gpio is used to control the external XO clock
- smsc,xo-clk-gpio: this output gpio is used to control the external XO clock
which is supplied to the hub as a reference clock
- hub-vbus-supply: this regulator is used to supply the power to
downstream ports
@ -178,9 +193,16 @@ Example SMSC HSIC HUB :
compatible = "qcom,hsic-smsc-hub";
smsc,model-id = <4604>;
ranges;
/* If pinctrl is used with all gpio_present */
pinctrl-names = "smsc_active","smsc_sleep";
pinctrl-0 = <&reset_act &refclk_act &int_act>;
pinctrl-1 = <&reset_sus &refclk_sus &int_sus>;
smsc,reset-gpio = <&pm8941_gpios 8 0x00>;
/* If target does not use pinctrl */
smsc,reset-gpio = <&pm8941_gpios 8 0x00>;
smsc,refclk-gpio = <&pm8941_gpios 16 0x00>;
smsc,int-gpio = <&msmgpio 50 0x00>;
/* End if */
hub-int-supply = <&pm8941_l10>;
hub-vbus-supply = <&pm8941_mvs1>;
@ -198,4 +220,3 @@ Example SMSC HSIC HUB :
hsic,data-pad-offset = <0x2054>;
};
};

View file

@ -14,6 +14,7 @@
#include <linux/err.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
@ -37,6 +38,7 @@ struct hsic_hub {
struct regulator *hsic_hub_reg;
struct regulator *int_pad_reg, *hub_vbus_reg;
bool enabled;
struct pinctrl *smsc_pinctrl;
};
static struct hsic_hub *smsc_hub;
static struct platform_driver smsc_hub_driver;
@ -240,7 +242,8 @@ static int msm_hsic_hub_init_clock(struct hsic_hub *hub, int init)
#define HSIC_HUB_INT_VOL_MAX 2950000 /* uV */
static int msm_hsic_hub_init_gpio(struct hsic_hub *hub, int init)
{
int ret;
int ret = 0;
struct pinctrl_state *set_state;
struct smsc_hub_platform_data *pdata = hub->pdata;
if (!init) {
@ -249,40 +252,82 @@ static int msm_hsic_hub_init_gpio(struct hsic_hub *hub, int init)
regulator_set_voltage(smsc_hub->int_pad_reg, 0,
HSIC_HUB_INT_VOL_MAX);
}
return 0;
if (smsc_hub->smsc_pinctrl) {
set_state = pinctrl_lookup_state(smsc_hub->smsc_pinctrl,
"smsc_sleep");
if (IS_ERR(set_state)) {
pr_err("cannot get smsc pinctrl sleep state\n");
ret = PTR_ERR(set_state);
goto out;
}
ret = pinctrl_select_state(smsc_hub->smsc_pinctrl,
set_state);
}
goto out;
}
/* Get pinctrl if target uses pinctrl */
smsc_hub->smsc_pinctrl = devm_pinctrl_get(smsc_hub->dev);
if (IS_ERR(smsc_hub->smsc_pinctrl)) {
if (of_property_read_bool(smsc_hub->dev->of_node,
"pinctrl-names")) {
dev_err(smsc_hub->dev, "Error encountered while getting pinctrl");
ret = PTR_ERR(smsc_hub->smsc_pinctrl);
goto out;
}
dev_dbg(smsc_hub->dev, "Target does not use pinctrl\n");
smsc_hub->smsc_pinctrl = NULL;
}
if (smsc_hub->smsc_pinctrl) {
set_state = pinctrl_lookup_state(smsc_hub->smsc_pinctrl,
"smsc_active");
if (IS_ERR(set_state)) {
pr_err("cannot get smsc pinctrl active state\n");
ret = PTR_ERR(set_state);
goto out;
}
ret = pinctrl_select_state(smsc_hub->smsc_pinctrl, set_state);
if (ret) {
pr_err("cannot set smsc pinctrl active state\n");
goto out;
}
}
ret = devm_gpio_request(hub->dev, pdata->hub_reset, "HSIC_HUB_RESET");
if (ret < 0) {
dev_err(hub->dev, "gpio request failed for GPIO%d\n",
pdata->hub_reset);
return ret;
goto out;
}
if (pdata->refclk_gpio) {
ret = devm_gpio_request(hub->dev, pdata->refclk_gpio,
"HSIC_HUB_CLK");
if (ret < 0)
dev_err(hub->dev, "gpio request failed (CLK GPIO)\n");
}
if (pdata->xo_clk_gpio) {
ret = devm_gpio_request(hub->dev, pdata->xo_clk_gpio,
"HSIC_HUB_XO_CLK");
if (ret < 0) {
dev_err(hub->dev, "gpio request failed(XO CLK GPIO)\n");
return ret;
}
}
if (pdata->int_gpio) {
ret = devm_gpio_request(hub->dev, pdata->int_gpio,
"HSIC_HUB_INT");
if (ret < 0) {
dev_err(hub->dev, "gpio request failed (INT GPIO)\n");
return ret;
if (IS_ERR_OR_NULL(smsc_hub->smsc_pinctrl)) {
if (pdata->refclk_gpio) {
ret = devm_gpio_request(hub->dev, pdata->refclk_gpio,
"HSIC_HUB_CLK");
if (ret < 0)
dev_err(hub->dev, "gpio request failed (CLK GPIO)\n");
}
if (pdata->xo_clk_gpio) {
ret = devm_gpio_request(hub->dev, pdata->xo_clk_gpio,
"HSIC_HUB_XO_CLK");
if (ret < 0) {
dev_err(hub->dev, "gpio request failed(XO CLK GPIO)\n");
goto out;
}
}
if (pdata->int_gpio) {
ret = devm_gpio_request(hub->dev, pdata->int_gpio,
"HSIC_HUB_INT");
if (ret < 0) {
dev_err(hub->dev, "gpio request failed (INT GPIO)\n");
goto out;
}
}
}
if (of_get_property(smsc_hub->dev->of_node, "hub-int-supply", NULL)) {
/* Enable LDO if required for external pull-up */
smsc_hub->int_pad_reg = devm_regulator_get(hub->dev, "hub-int");
if (IS_ERR(smsc_hub->int_pad_reg)) {
@ -294,19 +339,19 @@ static int msm_hsic_hub_init_gpio(struct hsic_hub *hub, int init)
if (ret) {
dev_err(hub->dev, "unable to set the voltage\n"
" for hsic hub int reg\n");
return ret;
goto out;
}
ret = regulator_enable(smsc_hub->int_pad_reg);
if (ret) {
dev_err(hub->dev, "unable to enable int reg\n");
regulator_set_voltage(smsc_hub->int_pad_reg, 0,
HSIC_HUB_INT_VOL_MAX);
return ret;
goto out;
}
}
}
return 0;
out:
return ret;
}
#define HSIC_HUB_VDD_VOL_MIN 1650000 /* uV */