]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/pinctrl/samsung/pinctrl-exynos.c
Merge branches 'for-4.11/upstream-fixes', 'for-4.12/accutouch', 'for-4.12/cp2112...
[mirror_ubuntu-artful-kernel.git] / drivers / pinctrl / samsung / pinctrl-exynos.c
index c81df3c843c3f485a26bbc48c3de6d921d08d1f4..f9b49967f512b52cec5447ae0baee9e146745d1b 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/irqdomain.h>
 #include <linux/irq.h>
 #include <linux/irqchip/chained_irq.h>
+#include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/io.h>
 #include <linux/slab.h>
@@ -59,6 +60,17 @@ static const struct samsung_pin_bank_type bank_type_alive = {
        .reg_offset = { 0x00, 0x04, 0x08, 0x0c, },
 };
 
+/* Exynos5433 has the 4bit widths for PINCFG_TYPE_DRV bitfields. */
+static const struct samsung_pin_bank_type exynos5433_bank_type_off = {
+       .fld_width = { 4, 1, 2, 4, 2, 2, },
+       .reg_offset = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, },
+};
+
+static const struct samsung_pin_bank_type exynos5433_bank_type_alive = {
+       .fld_width = { 4, 1, 2, 4, },
+       .reg_offset = { 0x00, 0x04, 0x08, 0x0c, },
+};
+
 static void exynos_irq_mask(struct irq_data *irqd)
 {
        struct irq_chip *chip = irq_data_get_irq_chip(irqd);
@@ -632,6 +644,60 @@ static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
                        exynos_pinctrl_resume_bank(drvdata, bank);
 }
 
+/* Retention control for S5PV210 are located at the end of clock controller */
+#define S5P_OTHERS 0xE000
+
+#define S5P_OTHERS_RET_IO              (1 << 31)
+#define S5P_OTHERS_RET_CF              (1 << 30)
+#define S5P_OTHERS_RET_MMC             (1 << 29)
+#define S5P_OTHERS_RET_UART            (1 << 28)
+
+static void s5pv210_retention_disable(struct samsung_pinctrl_drv_data *drvdata)
+{
+       void *clk_base = drvdata->retention_ctrl->priv;
+       u32 tmp;
+
+       tmp = __raw_readl(clk_base + S5P_OTHERS);
+       tmp |= (S5P_OTHERS_RET_IO | S5P_OTHERS_RET_CF | S5P_OTHERS_RET_MMC |
+               S5P_OTHERS_RET_UART);
+       __raw_writel(tmp, clk_base + S5P_OTHERS);
+}
+
+static struct samsung_retention_ctrl *
+s5pv210_retention_init(struct samsung_pinctrl_drv_data *drvdata,
+                      const struct samsung_retention_data *data)
+{
+       struct samsung_retention_ctrl *ctrl;
+       struct device_node *np;
+       void *clk_base;
+
+       ctrl = devm_kzalloc(drvdata->dev, sizeof(*ctrl), GFP_KERNEL);
+       if (!ctrl)
+               return ERR_PTR(-ENOMEM);
+
+       np = of_find_compatible_node(NULL, NULL, "samsung,s5pv210-clock");
+       if (!np) {
+               pr_err("%s: failed to find clock controller DT node\n",
+                       __func__);
+               return ERR_PTR(-ENODEV);
+       }
+
+       clk_base = of_iomap(np, 0);
+       if (!clk_base) {
+               pr_err("%s: failed to map clock registers\n", __func__);
+               return ERR_PTR(-EINVAL);
+       }
+
+       ctrl->priv = clk_base;
+       ctrl->disable = s5pv210_retention_disable;
+
+       return ctrl;
+}
+
+static const struct samsung_retention_data s5pv210_retention_data __initconst = {
+       .init    = s5pv210_retention_init,
+};
+
 /* pin banks of s5pv210 pin-controller */
 static const struct samsung_pin_bank_data s5pv210_pin_bank[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
@@ -679,6 +745,7 @@ const struct samsung_pin_ctrl s5pv210_pin_ctrl[] __initconst = {
                .eint_wkup_init = exynos_eint_wkup_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
+               .retention_data = &s5pv210_retention_data,
        },
 };