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

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
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -145,8 +145,13 @@ A. External GPIO Interrupts: For supporting external gpio interrupts, the

B. External Wakeup Interrupts: For supporting external wakeup interrupts, a
   child node representing the external wakeup interrupt controller should be
   included in the pin-controller device node. This child node should include
   the following properties.
   included in the pin-controller device node.

   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
     The possible values are:
@@ -156,6 +161,8 @@ B. External Wakeup Interrupts: For supporting external wakeup interrupts, a
       found on Samsung S3C2412 and S3C2413 SoCs,
     - samsung,s3c64xx-wakeup-eint: represents wakeup interrupt controller
       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
       found on Samsung Exynos4210 and S5PC110/S5PV210 SoCs.
     - samsung,exynos7-wakeup-eint: represents wakeup interrupt controller
+1 −1
Original line number Diff line number Diff line
@@ -272,7 +272,7 @@ static int exynos5420_cpu_suspend(unsigned long arg)
static void exynos_pm_set_wakeup_mask(void)
{
	/* 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);
}

+16 −0
Original line number Diff line number Diff line
@@ -616,16 +616,22 @@ static const struct samsung_pin_ctrl exynos5260_pin_ctrl[] __initconst = {
		.nr_banks	= ARRAY_SIZE(exynos5260_pin_banks0),
		.eint_gpio_init = exynos_eint_gpio_init,
		.eint_wkup_init = exynos_eint_wkup_init,
		.suspend	= exynos_pinctrl_suspend,
		.resume		= exynos_pinctrl_resume,
	}, {
		/* pin-controller instance 1 data */
		.pin_banks	= exynos5260_pin_banks1,
		.nr_banks	= ARRAY_SIZE(exynos5260_pin_banks1),
		.eint_gpio_init = exynos_eint_gpio_init,
		.suspend	= exynos_pinctrl_suspend,
		.resume		= exynos_pinctrl_resume,
	}, {
		/* pin-controller instance 2 data */
		.pin_banks	= exynos5260_pin_banks2,
		.nr_banks	= ARRAY_SIZE(exynos5260_pin_banks2),
		.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 = {
		.nr_banks	= ARRAY_SIZE(exynos5420_pin_banks0),
		.eint_gpio_init = exynos_eint_gpio_init,
		.eint_wkup_init = exynos_eint_wkup_init,
		.suspend	= exynos_pinctrl_suspend,
		.resume		= exynos_pinctrl_resume,
		.retention_data	= &exynos5420_retention_data,
	}, {
		/* pin-controller instance 1 data */
		.pin_banks	= exynos5420_pin_banks1,
		.nr_banks	= ARRAY_SIZE(exynos5420_pin_banks1),
		.eint_gpio_init = exynos_eint_gpio_init,
		.suspend	= exynos_pinctrl_suspend,
		.resume		= exynos_pinctrl_resume,
		.retention_data	= &exynos5420_retention_data,
	}, {
		/* pin-controller instance 2 data */
		.pin_banks	= exynos5420_pin_banks2,
		.nr_banks	= ARRAY_SIZE(exynos5420_pin_banks2),
		.eint_gpio_init = exynos_eint_gpio_init,
		.suspend	= exynos_pinctrl_suspend,
		.resume		= exynos_pinctrl_resume,
		.retention_data	= &exynos5420_retention_data,
	}, {
		/* pin-controller instance 3 data */
		.pin_banks	= exynos5420_pin_banks3,
		.nr_banks	= ARRAY_SIZE(exynos5420_pin_banks3),
		.eint_gpio_init = exynos_eint_gpio_init,
		.suspend	= exynos_pinctrl_suspend,
		.resume		= exynos_pinctrl_resume,
		.retention_data	= &exynos5420_retention_data,
	}, {
		/* pin-controller instance 4 data */
		.pin_banks	= exynos5420_pin_banks4,
		.nr_banks	= ARRAY_SIZE(exynos5420_pin_banks4),
		.eint_gpio_init = exynos_eint_gpio_init,
		.suspend	= exynos_pinctrl_suspend,
		.resume		= exynos_pinctrl_resume,
		.retention_data	= &exynos4_audio_retention_data,
	},
};
+67 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <linux/regmap.h>
#include <linux/err.h>
#include <linux/soc/samsung/exynos-pmu.h>
#include <linux/soc/samsung/exynos-regs-pmu.h>

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

@@ -37,6 +38,8 @@ struct exynos_irq_chip {
	u32 eint_con;
	u32 eint_mask;
	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)
@@ -215,6 +218,7 @@ static struct exynos_irq_chip exynos_gpio_irq_chip = {
	.eint_con = EXYNOS_GPIO_ECON_OFFSET,
	.eint_mask = EXYNOS_GPIO_EMASK_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,
@@ -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)
{
	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);
	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)
		exynos_eint_wake_mask |= bit;
	else
		exynos_eint_wake_mask &= ~bit;
	our_chip->eint_wake_mask_value = exynos_eint_wake_mask;

	return 0;
}
@@ -346,6 +353,25 @@ static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
/*
 * 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 = {
	.chip = {
		.name = "exynos4210_wkup_irq_chip",
@@ -360,6 +386,8 @@ static const struct exynos_irq_chip exynos4210_wkup_irq_chip __initconst = {
	.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,
	.eint_wake_mask_reg = EXYNOS_EINT_WAKEUP_MASK,
};

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_mask = EXYNOS7_WKUP_EMASK_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 */
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",
			.data = &exynos4210_wkup_irq_chip },
	{ .compatible = "samsung,exynos7-wakeup-eint",
@@ -542,6 +574,27 @@ int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
	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(
				struct samsung_pinctrl_drv_data *drvdata,
				struct samsung_pin_bank *bank)
@@ -564,11 +617,24 @@ static void exynos_pinctrl_suspend_bank(
void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
{
	struct samsung_pin_bank *bank = drvdata->pin_banks;
	struct exynos_irq_chip *irq_chip = NULL;
	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)
			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(
+11 −0
Original line number Diff line number Diff line
@@ -223,6 +223,13 @@ struct samsung_retention_data {
 *	interrupts for the controller.
 * @eint_wkup_init: platform specific callback to setup the external wakeup
 *	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 {
	const struct samsung_pin_bank_data *pin_banks;
@@ -255,6 +262,10 @@ struct samsung_pin_ctrl {
 * @pin_base: starting system wide pin number.
 * @nr_pins: number of pins supported by the controller.
 * @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 list_head		node;
Loading