Commit 8c17dee1 authored by Linus Walleij's avatar Linus Walleij

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

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

Samsung pinctrl drivers changes for v4.19

1. Add handling of external wakeup interrupts mask inside the pin
   controller driver.

   Existing solution is spread between the driver and machine code.  The
   machine code writes the mask but its value is taken from pin
   controller driver.

   This moves everything into pin controller driver allowing later to
   remove the cross-subsystem interaction.  Also this is a necessary
   step for implementing later Suspend to RAM on ARMv8 Exynos5433.

2. Bring necessary suspend/resume callbacks for Exynos542x and
   Exynos5260.

3. Document hidden requirement about one external wakeup interrupts
   device node.

4. Minor documentation cleanups.
parents 238262af b3793159
...@@ -145,8 +145,13 @@ A. External GPIO Interrupts: For supporting external gpio interrupts, the ...@@ -145,8 +145,13 @@ A. External GPIO Interrupts: For supporting external gpio interrupts, the
B. External Wakeup Interrupts: For supporting external wakeup interrupts, a B. External Wakeup Interrupts: For supporting external wakeup interrupts, a
child node representing the external wakeup interrupt controller should be child node representing the external wakeup interrupt controller should be
included in the pin-controller device node. This child node should include included in the pin-controller device node.
the following properties.
Only one pin-controller device node can include external wakeup interrupts
child node (in other words, only one External Wakeup Interrupts
pin-controller is supported).
This child node should include following properties:
- compatible: identifies the type of the external wakeup interrupt controller - compatible: identifies the type of the external wakeup interrupt controller
The possible values are: The possible values are:
...@@ -156,6 +161,8 @@ B. External Wakeup Interrupts: For supporting external wakeup interrupts, a ...@@ -156,6 +161,8 @@ B. External Wakeup Interrupts: For supporting external wakeup interrupts, a
found on Samsung S3C2412 and S3C2413 SoCs, found on Samsung S3C2412 and S3C2413 SoCs,
- samsung,s3c64xx-wakeup-eint: represents wakeup interrupt controller - samsung,s3c64xx-wakeup-eint: represents wakeup interrupt controller
found on Samsung S3C64xx SoCs, found on Samsung S3C64xx SoCs,
- samsung,s5pv210-wakeup-eint: represents wakeup interrupt controller
found on Samsung S5Pv210 SoCs,
- samsung,exynos4210-wakeup-eint: represents wakeup interrupt controller - samsung,exynos4210-wakeup-eint: represents wakeup interrupt controller
found on Samsung Exynos4210 and S5PC110/S5PV210 SoCs. found on Samsung Exynos4210 and S5PC110/S5PV210 SoCs.
- samsung,exynos7-wakeup-eint: represents wakeup interrupt controller - samsung,exynos7-wakeup-eint: represents wakeup interrupt controller
......
...@@ -272,7 +272,7 @@ static int exynos5420_cpu_suspend(unsigned long arg) ...@@ -272,7 +272,7 @@ static int exynos5420_cpu_suspend(unsigned long arg)
static void exynos_pm_set_wakeup_mask(void) static void exynos_pm_set_wakeup_mask(void)
{ {
/* Set wake-up mask registers */ /* Set wake-up mask registers */
pmu_raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK); pmu_raw_writel(exynos_get_eint_wake_mask(), EXYNOS_EINT_WAKEUP_MASK);
pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK); pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK);
} }
......
...@@ -616,16 +616,22 @@ static const struct samsung_pin_ctrl exynos5260_pin_ctrl[] __initconst = { ...@@ -616,16 +616,22 @@ static const struct samsung_pin_ctrl exynos5260_pin_ctrl[] __initconst = {
.nr_banks = ARRAY_SIZE(exynos5260_pin_banks0), .nr_banks = ARRAY_SIZE(exynos5260_pin_banks0),
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.eint_wkup_init = exynos_eint_wkup_init, .eint_wkup_init = exynos_eint_wkup_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
}, { }, {
/* pin-controller instance 1 data */ /* pin-controller instance 1 data */
.pin_banks = exynos5260_pin_banks1, .pin_banks = exynos5260_pin_banks1,
.nr_banks = ARRAY_SIZE(exynos5260_pin_banks1), .nr_banks = ARRAY_SIZE(exynos5260_pin_banks1),
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
}, { }, {
/* pin-controller instance 2 data */ /* pin-controller instance 2 data */
.pin_banks = exynos5260_pin_banks2, .pin_banks = exynos5260_pin_banks2,
.nr_banks = ARRAY_SIZE(exynos5260_pin_banks2), .nr_banks = ARRAY_SIZE(exynos5260_pin_banks2),
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
}, },
}; };
...@@ -842,30 +848,40 @@ static const struct samsung_pin_ctrl exynos5420_pin_ctrl[] __initconst = { ...@@ -842,30 +848,40 @@ static const struct samsung_pin_ctrl exynos5420_pin_ctrl[] __initconst = {
.nr_banks = ARRAY_SIZE(exynos5420_pin_banks0), .nr_banks = ARRAY_SIZE(exynos5420_pin_banks0),
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.eint_wkup_init = exynos_eint_wkup_init, .eint_wkup_init = exynos_eint_wkup_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
.retention_data = &exynos5420_retention_data, .retention_data = &exynos5420_retention_data,
}, { }, {
/* pin-controller instance 1 data */ /* pin-controller instance 1 data */
.pin_banks = exynos5420_pin_banks1, .pin_banks = exynos5420_pin_banks1,
.nr_banks = ARRAY_SIZE(exynos5420_pin_banks1), .nr_banks = ARRAY_SIZE(exynos5420_pin_banks1),
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
.retention_data = &exynos5420_retention_data, .retention_data = &exynos5420_retention_data,
}, { }, {
/* pin-controller instance 2 data */ /* pin-controller instance 2 data */
.pin_banks = exynos5420_pin_banks2, .pin_banks = exynos5420_pin_banks2,
.nr_banks = ARRAY_SIZE(exynos5420_pin_banks2), .nr_banks = ARRAY_SIZE(exynos5420_pin_banks2),
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
.retention_data = &exynos5420_retention_data, .retention_data = &exynos5420_retention_data,
}, { }, {
/* pin-controller instance 3 data */ /* pin-controller instance 3 data */
.pin_banks = exynos5420_pin_banks3, .pin_banks = exynos5420_pin_banks3,
.nr_banks = ARRAY_SIZE(exynos5420_pin_banks3), .nr_banks = ARRAY_SIZE(exynos5420_pin_banks3),
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
.retention_data = &exynos5420_retention_data, .retention_data = &exynos5420_retention_data,
}, { }, {
/* pin-controller instance 4 data */ /* pin-controller instance 4 data */
.pin_banks = exynos5420_pin_banks4, .pin_banks = exynos5420_pin_banks4,
.nr_banks = ARRAY_SIZE(exynos5420_pin_banks4), .nr_banks = ARRAY_SIZE(exynos5420_pin_banks4),
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
.retention_data = &exynos4_audio_retention_data, .retention_data = &exynos4_audio_retention_data,
}, },
}; };
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/soc/samsung/exynos-pmu.h> #include <linux/soc/samsung/exynos-pmu.h>
#include <linux/soc/samsung/exynos-regs-pmu.h>
#include <dt-bindings/pinctrl/samsung.h> #include <dt-bindings/pinctrl/samsung.h>
...@@ -37,6 +38,8 @@ struct exynos_irq_chip { ...@@ -37,6 +38,8 @@ struct exynos_irq_chip {
u32 eint_con; u32 eint_con;
u32 eint_mask; u32 eint_mask;
u32 eint_pend; u32 eint_pend;
u32 eint_wake_mask_value;
u32 eint_wake_mask_reg;
}; };
static inline struct exynos_irq_chip *to_exynos_irq_chip(struct irq_chip *chip) static inline struct exynos_irq_chip *to_exynos_irq_chip(struct irq_chip *chip)
...@@ -215,6 +218,7 @@ static struct exynos_irq_chip exynos_gpio_irq_chip = { ...@@ -215,6 +218,7 @@ static struct exynos_irq_chip exynos_gpio_irq_chip = {
.eint_con = EXYNOS_GPIO_ECON_OFFSET, .eint_con = EXYNOS_GPIO_ECON_OFFSET,
.eint_mask = EXYNOS_GPIO_EMASK_OFFSET, .eint_mask = EXYNOS_GPIO_EMASK_OFFSET,
.eint_pend = EXYNOS_GPIO_EPEND_OFFSET, .eint_pend = EXYNOS_GPIO_EPEND_OFFSET,
/* eint_wake_mask_value not used */
}; };
static int exynos_eint_irq_map(struct irq_domain *h, unsigned int virq, static int exynos_eint_irq_map(struct irq_domain *h, unsigned int virq,
...@@ -330,6 +334,8 @@ u32 exynos_get_eint_wake_mask(void) ...@@ -330,6 +334,8 @@ u32 exynos_get_eint_wake_mask(void)
static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on) static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
{ {
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); struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
unsigned long bit = 1UL << (2 * bank->eint_offset + irqd->hwirq); unsigned long bit = 1UL << (2 * bank->eint_offset + irqd->hwirq);
...@@ -339,6 +345,7 @@ static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on) ...@@ -339,6 +345,7 @@ static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
exynos_eint_wake_mask |= bit; exynos_eint_wake_mask |= bit;
else else
exynos_eint_wake_mask &= ~bit; exynos_eint_wake_mask &= ~bit;
our_chip->eint_wake_mask_value = exynos_eint_wake_mask;
return 0; return 0;
} }
...@@ -346,6 +353,25 @@ static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on) ...@@ -346,6 +353,25 @@ static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
/* /*
* irq_chip for wakeup interrupts * irq_chip for wakeup interrupts
*/ */
static const struct exynos_irq_chip s5pv210_wkup_irq_chip __initconst = {
.chip = {
.name = "s5pv210_wkup_irq_chip",
.irq_unmask = exynos_irq_unmask,
.irq_mask = exynos_irq_mask,
.irq_ack = exynos_irq_ack,
.irq_set_type = exynos_irq_set_type,
.irq_set_wake = exynos_wkup_irq_set_wake,
.irq_request_resources = exynos_irq_request_resources,
.irq_release_resources = exynos_irq_release_resources,
},
.eint_con = EXYNOS_WKUP_ECON_OFFSET,
.eint_mask = EXYNOS_WKUP_EMASK_OFFSET,
.eint_pend = EXYNOS_WKUP_EPEND_OFFSET,
.eint_wake_mask_value = EXYNOS_EINT_WAKEUP_MASK_DISABLED,
/* Only difference with exynos4210_wkup_irq_chip: */
.eint_wake_mask_reg = S5PV210_EINT_WAKEUP_MASK,
};
static const struct exynos_irq_chip exynos4210_wkup_irq_chip __initconst = { static const struct exynos_irq_chip exynos4210_wkup_irq_chip __initconst = {
.chip = { .chip = {
.name = "exynos4210_wkup_irq_chip", .name = "exynos4210_wkup_irq_chip",
...@@ -360,6 +386,8 @@ static const struct exynos_irq_chip exynos4210_wkup_irq_chip __initconst = { ...@@ -360,6 +386,8 @@ static const struct exynos_irq_chip exynos4210_wkup_irq_chip __initconst = {
.eint_con = EXYNOS_WKUP_ECON_OFFSET, .eint_con = EXYNOS_WKUP_ECON_OFFSET,
.eint_mask = EXYNOS_WKUP_EMASK_OFFSET, .eint_mask = EXYNOS_WKUP_EMASK_OFFSET,
.eint_pend = EXYNOS_WKUP_EPEND_OFFSET, .eint_pend = EXYNOS_WKUP_EPEND_OFFSET,
.eint_wake_mask_value = EXYNOS_EINT_WAKEUP_MASK_DISABLED,
.eint_wake_mask_reg = EXYNOS_EINT_WAKEUP_MASK,
}; };
static const struct exynos_irq_chip exynos7_wkup_irq_chip __initconst = { static const struct exynos_irq_chip exynos7_wkup_irq_chip __initconst = {
...@@ -376,10 +404,14 @@ static const struct exynos_irq_chip exynos7_wkup_irq_chip __initconst = { ...@@ -376,10 +404,14 @@ static const struct exynos_irq_chip exynos7_wkup_irq_chip __initconst = {
.eint_con = EXYNOS7_WKUP_ECON_OFFSET, .eint_con = EXYNOS7_WKUP_ECON_OFFSET,
.eint_mask = EXYNOS7_WKUP_EMASK_OFFSET, .eint_mask = EXYNOS7_WKUP_EMASK_OFFSET,
.eint_pend = EXYNOS7_WKUP_EPEND_OFFSET, .eint_pend = EXYNOS7_WKUP_EPEND_OFFSET,
.eint_wake_mask_value = EXYNOS_EINT_WAKEUP_MASK_DISABLED,
.eint_wake_mask_reg = EXYNOS5433_EINT_WAKEUP_MASK,
}; };
/* list of external wakeup controllers supported */ /* list of external wakeup controllers supported */
static const struct of_device_id exynos_wkup_irq_ids[] = { static const struct of_device_id exynos_wkup_irq_ids[] = {
{ .compatible = "samsung,s5pv210-wakeup-eint",
.data = &s5pv210_wkup_irq_chip },
{ .compatible = "samsung,exynos4210-wakeup-eint", { .compatible = "samsung,exynos4210-wakeup-eint",
.data = &exynos4210_wkup_irq_chip }, .data = &exynos4210_wkup_irq_chip },
{ .compatible = "samsung,exynos7-wakeup-eint", { .compatible = "samsung,exynos7-wakeup-eint",
...@@ -542,6 +574,27 @@ int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) ...@@ -542,6 +574,27 @@ int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
return 0; return 0;
} }
static void
exynos_pinctrl_set_eint_wakeup_mask(struct samsung_pinctrl_drv_data *drvdata,
struct exynos_irq_chip *irq_chip)
{
struct regmap *pmu_regs;
if (!drvdata->retention_ctrl || !drvdata->retention_ctrl->priv) {
dev_warn(drvdata->dev,
"No retention data configured bank with external wakeup interrupt. Wake-up mask will not be set.\n");
return;
}
pmu_regs = drvdata->retention_ctrl->priv;
dev_info(drvdata->dev,
"Setting external wakeup interrupt wakeup mask: 0x%x\n",
irq_chip->eint_wake_mask_value);
regmap_write(pmu_regs, irq_chip->eint_wake_mask_reg,
irq_chip->eint_wake_mask_value);
}
static void exynos_pinctrl_suspend_bank( static void exynos_pinctrl_suspend_bank(
struct samsung_pinctrl_drv_data *drvdata, struct samsung_pinctrl_drv_data *drvdata,
struct samsung_pin_bank *bank) struct samsung_pin_bank *bank)
...@@ -564,11 +617,24 @@ static void exynos_pinctrl_suspend_bank( ...@@ -564,11 +617,24 @@ static void exynos_pinctrl_suspend_bank(
void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata) void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
{ {
struct samsung_pin_bank *bank = drvdata->pin_banks; struct samsung_pin_bank *bank = drvdata->pin_banks;
struct exynos_irq_chip *irq_chip = NULL;
int i; int i;
for (i = 0; i < drvdata->nr_banks; ++i, ++bank) for (i = 0; i < drvdata->nr_banks; ++i, ++bank) {
if (bank->eint_type == EINT_TYPE_GPIO) if (bank->eint_type == EINT_TYPE_GPIO)
exynos_pinctrl_suspend_bank(drvdata, bank); exynos_pinctrl_suspend_bank(drvdata, bank);
else if (bank->eint_type == EINT_TYPE_WKUP) {
if (!irq_chip) {
irq_chip = bank->irq_chip;
exynos_pinctrl_set_eint_wakeup_mask(drvdata,
irq_chip);
} else if (bank->irq_chip != irq_chip) {
dev_warn(drvdata->dev,
"More than one external wakeup interrupt chip configured (bank: %s). This is not supported by hardware nor by driver.\n",
bank->name);
}
}
}
} }
static void exynos_pinctrl_resume_bank( static void exynos_pinctrl_resume_bank(
......
...@@ -223,6 +223,13 @@ struct samsung_retention_data { ...@@ -223,6 +223,13 @@ struct samsung_retention_data {
* interrupts for the controller. * interrupts for the controller.
* @eint_wkup_init: platform specific callback to setup the external wakeup * @eint_wkup_init: platform specific callback to setup the external wakeup
* interrupts for the controller. * interrupts for the controller.
* @suspend: platform specific suspend callback, executed during pin controller
* device suspend, see samsung_pinctrl_suspend()
* @resume: platform specific resume callback, executed during pin controller
* device suspend, see samsung_pinctrl_resume()
*
* External wakeup interrupts must define at least eint_wkup_init,
* retention_data and suspend in order for proper suspend/resume to work.
*/ */
struct samsung_pin_ctrl { struct samsung_pin_ctrl {
const struct samsung_pin_bank_data *pin_banks; const struct samsung_pin_bank_data *pin_banks;
...@@ -255,6 +262,10 @@ struct samsung_pin_ctrl { ...@@ -255,6 +262,10 @@ struct samsung_pin_ctrl {
* @pin_base: starting system wide pin number. * @pin_base: starting system wide pin number.
* @nr_pins: number of pins supported by the controller. * @nr_pins: number of pins supported by the controller.
* @retention_ctrl: retention control runtime data. * @retention_ctrl: retention control runtime data.
* @suspend: platform specific suspend callback, executed during pin controller
* device suspend, see samsung_pinctrl_suspend()
* @resume: platform specific resume callback, executed during pin controller
* device suspend, see samsung_pinctrl_resume()
*/ */
struct samsung_pinctrl_drv_data { struct samsung_pinctrl_drv_data {
struct list_head node; struct list_head node;
......
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* Samsung's Exynos pinctrl bindings * Samsung's Exynos pinctrl bindings
* *
* Copyright (c) 2016 Samsung Electronics Co., Ltd. * Copyright (c) 2016 Samsung Electronics Co., Ltd.
* http://www.samsung.com * http://www.samsung.com
* Author: Krzysztof Kozlowski <krzk@kernel.org> * Author: Krzysztof Kozlowski <krzk@kernel.org>
* */
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __DT_BINDINGS_PINCTRL_SAMSUNG_H__ #ifndef __DT_BINDINGS_PINCTRL_SAMSUNG_H__
#define __DT_BINDINGS_PINCTRL_SAMSUNG_H__ #define __DT_BINDINGS_PINCTRL_SAMSUNG_H__
......
...@@ -42,7 +42,9 @@ ...@@ -42,7 +42,9 @@
#define EXYNOS_SWRESET 0x0400 #define EXYNOS_SWRESET 0x0400
#define S5P_WAKEUP_STAT 0x0600 #define S5P_WAKEUP_STAT 0x0600
#define S5P_EINT_WAKEUP_MASK 0x0604 /* Value for EXYNOS_EINT_WAKEUP_MASK disabling all external wakeup interrupts */
#define EXYNOS_EINT_WAKEUP_MASK_DISABLED 0xffffffff
#define EXYNOS_EINT_WAKEUP_MASK 0x0604
#define S5P_WAKEUP_MASK 0x0608 #define S5P_WAKEUP_MASK 0x0608
#define S5P_WAKEUP_MASK2 0x0614 #define S5P_WAKEUP_MASK2 0x0614
...@@ -180,6 +182,9 @@ ...@@ -180,6 +182,9 @@
#define S5P_CORE_WAKEUP_FROM_LOCAL_CFG (0x3 << 8) #define S5P_CORE_WAKEUP_FROM_LOCAL_CFG (0x3 << 8)
#define S5P_CORE_AUTOWAKEUP_EN (1 << 31) #define S5P_CORE_AUTOWAKEUP_EN (1 << 31)
/* Only for S5Pv210 */
#define S5PV210_EINT_WAKEUP_MASK 0xC004
/* Only for EXYNOS4210 */ /* Only for EXYNOS4210 */
#define S5P_CMU_CLKSTOP_LCD1_LOWPWR 0x1154 #define S5P_CMU_CLKSTOP_LCD1_LOWPWR 0x1154
#define S5P_CMU_RESET_LCD1_LOWPWR 0x1174 #define S5P_CMU_RESET_LCD1_LOWPWR 0x1174
...@@ -641,6 +646,7 @@ ...@@ -641,6 +646,7 @@
| EXYNOS5420_KFC_USE_STANDBY_WFI3) | EXYNOS5420_KFC_USE_STANDBY_WFI3)
/* For EXYNOS5433 */ /* For EXYNOS5433 */
#define EXYNOS5433_EINT_WAKEUP_MASK (0x060C)
#define EXYNOS5433_USBHOST30_PHY_CONTROL (0x0728) #define EXYNOS5433_USBHOST30_PHY_CONTROL (0x0728)
#define EXYNOS5433_PAD_RETENTION_AUD_OPTION (0x3028) #define EXYNOS5433_PAD_RETENTION_AUD_OPTION (0x3028)
#define EXYNOS5433_PAD_RETENTION_MMC2_OPTION (0x30C8) #define EXYNOS5433_PAD_RETENTION_MMC2_OPTION (0x30C8)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment