Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 496d5819 authored by Linus Walleij's avatar Linus Walleij
Browse files

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

Merge tag 'samsung-pinctrl-4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung into devel

Samsung pinctrl driver changes for v4.14:
1. Fix NULL pointer dereference on S3C24XX.  This was reported some time ago and
   unfortunately it took few releases to fix.
2. Fix invalid register offset used for external interrupts on Exynos5433.
   This was caused by the same commit as above, although on different path.
3. Consolidate between drivers and bindings the defines for pin mux functions.
4. Minor code improvements.
parents 06351d13 bbed85f4
Loading
Loading
Loading
Loading
+12 −20
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@
#include <linux/err.h>
#include <linux/soc/samsung/exynos-pmu.h>

#include <dt-bindings/pinctrl/samsung.h>

#include "pinctrl-samsung.h"
#include "pinctrl-exynos.h"

@@ -149,15 +151,10 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type)

static int exynos_irq_request_resources(struct irq_data *irqd)
{
	struct irq_chip *chip = irq_data_get_irq_chip(irqd);
	struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
	struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
	const struct samsung_pin_bank_type *bank_type = bank->type;
	unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq;
	unsigned long reg_con = our_chip->eint_con + bank->eint_offset;
	unsigned long flags;
	unsigned int mask;
	unsigned int con;
	unsigned long reg_con, flags;
	unsigned int shift, mask, con;
	int ret;

	ret = gpiochip_lock_as_irq(&bank->gpio_chip, irqd->hwirq);
@@ -174,10 +171,10 @@ static int exynos_irq_request_resources(struct irq_data *irqd)

	spin_lock_irqsave(&bank->slock, flags);

	con = readl(bank->eint_base + reg_con);
	con = readl(bank->pctl_base + reg_con);
	con &= ~(mask << shift);
	con |= EXYNOS_EINT_FUNC << shift;
	writel(con, bank->eint_base + reg_con);
	con |= EXYNOS_PIN_FUNC_EINT << shift;
	writel(con, bank->pctl_base + reg_con);

	spin_unlock_irqrestore(&bank->slock, flags);

@@ -186,15 +183,10 @@ static int exynos_irq_request_resources(struct irq_data *irqd)

static void exynos_irq_release_resources(struct irq_data *irqd)
{
	struct irq_chip *chip = irq_data_get_irq_chip(irqd);
	struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
	struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
	const struct samsung_pin_bank_type *bank_type = bank->type;
	unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq;
	unsigned long reg_con = our_chip->eint_con + bank->eint_offset;
	unsigned long flags;
	unsigned int mask;
	unsigned int con;
	unsigned long reg_con, flags;
	unsigned int shift, mask, con;

	reg_con = bank->pctl_offset + bank_type->reg_offset[PINCFG_TYPE_FUNC];
	shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC];
@@ -202,10 +194,10 @@ static void exynos_irq_release_resources(struct irq_data *irqd)

	spin_lock_irqsave(&bank->slock, flags);

	con = readl(bank->eint_base + reg_con);
	con = readl(bank->pctl_base + reg_con);
	con &= ~(mask << shift);
	con |= FUNC_INPUT << shift;
	writel(con, bank->eint_base + reg_con);
	con |= EXYNOS_PIN_FUNC_INPUT << shift;
	writel(con, bank->pctl_base + reg_con);

	spin_unlock_irqrestore(&bank->slock, flags);

+0 −1
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@
#define EXYNOS7_WKUP_EMASK_OFFSET	0x900
#define EXYNOS7_WKUP_EPEND_OFFSET	0xA00
#define EXYNOS_SVC_OFFSET		0xB08
#define EXYNOS_EINT_FUNC		0xF

/* helpers to access interrupt service register */
#define EXYNOS_SVC_GROUP_SHIFT		3
+21 −16
Original line number Diff line number Diff line
@@ -151,7 +151,7 @@ static void s3c24xx_eint_set_function(struct samsung_pinctrl_drv_data *d,
	u32 val;

	/* Make sure that pin is configured as interrupt */
	reg = bank->pctl_base + bank->pctl_offset;
	reg = d->virt_base + bank->pctl_offset;
	shift = pin * bank_type->fld_width[PINCFG_TYPE_FUNC];
	mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;

@@ -184,7 +184,7 @@ static int s3c24xx_eint_type(struct irq_data *data, unsigned int type)
	s3c24xx_eint_set_handler(data, type);

	/* Set up interrupt trigger */
	reg = bank->eint_base + EINT_REG(index);
	reg = d->virt_base + EINT_REG(index);
	shift = EINT_OFFS(index);

	val = readl(reg);
@@ -259,29 +259,32 @@ static void s3c2410_demux_eint0_3(struct irq_desc *desc)
static void s3c2412_eint0_3_ack(struct irq_data *data)
{
	struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
	struct samsung_pinctrl_drv_data *d = bank->drvdata;

	unsigned long bitval = 1UL << data->hwirq;
	writel(bitval, bank->eint_base + EINTPEND_REG);
	writel(bitval, d->virt_base + EINTPEND_REG);
}

static void s3c2412_eint0_3_mask(struct irq_data *data)
{
	struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
	struct samsung_pinctrl_drv_data *d = bank->drvdata;
	unsigned long mask;

	mask = readl(bank->eint_base + EINTMASK_REG);
	mask = readl(d->virt_base + EINTMASK_REG);
	mask |= (1UL << data->hwirq);
	writel(mask, bank->eint_base + EINTMASK_REG);
	writel(mask, d->virt_base + EINTMASK_REG);
}

static void s3c2412_eint0_3_unmask(struct irq_data *data)
{
	struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
	struct samsung_pinctrl_drv_data *d = bank->drvdata;
	unsigned long mask;

	mask = readl(bank->eint_base + EINTMASK_REG);
	mask = readl(d->virt_base + EINTMASK_REG);
	mask &= ~(1UL << data->hwirq);
	writel(mask, bank->eint_base + EINTMASK_REG);
	writel(mask, d->virt_base + EINTMASK_REG);
}

static struct irq_chip s3c2412_eint0_3_chip = {
@@ -316,31 +319,34 @@ static void s3c2412_demux_eint0_3(struct irq_desc *desc)
static void s3c24xx_eint_ack(struct irq_data *data)
{
	struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
	struct samsung_pinctrl_drv_data *d = bank->drvdata;
	unsigned char index = bank->eint_offset + data->hwirq;

	writel(1UL << index, bank->eint_base + EINTPEND_REG);
	writel(1UL << index, d->virt_base + EINTPEND_REG);
}

static void s3c24xx_eint_mask(struct irq_data *data)
{
	struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
	struct samsung_pinctrl_drv_data *d = bank->drvdata;
	unsigned char index = bank->eint_offset + data->hwirq;
	unsigned long mask;

	mask = readl(bank->eint_base + EINTMASK_REG);
	mask = readl(d->virt_base + EINTMASK_REG);
	mask |= (1UL << index);
	writel(mask, bank->eint_base + EINTMASK_REG);
	writel(mask, d->virt_base + EINTMASK_REG);
}

static void s3c24xx_eint_unmask(struct irq_data *data)
{
	struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
	struct samsung_pinctrl_drv_data *d = bank->drvdata;
	unsigned char index = bank->eint_offset + data->hwirq;
	unsigned long mask;

	mask = readl(bank->eint_base + EINTMASK_REG);
	mask = readl(d->virt_base + EINTMASK_REG);
	mask &= ~(1UL << index);
	writel(mask, bank->eint_base + EINTMASK_REG);
	writel(mask, d->virt_base + EINTMASK_REG);
}

static struct irq_chip s3c24xx_eint_chip = {
@@ -356,14 +362,13 @@ static inline void s3c24xx_demux_eint(struct irq_desc *desc,
{
	struct s3c24xx_eint_data *data = irq_desc_get_handler_data(desc);
	struct irq_chip *chip = irq_desc_get_chip(desc);
	struct irq_data *irqd = irq_desc_get_irq_data(desc);
	struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
	struct samsung_pinctrl_drv_data *d = data->drvdata;
	unsigned int pend, mask;

	chained_irq_enter(chip, desc);

	pend = readl(bank->eint_base + EINTPEND_REG);
	mask = readl(bank->eint_base + EINTMASK_REG);
	pend = readl(d->virt_base + EINTPEND_REG);
	mask = readl(d->virt_base + EINTMASK_REG);

	pend &= ~mask;
	pend &= range;
+18 −22
Original line number Diff line number Diff line
@@ -280,7 +280,7 @@ static void s3c64xx_irq_set_function(struct samsung_pinctrl_drv_data *d,
	u32 val;

	/* Make sure that pin is configured as interrupt */
	reg = bank->pctl_base + bank->pctl_offset;
	reg = d->virt_base + bank->pctl_offset;
	shift = pin;
	if (bank_type->fld_width[PINCFG_TYPE_FUNC] * shift >= 32) {
		/* 4-bit bank type with 2 con regs */
@@ -308,8 +308,9 @@ static void s3c64xx_irq_set_function(struct samsung_pinctrl_drv_data *d,
static inline void s3c64xx_gpio_irq_set_mask(struct irq_data *irqd, bool mask)
{
	struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
	struct samsung_pinctrl_drv_data *d = bank->drvdata;
	unsigned char index = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
	void __iomem *reg = bank->eint_base + EINTMASK_REG(bank->eint_offset);
	void __iomem *reg = d->virt_base + EINTMASK_REG(bank->eint_offset);
	u32 val;

	val = readl(reg);
@@ -333,8 +334,9 @@ static void s3c64xx_gpio_irq_mask(struct irq_data *irqd)
static void s3c64xx_gpio_irq_ack(struct irq_data *irqd)
{
	struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
	struct samsung_pinctrl_drv_data *d = bank->drvdata;
	unsigned char index = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
	void __iomem *reg = bank->eint_base + EINTPEND_REG(bank->eint_offset);
	void __iomem *reg = d->virt_base + EINTPEND_REG(bank->eint_offset);

	writel(1 << index, reg);
}
@@ -357,7 +359,7 @@ static int s3c64xx_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
	s3c64xx_irq_set_handler(irqd, type);

	/* Set up interrupt trigger */
	reg = bank->eint_base + EINTCON_REG(bank->eint_offset);
	reg = d->virt_base + EINTCON_REG(bank->eint_offset);
	shift = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
	shift = 4 * (shift / 4); /* 4 EINTs per trigger selector */

@@ -409,8 +411,7 @@ static void s3c64xx_eint_gpio_irq(struct irq_desc *desc)
{
	struct irq_chip *chip = irq_desc_get_chip(desc);
	struct s3c64xx_eint_gpio_data *data = irq_desc_get_handler_data(desc);
	struct irq_data *irqd = irq_desc_get_irq_data(desc);
	struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
	struct samsung_pinctrl_drv_data *drvdata = data->drvdata;

	chained_irq_enter(chip, desc);

@@ -420,7 +421,7 @@ static void s3c64xx_eint_gpio_irq(struct irq_desc *desc)
		unsigned int pin;
		unsigned int virq;

		svc = readl(bank->eint_base + SERVICE_REG);
		svc = readl(drvdata->virt_base + SERVICE_REG);
		group = SVC_GROUP(svc);
		pin = svc & SVC_NUM_MASK;

@@ -515,15 +516,15 @@ static inline void s3c64xx_eint0_irq_set_mask(struct irq_data *irqd, bool mask)
{
	struct s3c64xx_eint0_domain_data *ddata =
					irq_data_get_irq_chip_data(irqd);
	struct samsung_pin_bank *bank = ddata->bank;
	struct samsung_pinctrl_drv_data *d = ddata->bank->drvdata;
	u32 val;

	val = readl(bank->eint_base + EINT0MASK_REG);
	val = readl(d->virt_base + EINT0MASK_REG);
	if (mask)
		val |= 1 << ddata->eints[irqd->hwirq];
	else
		val &= ~(1 << ddata->eints[irqd->hwirq]);
	writel(val, bank->eint_base + EINT0MASK_REG);
	writel(val, d->virt_base + EINT0MASK_REG);
}

static void s3c64xx_eint0_irq_unmask(struct irq_data *irqd)
@@ -540,10 +541,10 @@ static void s3c64xx_eint0_irq_ack(struct irq_data *irqd)
{
	struct s3c64xx_eint0_domain_data *ddata =
					irq_data_get_irq_chip_data(irqd);
	struct samsung_pin_bank *bank = ddata->bank;
	struct samsung_pinctrl_drv_data *d = ddata->bank->drvdata;

	writel(1 << ddata->eints[irqd->hwirq],
					bank->eint_base + EINT0PEND_REG);
					d->virt_base + EINT0PEND_REG);
}

static int s3c64xx_eint0_irq_set_type(struct irq_data *irqd, unsigned int type)
@@ -551,7 +552,7 @@ static int s3c64xx_eint0_irq_set_type(struct irq_data *irqd, unsigned int type)
	struct s3c64xx_eint0_domain_data *ddata =
					irq_data_get_irq_chip_data(irqd);
	struct samsung_pin_bank *bank = ddata->bank;
	struct samsung_pinctrl_drv_data *d = ddata->bank->drvdata;
	struct samsung_pinctrl_drv_data *d = bank->drvdata;
	void __iomem *reg;
	int trigger;
	u8 shift;
@@ -566,7 +567,7 @@ static int s3c64xx_eint0_irq_set_type(struct irq_data *irqd, unsigned int type)
	s3c64xx_irq_set_handler(irqd, type);

	/* Set up interrupt trigger */
	reg = bank->eint_base + EINT0CON0_REG;
	reg = d->virt_base + EINT0CON0_REG;
	shift = ddata->eints[irqd->hwirq];
	if (shift >= EINT_MAX_PER_REG) {
		reg += 4;
@@ -598,19 +599,14 @@ static struct irq_chip s3c64xx_eint0_irq_chip = {
static inline void s3c64xx_irq_demux_eint(struct irq_desc *desc, u32 range)
{
	struct irq_chip *chip = irq_desc_get_chip(desc);
	struct irq_data *irqd = irq_desc_get_irq_data(desc);
	struct s3c64xx_eint0_domain_data *ddata =
					irq_data_get_irq_chip_data(irqd);
	struct samsung_pin_bank *bank = ddata->bank;

	struct s3c64xx_eint0_data *data = irq_desc_get_handler_data(desc);

	struct samsung_pinctrl_drv_data *drvdata = data->drvdata;
	unsigned int pend, mask;

	chained_irq_enter(chip, desc);

	pend = readl(bank->eint_base + EINT0PEND_REG);
	mask = readl(bank->eint_base + EINT0MASK_REG);
	pend = readl(drvdata->virt_base + EINT0PEND_REG);
	mask = readl(drvdata->virt_base + EINT0MASK_REG);

	pend = pend & range & ~mask;
	pend &= range;
+10 −2
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@
#include <linux/of_device.h>
#include <linux/spinlock.h>

#include <dt-bindings/pinctrl/samsung.h>

#include "../core.h"
#include "pinctrl-samsung.h"

@@ -586,7 +588,7 @@ static int samsung_gpio_set_direction(struct gpio_chip *gc,
	data = readl(reg);
	data &= ~(mask << shift);
	if (!input)
		data |= FUNC_OUTPUT << shift;
		data |= EXYNOS_PIN_FUNC_OUTPUT << shift;
	writel(data, reg);

	return 0;
@@ -958,7 +960,7 @@ samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d,
	struct samsung_pin_bank *bank;
	struct resource *res;
	void __iomem *virt_base[SAMSUNG_PINCTRL_NUM_RESOURCES];
	int i;
	unsigned int i;

	id = of_alias_get_id(node, "pinctrl");
	if (id < 0) {
@@ -1013,6 +1015,12 @@ samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d,
		bank->eint_base = virt_base[0];
		bank->pctl_base = virt_base[bdata->pctl_res_idx];
	}
	/*
	 * Legacy platforms should provide only one resource with IO memory.
	 * Store it as virt_base because legacy driver needs to access it
	 * through samsung_pinctrl_drv_data.
	 */
	d->virt_base = virt_base[0];

	for_each_child_of_node(node, np) {
		if (!of_find_property(np, "gpio-controller", NULL))
Loading