summaryrefslogtreecommitdiff
path: root/drivers/pinctrl/samsung/pinctrl-exynos.c
diff options
context:
space:
mode:
authorMarek Szyprowski <m.szyprowski@samsung.com>2017-01-26 10:29:25 +0100
committerLinus Walleij <linus.walleij@linaro.org>2017-01-26 16:56:57 +0100
commit07731019c59c06e257aac351d774b2292c251dde (patch)
treef9690b493f3bb0fb217f0e630de974cb0c121276 /drivers/pinctrl/samsung/pinctrl-exynos.c
parent545e3e7da3d1356d3416faea2a8f94488c7a0056 (diff)
pinctrl: samsung: Move retention control from mach-exynos to the pinctrl driver
This patch moves pad retention control from PMU driver to Exynos pin controller driver. This helps to avoid possible ordering and logical dependencies between machine, PMU and pin control code. Till now it worked fine only because sys_ops for PMU and pin controller were called in registration order. This is also a preparation for adding new features to Exynos pin controller driver, like runtime power management and suspending individual pin controllers, which might be a part of some power domain. Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org> Acked-by: Tomasz Figa <tomasz.figa@gmail.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/samsung/pinctrl-exynos.c')
-rw-r--r--drivers/pinctrl/samsung/pinctrl-exynos.c145
1 files changed, 145 insertions, 0 deletions
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c
index 53baafdad51b..c81df3c843c3 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.c
@@ -28,7 +28,10 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/regmap.h>
#include <linux/err.h>
+#include <linux/soc/samsung/exynos-pmu.h>
+#include <linux/soc/samsung/exynos-regs-pmu.h>
#include "pinctrl-samsung.h"
#include "pinctrl-exynos.h"
@@ -679,6 +682,54 @@ const struct samsung_pin_ctrl s5pv210_pin_ctrl[] __initconst = {
},
};
+/* Pad retention control code for accessing PMU regmap */
+static atomic_t exynos_shared_retention_refcnt;
+
+static void exynos_retention_enable(struct samsung_pinctrl_drv_data *drvdata)
+{
+ if (drvdata->retention_ctrl->refcnt)
+ atomic_inc(drvdata->retention_ctrl->refcnt);
+}
+
+static void exynos_retention_disable(struct samsung_pinctrl_drv_data *drvdata)
+{
+ struct samsung_retention_ctrl *ctrl = drvdata->retention_ctrl;
+ struct regmap *pmu_regs = ctrl->priv;
+ int i;
+
+ if (ctrl->refcnt && !atomic_dec_and_test(ctrl->refcnt))
+ return;
+
+ for (i = 0; i < ctrl->nr_regs; i++)
+ regmap_write(pmu_regs, ctrl->regs[i], ctrl->value);
+}
+
+static struct samsung_retention_ctrl *
+exynos_retention_init(struct samsung_pinctrl_drv_data *drvdata,
+ const struct samsung_retention_data *data)
+{
+ struct samsung_retention_ctrl *ctrl;
+ struct regmap *pmu_regs;
+
+ ctrl = devm_kzalloc(drvdata->dev, sizeof(*ctrl), GFP_KERNEL);
+ if (!ctrl)
+ return ERR_PTR(-ENOMEM);
+
+ pmu_regs = exynos_get_pmu_regmap();
+ if (IS_ERR(pmu_regs))
+ return ERR_CAST(pmu_regs);
+
+ ctrl->priv = pmu_regs;
+ ctrl->regs = data->regs;
+ ctrl->nr_regs = data->nr_regs;
+ ctrl->value = data->value;
+ ctrl->refcnt = data->refcnt;
+ ctrl->enable = exynos_retention_enable;
+ ctrl->disable = exynos_retention_disable;
+
+ return ctrl;
+}
+
/* pin banks of exynos3250 pin-controller 0 */
static const struct samsung_pin_bank_data exynos3250_pin_banks0[] __initconst = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
@@ -711,6 +762,30 @@ static const struct samsung_pin_bank_data exynos3250_pin_banks1[] __initconst =
};
/*
+ * PMU pad retention groups for Exynos3250 doesn't match pin banks, so handle
+ * them all together
+ */
+static const u32 exynos3250_retention_regs[] = {
+ S5P_PAD_RET_MAUDIO_OPTION,
+ S5P_PAD_RET_GPIO_OPTION,
+ S5P_PAD_RET_UART_OPTION,
+ S5P_PAD_RET_MMCA_OPTION,
+ S5P_PAD_RET_MMCB_OPTION,
+ S5P_PAD_RET_EBIA_OPTION,
+ S5P_PAD_RET_EBIB_OPTION,
+ S5P_PAD_RET_MMC2_OPTION,
+ S5P_PAD_RET_SPI_OPTION,
+};
+
+static const struct samsung_retention_data exynos3250_retention_data __initconst = {
+ .regs = exynos3250_retention_regs,
+ .nr_regs = ARRAY_SIZE(exynos3250_retention_regs),
+ .value = EXYNOS_WAKEUP_FROM_LOWPWR,
+ .refcnt = &exynos_shared_retention_refcnt,
+ .init = exynos_retention_init,
+};
+
+/*
* Samsung pinctrl driver data for Exynos3250 SoC. Exynos3250 SoC includes
* two gpio/pin-mux/pinconfig controllers.
*/
@@ -722,6 +797,7 @@ const struct samsung_pin_ctrl exynos3250_pin_ctrl[] __initconst = {
.eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
+ .retention_data = &exynos3250_retention_data,
}, {
/* pin-controller instance 1 data */
.pin_banks = exynos3250_pin_banks1,
@@ -730,6 +806,7 @@ const struct samsung_pin_ctrl exynos3250_pin_ctrl[] __initconst = {
.eint_wkup_init = exynos_eint_wkup_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
+ .retention_data = &exynos3250_retention_data,
},
};
@@ -782,6 +859,36 @@ static const struct samsung_pin_bank_data exynos4210_pin_banks2[] __initconst =
EXYNOS_PIN_BANK_EINTN(7, 0x000, "gpz"),
};
+/* PMU pad retention groups registers for Exynos4 (without audio) */
+static const u32 exynos4_retention_regs[] = {
+ S5P_PAD_RET_GPIO_OPTION,
+ S5P_PAD_RET_UART_OPTION,
+ S5P_PAD_RET_MMCA_OPTION,
+ S5P_PAD_RET_MMCB_OPTION,
+ S5P_PAD_RET_EBIA_OPTION,
+ S5P_PAD_RET_EBIB_OPTION,
+};
+
+static const struct samsung_retention_data exynos4_retention_data __initconst = {
+ .regs = exynos4_retention_regs,
+ .nr_regs = ARRAY_SIZE(exynos4_retention_regs),
+ .value = EXYNOS_WAKEUP_FROM_LOWPWR,
+ .refcnt = &exynos_shared_retention_refcnt,
+ .init = exynos_retention_init,
+};
+
+/* PMU retention control for audio pins can be tied to audio pin bank */
+static const u32 exynos4_audio_retention_regs[] = {
+ S5P_PAD_RET_MAUDIO_OPTION,
+};
+
+static const struct samsung_retention_data exynos4_audio_retention_data __initconst = {
+ .regs = exynos4_audio_retention_regs,
+ .nr_regs = ARRAY_SIZE(exynos4_audio_retention_regs),
+ .value = EXYNOS_WAKEUP_FROM_LOWPWR,
+ .init = exynos_retention_init,
+};
+
/*
* Samsung pinctrl driver data for Exynos4210 SoC. Exynos4210 SoC includes
* three gpio/pin-mux/pinconfig controllers.
@@ -794,6 +901,7 @@ const struct samsung_pin_ctrl exynos4210_pin_ctrl[] __initconst = {
.eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
+ .retention_data = &exynos4_retention_data,
}, {
/* pin-controller instance 1 data */
.pin_banks = exynos4210_pin_banks1,
@@ -802,10 +910,12 @@ const struct samsung_pin_ctrl exynos4210_pin_ctrl[] __initconst = {
.eint_wkup_init = exynos_eint_wkup_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
+ .retention_data = &exynos4_retention_data,
}, {
/* pin-controller instance 2 data */
.pin_banks = exynos4210_pin_banks2,
.nr_banks = ARRAY_SIZE(exynos4210_pin_banks2),
+ .retention_data = &exynos4_audio_retention_data,
},
};
@@ -879,6 +989,7 @@ const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = {
.eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
+ .retention_data = &exynos4_retention_data,
}, {
/* pin-controller instance 1 data */
.pin_banks = exynos4x12_pin_banks1,
@@ -887,6 +998,7 @@ const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = {
.eint_wkup_init = exynos_eint_wkup_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
+ .retention_data = &exynos4_retention_data,
}, {
/* pin-controller instance 2 data */
.pin_banks = exynos4x12_pin_banks2,
@@ -894,6 +1006,7 @@ const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = {
.eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
+ .retention_data = &exynos4_audio_retention_data,
}, {
/* pin-controller instance 3 data */
.pin_banks = exynos4x12_pin_banks3,
@@ -973,6 +1086,7 @@ const struct samsung_pin_ctrl exynos5250_pin_ctrl[] __initconst = {
.eint_wkup_init = exynos_eint_wkup_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
+ .retention_data = &exynos4_retention_data,
}, {
/* pin-controller instance 1 data */
.pin_banks = exynos5250_pin_banks1,
@@ -980,6 +1094,7 @@ const struct samsung_pin_ctrl exynos5250_pin_ctrl[] __initconst = {
.eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
+ .retention_data = &exynos4_retention_data,
}, {
/* pin-controller instance 2 data */
.pin_banks = exynos5250_pin_banks2,
@@ -994,6 +1109,7 @@ const struct samsung_pin_ctrl exynos5250_pin_ctrl[] __initconst = {
.eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
+ .retention_data = &exynos4_audio_retention_data,
},
};
@@ -1220,6 +1336,30 @@ static const struct samsung_pin_bank_data exynos5420_pin_banks4[] __initconst =
EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
};
+/* PMU pad retention groups registers for Exynos5420 (without audio) */
+static const u32 exynos5420_retention_regs[] = {
+ EXYNOS_PAD_RET_DRAM_OPTION,
+ EXYNOS_PAD_RET_JTAG_OPTION,
+ EXYNOS5420_PAD_RET_GPIO_OPTION,
+ EXYNOS5420_PAD_RET_UART_OPTION,
+ EXYNOS5420_PAD_RET_MMCA_OPTION,
+ EXYNOS5420_PAD_RET_MMCB_OPTION,
+ EXYNOS5420_PAD_RET_MMCC_OPTION,
+ EXYNOS5420_PAD_RET_HSI_OPTION,
+ EXYNOS_PAD_RET_EBIA_OPTION,
+ EXYNOS_PAD_RET_EBIB_OPTION,
+ EXYNOS5420_PAD_RET_SPI_OPTION,
+ EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION,
+};
+
+static const struct samsung_retention_data exynos5420_retention_data __initconst = {
+ .regs = exynos5420_retention_regs,
+ .nr_regs = ARRAY_SIZE(exynos5420_retention_regs),
+ .value = EXYNOS_WAKEUP_FROM_LOWPWR,
+ .refcnt = &exynos_shared_retention_refcnt,
+ .init = exynos_retention_init,
+};
+
/*
* Samsung pinctrl driver data for Exynos5420 SoC. Exynos5420 SoC includes
* four gpio/pin-mux/pinconfig controllers.
@@ -1231,26 +1371,31 @@ 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,
+ .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,
+ .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,
+ .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,
+ .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,
+ .retention_data = &exynos4_audio_retention_data,
},
};