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.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJZjUS7AAoJEME3ZuaGi4PXzkAQAJF2hRXIUDxnZ0Y+Ms7JQwRq
 aLqWkqQoAZzu8zUd5z42o86rGiUQ/ZLR3YEWOqNuvNaLdj//GxFBKsamOqsrYiWc
 6qqgjLN5KFHT6Hnvc6nYk7Z/cPlMCjhlisvDT1PEH5HQX2HwK4RRByyylUNA+qe1
 hhDz0yKq0HQKUOJfH9mEs7JqHqlpoh3HymqcnM13HxhvduMxMjJdp3UHug6iNyXG
 tForolMQEGTH4G6A4bXrhsN5EPSNvOy4ya8W0rrP/r4A/k3D2mjzxHmfUNYyJmzO
 +oId+l9nmCKKmmIs/CXNUfohSpJ60Dn+DIyJm8JIs783jfvE2qPi7CA9UwAz8ENV
 g9ZLyOxwxsIiWAmUrzYc5pockGlk+hYazvqT+Ib08s+jUOhjJ8eZ4oW5ZDNQOe7f
 ovheW+qvSsbuXJLy0gL7LZbukBO2B13zJJLgZqiBF5qtMr0OQ8OuzO1Na5QnN3kA
 qRtHShbdIc24ego2IB5lBSyTdbgS3DdRprQPr/pCV1f6sBVyKYAsVkmvZ/sWBD1U
 NV1kAtsgubvknMOqm1SUux0P1o9QuqAd/o/lXuceu65K2ZFgcKJyMdo/bHZzd3uz
 A9Gu8tgIYjCMl2rlOrnc0IWPfONQsU4cfyYFg2c9y3MVfYUBA0b7gHtwhN1XJijU
 hTqM8E+UvViN5UIN8wAs
 =eAr5
 -----END PGP SIGNATURE-----

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.
This commit is contained in:
Linus Walleij 2017-08-14 16:55:01 +02:00
commit 496d5819ff
7 changed files with 71 additions and 69 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -25,10 +25,6 @@
#include <linux/gpio.h>
/* pinmux function number for pin as gpio output line */
#define FUNC_INPUT 0x0
#define FUNC_OUTPUT 0x1
/**
* enum pincfg_type - possible pin configuration types supported.
* @PINCFG_TYPE_FUNC: Function configuration.
@ -234,8 +230,8 @@ struct samsung_retention_data {
*/
struct samsung_pin_ctrl {
const struct samsung_pin_bank_data *pin_banks;
u32 nr_banks;
int nr_ext_resources;
unsigned int nr_banks;
unsigned int nr_ext_resources;
const struct samsung_retention_data *retention_data;
int (*eint_gpio_init)(struct samsung_pinctrl_drv_data *);
@ -247,6 +243,10 @@ struct samsung_pin_ctrl {
/**
* struct samsung_pinctrl_drv_data: wrapper for holding driver data together.
* @node: global list node
* @virt_base: register base address of the controller; this will be equal
* to each bank samsung_pin_bank->pctl_base and used on legacy
* platforms (like S3C24XX or S3C64XX) which has to access the base
* through samsung_pinctrl_drv_data, not samsung_pin_bank).
* @dev: device instance representing the controller.
* @irq: interrpt number used by the controller to notify gpio interrupts.
* @ctrl: pin controller instance managed by the driver.
@ -262,6 +262,7 @@ struct samsung_pin_ctrl {
*/
struct samsung_pinctrl_drv_data {
struct list_head node;
void __iomem *virt_base;
struct device *dev;
int irq;
@ -274,7 +275,7 @@ struct samsung_pinctrl_drv_data {
unsigned int nr_functions;
struct samsung_pin_bank *pin_banks;
u32 nr_banks;
unsigned int nr_banks;
unsigned int pin_base;
unsigned int nr_pins;

View File

@ -66,7 +66,8 @@
#define EXYNOS_PIN_FUNC_4 4
#define EXYNOS_PIN_FUNC_5 5
#define EXYNOS_PIN_FUNC_6 6
#define EXYNOS_PIN_FUNC_F 0xf
#define EXYNOS_PIN_FUNC_EINT 0xf
#define EXYNOS_PIN_FUNC_F EXYNOS_PIN_FUNC_EINT
/* Drive strengths for Exynos7 FSYS1 block */
#define EXYNOS7_FSYS1_PIN_DRV_LV1 0