diff options
Diffstat (limited to 'drivers/reset/reset-rzg2l-usbphy-ctrl.c')
| -rw-r--r-- | drivers/reset/reset-rzg2l-usbphy-ctrl.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/drivers/reset/reset-rzg2l-usbphy-ctrl.c b/drivers/reset/reset-rzg2l-usbphy-ctrl.c index 8a7f167e405e..4ecb9acb2641 100644 --- a/drivers/reset/reset-rzg2l-usbphy-ctrl.c +++ b/drivers/reset/reset-rzg2l-usbphy-ctrl.c @@ -13,6 +13,7 @@ #include <linux/regmap.h> #include <linux/reset.h> #include <linux/reset-controller.h> +#include <linux/mfd/syscon.h> #define RESET 0x000 #define VBENCTL 0x03c @@ -91,8 +92,14 @@ static int rzg2l_usbphy_ctrl_status(struct reset_controller_dev *rcdev, return !!(readl(priv->base + RESET) & port_mask); } +#define RZG2L_USBPHY_CTRL_PWRRDY 1 + static const struct of_device_id rzg2l_usbphy_ctrl_match_table[] = { { .compatible = "renesas,rzg2l-usbphy-ctrl" }, + { + .compatible = "renesas,r9a08g045-usbphy-ctrl", + .data = (void *)RZG2L_USBPHY_CTRL_PWRRDY + }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, rzg2l_usbphy_ctrl_match_table); @@ -110,6 +117,55 @@ static const struct regmap_config rzg2l_usb_regconf = { .max_register = 1, }; +static void rzg2l_usbphy_ctrl_set_pwrrdy(struct regmap_field *pwrrdy, + bool power_on) +{ + u32 val = power_on ? 0 : 1; + + /* The initialization path guarantees that the mask is 1 bit long. */ + regmap_field_update_bits(pwrrdy, 1, val); +} + +static void rzg2l_usbphy_ctrl_pwrrdy_off(void *data) +{ + rzg2l_usbphy_ctrl_set_pwrrdy(data, false); +} + +static int rzg2l_usbphy_ctrl_pwrrdy_init(struct device *dev) +{ + struct regmap_field *pwrrdy; + struct reg_field field; + struct regmap *regmap; + const int *data; + u32 args[2]; + + data = device_get_match_data(dev); + if ((uintptr_t)data != RZG2L_USBPHY_CTRL_PWRRDY) + return 0; + + regmap = syscon_regmap_lookup_by_phandle_args(dev->of_node, + "renesas,sysc-pwrrdy", + ARRAY_SIZE(args), args); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* Don't allow more than one bit in mask. */ + if (hweight32(args[1]) != 1) + return -EINVAL; + + field.reg = args[0]; + field.lsb = __ffs(args[1]); + field.msb = __fls(args[1]); + + pwrrdy = devm_regmap_field_alloc(dev, regmap, field); + if (IS_ERR(pwrrdy)) + return PTR_ERR(pwrrdy); + + rzg2l_usbphy_ctrl_set_pwrrdy(pwrrdy, true); + + return devm_add_action_or_reset(dev, rzg2l_usbphy_ctrl_pwrrdy_off, pwrrdy); +} + static int rzg2l_usbphy_ctrl_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -132,6 +188,10 @@ static int rzg2l_usbphy_ctrl_probe(struct platform_device *pdev) if (IS_ERR(regmap)) return PTR_ERR(regmap); + error = rzg2l_usbphy_ctrl_pwrrdy_init(dev); + if (error) + return error; + priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(priv->rstc)) return dev_err_probe(dev, PTR_ERR(priv->rstc), |
