Commit cd77b0dd authored by Linus Walleij's avatar Linus Walleij
Browse files

Merge tag 'samsung-pinctrl-6.12' of...

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: default avatarLinus Walleij <linus.walleij@linaro.org>
parents 9b82ec85 39dbbd4e
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -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,
+4 −12
Original line number Diff line number Diff line
@@ -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;
+14 −0
Original line number Diff line number Diff line
@@ -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,
	},
};

+88 −20
Original line number Diff line number Diff line
@@ -122,7 +122,7 @@ 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),
	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;
+21 −0
Original line number Diff line number Diff line
@@ -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;