1

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:
Linus Walleij 2024-08-30 09:30:25 +02:00
commit cd77b0dd6f
5 changed files with 141 additions and 32 deletions

View File

@ -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,

View File

@ -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;

View File

@ -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,
},
};

View File

@ -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;

View File

@ -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;