Samsung pinctrl drivers changes for v6.12
1. Few cleanups: use more appropriate of_property_present(), use scoped OF nodes handling and switch to kmemdup_array(). 2. Implement configuring pull-up and pull-down via GPIOLIB. -----BEGIN PGP SIGNATURE----- iQJEBAABCgAuFiEE3dJiKD0RGyM7briowTdm5oaLg9cFAmbNxFMQHGtyemtAa2Vy bmVsLm9yZwAKCRDBN2bmhouD15c8D/9nRIQ9P44h63kjRvt10xeLxAYN7yXGOtmZ ej2/EIimoXCLfyUt9GyKJGQ2W0nMA+XLD5epWy6oski5m7BIZbfLSM5PwBjH+iZY 9roPj0JArDA/KM9ubtO2qTpOAzLw5UV/E207Ecro6mP+BPgXZh42lpPbdkU3ALcG w+H7yhWB6mnqXIPu50dv6bMD5jAxCZW8J+CTNZMHe41MKjPvDauxqJW8dOrB2Ld5 0SeiN+2LhSA6QUJs98S0A5Nrl1WOBdHce5icK5S1I4Xv7WvLl0cs3xg7HkH1zZpr WOGDLOniSkIYrr+AiyxL0euEWGCuLFnfxc60ULGoF21KdZQAHEbiEl7eGkKMLm60 I7Ujnh6NxG0cYmHVbAkvZr+esb9WYe3zWjsGNFUaaBnhQ7qTmOuIfRp34gM3TK7q 7DKEHE8/sH5uoAPW34OtcggqPysXIsAUYqnAqso5UWcpR1S/VZkCtyEb+f61X61J ek/tOd/idMZTjYdcncxQoMDGl1X/bvlanEsKovhoosOUr70wN4wtzDXy7HvFOb/3 CsF8x6f9qh4BGGIaV7sAxMWSTODjrkCkhXNZvAVPHCMp3SY7pALIskOa0gVSEkmD sYBWU09xMvR4fZ09tE9yVF1PlBU+KwX+72qm4TtPKZJOegxxEQkywmp35znc4kRB ovHr08irwQ== =worQ -----END PGP SIGNATURE----- Merge tag 'samsung-pinctrl-6.12' of https://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung into devel Samsung pinctrl drivers changes for v6.12 1. Few cleanups: use more appropriate of_property_present(), use scoped OF nodes handling and switch to kmemdup_array(). 2. Implement configuring pull-up and pull-down via GPIOLIB. Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
commit
cd77b0dd6f
@ -40,6 +40,19 @@ static const struct samsung_pin_bank_type bank_type_alive = {
|
||||
#define S5P_OTHERS_RET_MMC (1 << 29)
|
||||
#define S5P_OTHERS_RET_UART (1 << 28)
|
||||
|
||||
#define S5P_PIN_PULL_DISABLE 0
|
||||
#define S5P_PIN_PULL_DOWN 1
|
||||
#define S5P_PIN_PULL_UP 2
|
||||
|
||||
static void s5pv210_pud_value_init(struct samsung_pinctrl_drv_data *drvdata)
|
||||
{
|
||||
unsigned int *pud_val = drvdata->pud_val;
|
||||
|
||||
pud_val[PUD_PULL_DISABLE] = S5P_PIN_PULL_DISABLE;
|
||||
pud_val[PUD_PULL_DOWN] = S5P_PIN_PULL_DOWN;
|
||||
pud_val[PUD_PULL_UP] = S5P_PIN_PULL_UP;
|
||||
}
|
||||
|
||||
static void s5pv210_retention_disable(struct samsung_pinctrl_drv_data *drvdata)
|
||||
{
|
||||
void __iomem *clk_base = (void __iomem *)drvdata->retention_ctrl->priv;
|
||||
@ -133,6 +146,7 @@ static const struct samsung_pin_ctrl s5pv210_pin_ctrl[] __initconst = {
|
||||
.nr_banks = ARRAY_SIZE(s5pv210_pin_bank),
|
||||
.eint_gpio_init = exynos_eint_gpio_init,
|
||||
.eint_wkup_init = exynos_eint_wkup_init,
|
||||
.pud_value_init = s5pv210_pud_value_init,
|
||||
.suspend = exynos_pinctrl_suspend,
|
||||
.resume = exynos_pinctrl_resume,
|
||||
.retention_data = &s5pv210_retention_data,
|
||||
|
@ -662,7 +662,7 @@ static void exynos_irq_demux_eint16_31(struct irq_desc *desc)
|
||||
__init int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
|
||||
{
|
||||
struct device *dev = d->dev;
|
||||
struct device_node *wkup_np = NULL;
|
||||
struct device_node *wkup_np __free(device_node) = NULL;
|
||||
struct device_node *np;
|
||||
struct samsung_pin_bank *bank;
|
||||
struct exynos_weint_data *weint_data;
|
||||
@ -692,17 +692,14 @@ __init int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
|
||||
|
||||
bank->irq_chip = devm_kmemdup(dev, irq_chip, sizeof(*irq_chip),
|
||||
GFP_KERNEL);
|
||||
if (!bank->irq_chip) {
|
||||
of_node_put(wkup_np);
|
||||
if (!bank->irq_chip)
|
||||
return -ENOMEM;
|
||||
}
|
||||
bank->irq_chip->chip.name = bank->name;
|
||||
|
||||
bank->irq_domain = irq_domain_create_linear(bank->fwnode,
|
||||
bank->nr_pins, &exynos_eint_irqd_ops, bank);
|
||||
if (!bank->irq_domain) {
|
||||
dev_err(dev, "wkup irq domain add failed\n");
|
||||
of_node_put(wkup_np);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
@ -715,10 +712,8 @@ __init int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
|
||||
weint_data = devm_kcalloc(dev,
|
||||
bank->nr_pins, sizeof(*weint_data),
|
||||
GFP_KERNEL);
|
||||
if (!weint_data) {
|
||||
of_node_put(wkup_np);
|
||||
if (!weint_data)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (idx = 0; idx < bank->nr_pins; ++idx) {
|
||||
irq = irq_of_parse_and_map(to_of_node(bank->fwnode), idx);
|
||||
@ -735,13 +730,10 @@ __init int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
|
||||
}
|
||||
}
|
||||
|
||||
if (!muxed_banks) {
|
||||
of_node_put(wkup_np);
|
||||
if (!muxed_banks)
|
||||
return 0;
|
||||
}
|
||||
|
||||
irq = irq_of_parse_and_map(wkup_np, 0);
|
||||
of_node_put(wkup_np);
|
||||
if (!irq) {
|
||||
dev_err(dev, "irq number for muxed EINTs not found\n");
|
||||
return 0;
|
||||
|
@ -63,6 +63,10 @@
|
||||
#define EINT_CON_MASK 0xF
|
||||
#define EINT_CON_LEN 4
|
||||
|
||||
#define S3C_PIN_PULL_DISABLE 0
|
||||
#define S3C_PIN_PULL_DOWN 1
|
||||
#define S3C_PIN_PULL_UP 2
|
||||
|
||||
static const struct samsung_pin_bank_type bank_type_4bit_off = {
|
||||
.fld_width = { 4, 1, 2, 0, 2, 2, },
|
||||
.reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, },
|
||||
@ -255,6 +259,15 @@ static int s3c64xx_irq_get_trigger(unsigned int type)
|
||||
return trigger;
|
||||
}
|
||||
|
||||
static void s3c64xx_pud_value_init(struct samsung_pinctrl_drv_data *drvdata)
|
||||
{
|
||||
unsigned int *pud_val = drvdata->pud_val;
|
||||
|
||||
pud_val[PUD_PULL_DISABLE] = S3C_PIN_PULL_DISABLE;
|
||||
pud_val[PUD_PULL_DOWN] = S3C_PIN_PULL_DOWN;
|
||||
pud_val[PUD_PULL_UP] = S3C_PIN_PULL_UP;
|
||||
}
|
||||
|
||||
static void s3c64xx_irq_set_handler(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
/* Edge- and level-triggered interrupts need different handlers */
|
||||
@ -797,6 +810,7 @@ static const struct samsung_pin_ctrl s3c64xx_pin_ctrl[] __initconst = {
|
||||
.nr_banks = ARRAY_SIZE(s3c64xx_pin_banks0),
|
||||
.eint_gpio_init = s3c64xx_eint_gpio_init,
|
||||
.eint_wkup_init = s3c64xx_eint_eint0_init,
|
||||
.pud_value_init = s3c64xx_pud_value_init,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -122,8 +122,8 @@ static int add_map_configs(struct device *dev, struct pinctrl_map **map,
|
||||
if (WARN_ON(*num_maps == *reserved_maps))
|
||||
return -ENOSPC;
|
||||
|
||||
dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
|
||||
GFP_KERNEL);
|
||||
dup_configs = kmemdup_array(configs, num_configs, sizeof(*dup_configs),
|
||||
GFP_KERNEL);
|
||||
if (!dup_configs)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -251,7 +251,6 @@ static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev,
|
||||
{
|
||||
struct samsung_pinctrl_drv_data *drvdata;
|
||||
unsigned reserved_maps;
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
|
||||
drvdata = pinctrl_dev_get_drvdata(pctldev);
|
||||
@ -266,12 +265,11 @@ static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev,
|
||||
&reserved_maps,
|
||||
num_maps);
|
||||
|
||||
for_each_child_of_node(np_config, np) {
|
||||
for_each_child_of_node_scoped(np_config, np) {
|
||||
ret = samsung_dt_subnode_to_map(drvdata, pctldev->dev, np, map,
|
||||
&reserved_maps, num_maps);
|
||||
if (ret < 0) {
|
||||
samsung_dt_free_map(pctldev, *map, *num_maps);
|
||||
of_node_put(np);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -823,16 +821,16 @@ static struct samsung_pmx_func *samsung_pinctrl_create_functions(
|
||||
struct device_node *func_np;
|
||||
|
||||
if (!of_get_child_count(cfg_np)) {
|
||||
if (!of_find_property(cfg_np,
|
||||
"samsung,pin-function", NULL))
|
||||
if (!of_property_present(cfg_np,
|
||||
"samsung,pin-function"))
|
||||
continue;
|
||||
++func_cnt;
|
||||
continue;
|
||||
}
|
||||
|
||||
for_each_child_of_node(cfg_np, func_np) {
|
||||
if (!of_find_property(func_np,
|
||||
"samsung,pin-function", NULL))
|
||||
if (!of_property_present(func_np,
|
||||
"samsung,pin-function"))
|
||||
continue;
|
||||
++func_cnt;
|
||||
}
|
||||
@ -849,16 +847,12 @@ static struct samsung_pmx_func *samsung_pinctrl_create_functions(
|
||||
* and create pin groups and pin function lists.
|
||||
*/
|
||||
func_cnt = 0;
|
||||
for_each_child_of_node(dev_np, cfg_np) {
|
||||
struct device_node *func_np;
|
||||
|
||||
for_each_child_of_node_scoped(dev_np, cfg_np) {
|
||||
if (!of_get_child_count(cfg_np)) {
|
||||
ret = samsung_pinctrl_create_function(dev, drvdata,
|
||||
cfg_np, func);
|
||||
if (ret < 0) {
|
||||
of_node_put(cfg_np);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
if (ret > 0) {
|
||||
++func;
|
||||
++func_cnt;
|
||||
@ -866,14 +860,11 @@ static struct samsung_pmx_func *samsung_pinctrl_create_functions(
|
||||
continue;
|
||||
}
|
||||
|
||||
for_each_child_of_node(cfg_np, func_np) {
|
||||
for_each_child_of_node_scoped(cfg_np, func_np) {
|
||||
ret = samsung_pinctrl_create_function(dev, drvdata,
|
||||
func_np, func);
|
||||
if (ret < 0) {
|
||||
of_node_put(func_np);
|
||||
of_node_put(cfg_np);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
if (ret > 0) {
|
||||
++func;
|
||||
++func_cnt;
|
||||
@ -997,6 +988,77 @@ static int samsung_pinctrl_unregister(struct platform_device *pdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void samsung_pud_value_init(struct samsung_pinctrl_drv_data *drvdata)
|
||||
{
|
||||
unsigned int *pud_val = drvdata->pud_val;
|
||||
|
||||
pud_val[PUD_PULL_DISABLE] = EXYNOS_PIN_PUD_PULL_DISABLE;
|
||||
pud_val[PUD_PULL_DOWN] = EXYNOS_PIN_PID_PULL_DOWN;
|
||||
pud_val[PUD_PULL_UP] = EXYNOS_PIN_PID_PULL_UP;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable or Disable the pull-down and pull-up for the gpio pins in the
|
||||
* PUD register.
|
||||
*/
|
||||
static void samsung_gpio_set_pud(struct gpio_chip *gc, unsigned int offset,
|
||||
unsigned int value)
|
||||
{
|
||||
struct samsung_pin_bank *bank = gpiochip_get_data(gc);
|
||||
const struct samsung_pin_bank_type *type = bank->type;
|
||||
void __iomem *reg;
|
||||
unsigned int data, mask;
|
||||
|
||||
reg = bank->pctl_base + bank->pctl_offset;
|
||||
data = readl(reg + type->reg_offset[PINCFG_TYPE_PUD]);
|
||||
mask = (1 << type->fld_width[PINCFG_TYPE_PUD]) - 1;
|
||||
data &= ~(mask << (offset * type->fld_width[PINCFG_TYPE_PUD]));
|
||||
data |= value << (offset * type->fld_width[PINCFG_TYPE_PUD]);
|
||||
writel(data, reg + type->reg_offset[PINCFG_TYPE_PUD]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Identify the type of PUD config based on the gpiolib request to enable
|
||||
* or disable the PUD config.
|
||||
*/
|
||||
static int samsung_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
|
||||
unsigned long config)
|
||||
{
|
||||
struct samsung_pin_bank *bank = gpiochip_get_data(gc);
|
||||
struct samsung_pinctrl_drv_data *drvdata = bank->drvdata;
|
||||
unsigned int value;
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
switch (pinconf_to_config_param(config)) {
|
||||
case PIN_CONFIG_BIAS_DISABLE:
|
||||
value = drvdata->pud_val[PUD_PULL_DISABLE];
|
||||
break;
|
||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||
value = drvdata->pud_val[PUD_PULL_DOWN];
|
||||
break;
|
||||
case PIN_CONFIG_BIAS_PULL_UP:
|
||||
value = drvdata->pud_val[PUD_PULL_UP];
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
ret = clk_enable(drvdata->pclk);
|
||||
if (ret) {
|
||||
dev_err(drvdata->dev, "failed to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
raw_spin_lock_irqsave(&bank->slock, flags);
|
||||
samsung_gpio_set_pud(gc, offset, value);
|
||||
raw_spin_unlock_irqrestore(&bank->slock, flags);
|
||||
|
||||
clk_disable(drvdata->pclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct gpio_chip samsung_gpiolib_chip = {
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
@ -1006,6 +1068,7 @@ static const struct gpio_chip samsung_gpiolib_chip = {
|
||||
.direction_output = samsung_gpio_direction_output,
|
||||
.to_irq = samsung_gpio_to_irq,
|
||||
.add_pin_ranges = samsung_add_pin_ranges,
|
||||
.set_config = samsung_gpio_set_config,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
@ -1237,6 +1300,11 @@ static int samsung_pinctrl_probe(struct platform_device *pdev)
|
||||
if (ctrl->eint_wkup_init)
|
||||
ctrl->eint_wkup_init(drvdata);
|
||||
|
||||
if (ctrl->pud_value_init)
|
||||
ctrl->pud_value_init(drvdata);
|
||||
else
|
||||
samsung_pud_value_init(drvdata);
|
||||
|
||||
ret = samsung_gpiolib_register(pdev, drvdata);
|
||||
if (ret)
|
||||
goto err_unregister;
|
||||
|
@ -61,6 +61,25 @@ enum pincfg_type {
|
||||
#define PIN_CON_FUNC_INPUT 0x0
|
||||
#define PIN_CON_FUNC_OUTPUT 0x1
|
||||
|
||||
/* Values for the pin PUD register */
|
||||
#define EXYNOS_PIN_PUD_PULL_DISABLE 0x0
|
||||
#define EXYNOS_PIN_PID_PULL_DOWN 0x1
|
||||
#define EXYNOS_PIN_PID_PULL_UP 0x3
|
||||
|
||||
/*
|
||||
* enum pud_index - Possible index values to access the pud_val array.
|
||||
* @PUD_PULL_DISABLE: Index for the value of pud disable
|
||||
* @PUD_PULL_DOWN: Index for the value of pull down enable
|
||||
* @PUD_PULL_UP: Index for the value of pull up enable
|
||||
* @PUD_MAX: Maximum value of the index
|
||||
*/
|
||||
enum pud_index {
|
||||
PUD_PULL_DISABLE,
|
||||
PUD_PULL_DOWN,
|
||||
PUD_PULL_UP,
|
||||
PUD_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum eint_type - possible external interrupt types.
|
||||
* @EINT_TYPE_NONE: bank does not support external interrupts
|
||||
@ -261,6 +280,7 @@ struct samsung_pin_ctrl {
|
||||
|
||||
int (*eint_gpio_init)(struct samsung_pinctrl_drv_data *);
|
||||
int (*eint_wkup_init)(struct samsung_pinctrl_drv_data *);
|
||||
void (*pud_value_init)(struct samsung_pinctrl_drv_data *drvdata);
|
||||
void (*suspend)(struct samsung_pinctrl_drv_data *);
|
||||
void (*resume)(struct samsung_pinctrl_drv_data *);
|
||||
};
|
||||
@ -307,6 +327,7 @@ struct samsung_pinctrl_drv_data {
|
||||
struct samsung_pin_bank *pin_banks;
|
||||
unsigned int nr_banks;
|
||||
unsigned int nr_pins;
|
||||
unsigned int pud_val[PUD_MAX];
|
||||
|
||||
struct samsung_retention_ctrl *retention_ctrl;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user