On 12/07/18 13:00, Aapo Vienamo wrote: > Register a pinctrl device and implement get and set functions for > PIN_CONFIG_LOW_POWER_MODE and PIN_CONFIG_POWER_SOURCE parameters. > > Signed-off-by: Aapo Vienamo <avienamo@xxxxxxxxxx> > --- > drivers/soc/tegra/pmc.c | 187 +++++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 185 insertions(+), 2 deletions(-) > > diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c > index 7d3c3de..6bfd00d 100644 > --- a/drivers/soc/tegra/pmc.c > +++ b/drivers/soc/tegra/pmc.c > @@ -33,6 +33,9 @@ > #include <linux/of_address.h> > #include <linux/of_clk.h> > #include <linux/of_platform.h> > +#include <linux/pinctrl/pinctrl.h> > +#include <linux/pinctrl/pinconf.h> > +#include <linux/pinctrl/pinconf-generic.h> > #include <linux/platform_device.h> > #include <linux/pm_domain.h> > #include <linux/reboot.h> > @@ -164,6 +167,9 @@ struct tegra_pmc_soc { > const struct tegra_io_pad_soc *io_pads; > unsigned int num_io_pads; > > + const struct pinctrl_pin_desc *pin_descs; > + unsigned int num_pin_descs; > + > const struct tegra_pmc_regs *regs; > void (*init)(struct tegra_pmc *pmc); > void (*setup_irq_polarity)(struct tegra_pmc *pmc, > @@ -222,6 +228,8 @@ struct tegra_pmc { > DECLARE_BITMAP(powergates_available, TEGRA_POWERGATE_MAX); > > struct mutex powergates_lock; > + > + struct pinctrl_dev *pctl_dev; > }; > > static struct tegra_pmc *pmc = &(struct tegra_pmc) { > @@ -1398,6 +1406,142 @@ static void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc) > of_node_put(np); > } > > +static int tegra_io_pad_pinctrl_get_groups_count(struct pinctrl_dev *pctl_dev) > +{ > + return pmc->soc->num_io_pads; > +} > + > +static const char *tegra_io_pad_pinctrl_get_group_name( > + struct pinctrl_dev *pctl, unsigned int group) > +{ > + return pmc->soc->io_pads[group].name; > +} > + > +static int tegra_io_pad_pinctrl_get_group_pins(struct pinctrl_dev *pctl_dev, > + unsigned int group, > + const unsigned int **pins, > + unsigned int *num_pins) > +{ > + *pins = &pmc->soc->io_pads[group].id; > + *num_pins = 1; > + return 0; > +} > + > +static const struct pinctrl_ops tegra_io_pad_pinctrl_ops = { > + .get_groups_count = tegra_io_pad_pinctrl_get_groups_count, > + .get_group_name = tegra_io_pad_pinctrl_get_group_name, > + .get_group_pins = tegra_io_pad_pinctrl_get_group_pins, > + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, > + .dt_free_map = pinconf_generic_dt_free_map, > +}; > + > +static int tegra_io_pad_pinconf_get(struct pinctrl_dev *pctl_dev, > + unsigned int pin, unsigned long *config) > +{ > + const struct tegra_io_pad_soc *pad = tegra_io_pad_find(pmc, pin); > + enum pin_config_param param = pinconf_to_config_param(*config); > + int ret; > + u32 arg; > + > + if (!pad) > + return -EINVAL; > + > + switch (param) { > + case PIN_CONFIG_POWER_SOURCE: > + ret = tegra_io_pad_get_voltage(pad->id); > + if (ret < 0) > + return ret; > + arg = ret; > + break; > + case PIN_CONFIG_LOW_POWER_MODE: > + ret = tegra_io_pad_is_powered(pad->id); > + if (ret < 0) > + return ret; > + arg = !ret; > + break; > + default: > + return -EINVAL; > + } > + > + *config = pinconf_to_config_packed(param, arg); > + > + return 0; > +} > + > +static int tegra_io_pad_pinconf_set(struct pinctrl_dev *pctl_dev, > + unsigned int pin, unsigned long *configs, > + unsigned int num_configs) > +{ > + const struct tegra_io_pad_soc *pad = tegra_io_pad_find(pmc, pin); > + enum pin_config_param param; > + unsigned int i; > + int err; > + u32 arg; > + > + if (!pad) > + 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_LOW_POWER_MODE: > + if (arg) > + err = tegra_io_pad_power_disable(pad->id); > + else > + err = tegra_io_pad_power_enable(pad->id); > + if (err) > + return err; > + break; > + case PIN_CONFIG_POWER_SOURCE: > + if (arg != TEGRA_IO_PAD_VOLTAGE_1V8 && > + arg != TEGRA_IO_PAD_VOLTAGE_3V3) > + return -EINVAL; > + err = tegra_io_pad_set_voltage(pad->id, arg); > + if (err) > + return err; > + break; > + default: > + return -EINVAL; > + } > + } > + > + return 0; > +} > + > +static const struct pinconf_ops tegra_io_pad_pinconf_ops = { > + .pin_config_get = tegra_io_pad_pinconf_get, > + .pin_config_set = tegra_io_pad_pinconf_set, > + .is_generic = true, > +}; > + > +static struct pinctrl_desc tegra_pmc_pctl_desc = { > + .pctlops = &tegra_io_pad_pinctrl_ops, > + .confops = &tegra_io_pad_pinconf_ops, > +}; > + > +static int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc) > +{ > + int err = 0; > + > + if (!pmc->soc->num_pin_descs) > + return 0; > + > + tegra_pmc_pctl_desc.name = dev_name(pmc->dev); > + tegra_pmc_pctl_desc.pins = pmc->soc->pin_descs; > + tegra_pmc_pctl_desc.npins = pmc->soc->num_pin_descs; > + > + pmc->pctl_dev = devm_pinctrl_register(pmc->dev, &tegra_pmc_pctl_desc, > + pmc); > + if (IS_ERR(pmc->pctl_dev)) { > + err = PTR_ERR(pmc->pctl_dev); > + dev_err(pmc->dev, "unable to register pinctrl, %d\n", err); > + } > + > + return err; > +} > + > static int tegra_pmc_probe(struct platform_device *pdev) > { > void __iomem *base; > @@ -1475,18 +1619,27 @@ static int tegra_pmc_probe(struct platform_device *pdev) > > err = register_restart_handler(&tegra_pmc_restart_handler); > if (err) { > - debugfs_remove(pmc->debugfs); > dev_err(&pdev->dev, "unable to register restart handler, %d\n", > err); > - return err; > + goto cleanup_debugfs; > } > > + err = tegra_pmc_pinctrl_init(pmc); > + if (err) > + goto cleanup_restart_handler; > + > mutex_lock(&pmc->powergates_lock); > iounmap(pmc->base); > pmc->base = base; > mutex_unlock(&pmc->powergates_lock); > > return 0; > + > +cleanup_restart_handler: > + unregister_restart_handler(&tegra_pmc_restart_handler); > +cleanup_debugfs: > + debugfs_remove(pmc->debugfs); > + return err; > } > > #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM) > @@ -1576,6 +1729,8 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { > .has_gpu_clamps = false, > .num_io_pads = 0, > .io_pads = NULL, > + .num_pin_descs = 0, > + .pin_descs = NULL, > .regs = &tegra20_pmc_regs, > .init = tegra20_pmc_init, > .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, > @@ -1615,6 +1770,8 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { > .has_impl_33v_pwr = false, > .num_io_pads = 0, > .io_pads = NULL, > + .num_pin_descs = 0, > + .pin_descs = NULL, > .regs = &tegra20_pmc_regs, > .init = tegra20_pmc_init, > .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, > @@ -1658,6 +1815,8 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { > .has_impl_33v_pwr = false, > .num_io_pads = 0, > .io_pads = NULL, > + .num_pin_descs = 0, > + .pin_descs = NULL, > .regs = &tegra20_pmc_regs, > .init = tegra20_pmc_init, > .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, > @@ -1704,6 +1863,12 @@ static const u8 tegra124_cpu_powergates[] = { > .name = (_name), \ > }) > > +#define TEGRA_IO_PIN_DESC(_id, _dpd, _voltage, _name) \ > + ((struct pinctrl_pin_desc) { \ > + .number = (_id), \ > + .name = (_name) \ > + }) > + > #define TEGRA124_IO_PAD_TABLE(_pad) \ > /* .id .dpd .voltage .name */ \ > _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \ > @@ -1741,6 +1906,10 @@ static const struct tegra_io_pad_soc tegra124_io_pads[] = { > TEGRA124_IO_PAD_TABLE(TEGRA_IO_PAD) > }; > > +static const struct pinctrl_pin_desc tegra124_pin_descs[] = { > + TEGRA124_IO_PAD_TABLE(TEGRA_IO_PIN_DESC) > +}; > + > static const struct tegra_pmc_soc tegra124_pmc_soc = { > .num_powergates = ARRAY_SIZE(tegra124_powergates), > .powergates = tegra124_powergates, > @@ -1751,6 +1920,8 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { > .has_impl_33v_pwr = false, > .num_io_pads = ARRAY_SIZE(tegra124_io_pads), > .io_pads = tegra124_io_pads, > + .num_pin_descs = ARRAY_SIZE(tegra124_pin_descs), > + .pin_descs = tegra124_pin_descs, > .regs = &tegra20_pmc_regs, > .init = tegra20_pmc_init, > .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, > @@ -1835,6 +2006,10 @@ static const struct tegra_io_pad_soc tegra210_io_pads[] = { > TEGRA210_IO_PAD_TABLE(TEGRA_IO_PAD) > }; > > +static const struct pinctrl_pin_desc tegra210_pin_descs[] = { > + TEGRA210_IO_PAD_TABLE(TEGRA_IO_PIN_DESC) > +}; > + > static const struct tegra_pmc_soc tegra210_pmc_soc = { > .num_powergates = ARRAY_SIZE(tegra210_powergates), > .powergates = tegra210_powergates, > @@ -1846,6 +2021,8 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { > .needs_mbist_war = true, > .num_io_pads = ARRAY_SIZE(tegra210_io_pads), > .io_pads = tegra210_io_pads, > + .num_pin_descs = ARRAY_SIZE(tegra210_pin_descs), > + .pin_descs = tegra210_pin_descs, > .regs = &tegra20_pmc_regs, > .init = tegra20_pmc_init, > .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, > @@ -1896,6 +2073,10 @@ static const struct tegra_io_pad_soc tegra186_io_pads[] = { > TEGRA186_IO_PAD_TABLE(TEGRA_IO_PAD) > }; > > +static const struct pinctrl_pin_desc tegra186_pin_descs[] = { > + TEGRA186_IO_PAD_TABLE(TEGRA_IO_PIN_DESC) > +}; > + > static const struct tegra_pmc_regs tegra186_pmc_regs = { > .scratch0 = 0x2000, > .dpd_req = 0x74, > @@ -1949,6 +2130,8 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = { > .has_impl_33v_pwr = true, > .num_io_pads = ARRAY_SIZE(tegra186_io_pads), > .io_pads = tegra186_io_pads, > + .num_pin_descs = ARRAY_SIZE(tegra186_pin_descs), > + .pin_descs = tegra186_pin_descs, > .regs = &tegra186_pmc_regs, > .init = NULL, > .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, > Acked-by: Jon Hunter <jonathanh@xxxxxxxxxx> Cheers Jon -- nvpublic -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html