diff options
-rw-r--r-- | Documentation/devicetree/bindings/phy/samsung-phy.txt | 2 | ||||
-rw-r--r-- | drivers/phy/phy-exynos-mipi-video.c | 89 | ||||
-rw-r--r-- | include/linux/mfd/syscon/exynos4-pmu.h | 21 |
3 files changed, 79 insertions, 33 deletions
diff --git a/Documentation/devicetree/bindings/phy/samsung-phy.txt b/Documentation/devicetree/bindings/phy/samsung-phy.txt index d5bad920827f..91e38cfe1f8f 100644 --- a/Documentation/devicetree/bindings/phy/samsung-phy.txt +++ b/Documentation/devicetree/bindings/phy/samsung-phy.txt | |||
@@ -3,8 +3,8 @@ Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY | |||
3 | 3 | ||
4 | Required properties: | 4 | Required properties: |
5 | - compatible : should be "samsung,s5pv210-mipi-video-phy"; | 5 | - compatible : should be "samsung,s5pv210-mipi-video-phy"; |
6 | - reg : offset and length of the MIPI DPHY register set; | ||
7 | - #phy-cells : from the generic phy bindings, must be 1; | 6 | - #phy-cells : from the generic phy bindings, must be 1; |
7 | - syscon - phandle to the PMU system controller; | ||
8 | 8 | ||
9 | For "samsung,s5pv210-mipi-video-phy" compatible PHYs the second cell in | 9 | For "samsung,s5pv210-mipi-video-phy" compatible PHYs the second cell in |
10 | the PHY specifier identifies the PHY and its meaning is as follows: | 10 | the PHY specifier identifies the PHY and its meaning is as follows: |
diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c index 943e0f88a120..f017b2f2a54e 100644 --- a/drivers/phy/phy-exynos-mipi-video.c +++ b/drivers/phy/phy-exynos-mipi-video.c | |||
@@ -12,19 +12,18 @@ | |||
12 | #include <linux/err.h> | 12 | #include <linux/err.h> |
13 | #include <linux/io.h> | 13 | #include <linux/io.h> |
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/mfd/syscon/exynos4-pmu.h> | ||
15 | #include <linux/module.h> | 16 | #include <linux/module.h> |
16 | #include <linux/of.h> | 17 | #include <linux/of.h> |
17 | #include <linux/of_address.h> | 18 | #include <linux/of_address.h> |
18 | #include <linux/phy/phy.h> | 19 | #include <linux/phy/phy.h> |
19 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/regmap.h> | ||
20 | #include <linux/spinlock.h> | 22 | #include <linux/spinlock.h> |
23 | #include <linux/mfd/syscon.h> | ||
21 | 24 | ||
22 | /* MIPI_PHYn_CONTROL register offset: n = 0..1 */ | 25 | /* MIPI_PHYn_CONTROL reg. offset (for base address from ioremap): n = 0..1 */ |
23 | #define EXYNOS_MIPI_PHY_CONTROL(n) ((n) * 4) | 26 | #define EXYNOS_MIPI_PHY_CONTROL(n) ((n) * 4) |
24 | #define EXYNOS_MIPI_PHY_ENABLE (1 << 0) | ||
25 | #define EXYNOS_MIPI_PHY_SRESETN (1 << 1) | ||
26 | #define EXYNOS_MIPI_PHY_MRESETN (1 << 2) | ||
27 | #define EXYNOS_MIPI_PHY_RESET_MASK (3 << 1) | ||
28 | 27 | ||
29 | enum exynos_mipi_phy_id { | 28 | enum exynos_mipi_phy_id { |
30 | EXYNOS_MIPI_PHY_ID_CSIS0, | 29 | EXYNOS_MIPI_PHY_ID_CSIS0, |
@@ -38,43 +37,62 @@ enum exynos_mipi_phy_id { | |||
38 | ((id) == EXYNOS_MIPI_PHY_ID_DSIM0 || (id) == EXYNOS_MIPI_PHY_ID_DSIM1) | 37 | ((id) == EXYNOS_MIPI_PHY_ID_DSIM0 || (id) == EXYNOS_MIPI_PHY_ID_DSIM1) |
39 | 38 | ||
40 | struct exynos_mipi_video_phy { | 39 | struct exynos_mipi_video_phy { |
41 | spinlock_t slock; | ||
42 | struct video_phy_desc { | 40 | struct video_phy_desc { |
43 | struct phy *phy; | 41 | struct phy *phy; |
44 | unsigned int index; | 42 | unsigned int index; |
45 | } phys[EXYNOS_MIPI_PHYS_NUM]; | 43 | } phys[EXYNOS_MIPI_PHYS_NUM]; |
44 | spinlock_t slock; | ||
46 | void __iomem *regs; | 45 | void __iomem *regs; |
46 | struct mutex mutex; | ||
47 | struct regmap *regmap; | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | static int __set_phy_state(struct exynos_mipi_video_phy *state, | 50 | static int __set_phy_state(struct exynos_mipi_video_phy *state, |
50 | enum exynos_mipi_phy_id id, unsigned int on) | 51 | enum exynos_mipi_phy_id id, unsigned int on) |
51 | { | 52 | { |
53 | const unsigned int offset = EXYNOS4_MIPI_PHY_CONTROL(id / 2); | ||
52 | void __iomem *addr; | 54 | void __iomem *addr; |
53 | u32 reg, reset; | 55 | u32 val, reset; |
54 | |||
55 | addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2); | ||
56 | 56 | ||
57 | if (is_mipi_dsim_phy_id(id)) | 57 | if (is_mipi_dsim_phy_id(id)) |
58 | reset = EXYNOS_MIPI_PHY_MRESETN; | 58 | reset = EXYNOS4_MIPI_PHY_MRESETN; |
59 | else | ||
60 | reset = EXYNOS_MIPI_PHY_SRESETN; | ||
61 | |||
62 | spin_lock(&state->slock); | ||
63 | reg = readl(addr); | ||
64 | if (on) | ||
65 | reg |= reset; | ||
66 | else | 59 | else |
67 | reg &= ~reset; | 60 | reset = EXYNOS4_MIPI_PHY_SRESETN; |
68 | writel(reg, addr); | 61 | |
69 | 62 | if (state->regmap) { | |
70 | /* Clear ENABLE bit only if MRESETN, SRESETN bits are not set. */ | 63 | mutex_lock(&state->mutex); |
71 | if (on) | 64 | regmap_read(state->regmap, offset, &val); |
72 | reg |= EXYNOS_MIPI_PHY_ENABLE; | 65 | if (on) |
73 | else if (!(reg & EXYNOS_MIPI_PHY_RESET_MASK)) | 66 | val |= reset; |
74 | reg &= ~EXYNOS_MIPI_PHY_ENABLE; | 67 | else |
68 | val &= ~reset; | ||
69 | regmap_write(state->regmap, offset, val); | ||
70 | if (on) | ||
71 | val |= EXYNOS4_MIPI_PHY_ENABLE; | ||
72 | else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK)) | ||
73 | val &= ~EXYNOS4_MIPI_PHY_ENABLE; | ||
74 | regmap_write(state->regmap, offset, val); | ||
75 | mutex_unlock(&state->mutex); | ||
76 | } else { | ||
77 | addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2); | ||
78 | |||
79 | spin_lock(&state->slock); | ||
80 | val = readl(addr); | ||
81 | if (on) | ||
82 | val |= reset; | ||
83 | else | ||
84 | val &= ~reset; | ||
85 | writel(val, addr); | ||
86 | /* Clear ENABLE bit only if MRESETN, SRESETN bits are not set */ | ||
87 | if (on) | ||
88 | val |= EXYNOS4_MIPI_PHY_ENABLE; | ||
89 | else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK)) | ||
90 | val &= ~EXYNOS4_MIPI_PHY_ENABLE; | ||
91 | |||
92 | writel(val, addr); | ||
93 | spin_unlock(&state->slock); | ||
94 | } | ||
75 | 95 | ||
76 | writel(reg, addr); | ||
77 | spin_unlock(&state->slock); | ||
78 | return 0; | 96 | return 0; |
79 | } | 97 | } |
80 | 98 | ||
@@ -118,7 +136,6 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) | |||
118 | { | 136 | { |
119 | struct exynos_mipi_video_phy *state; | 137 | struct exynos_mipi_video_phy *state; |
120 | struct device *dev = &pdev->dev; | 138 | struct device *dev = &pdev->dev; |
121 | struct resource *res; | ||
122 | struct phy_provider *phy_provider; | 139 | struct phy_provider *phy_provider; |
123 | unsigned int i; | 140 | unsigned int i; |
124 | 141 | ||
@@ -126,14 +143,22 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) | |||
126 | if (!state) | 143 | if (!state) |
127 | return -ENOMEM; | 144 | return -ENOMEM; |
128 | 145 | ||
129 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 146 | state->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); |
147 | if (IS_ERR(state->regmap)) { | ||
148 | struct resource *res; | ||
130 | 149 | ||
131 | state->regs = devm_ioremap_resource(dev, res); | 150 | dev_info(dev, "regmap lookup failed: %ld\n", |
132 | if (IS_ERR(state->regs)) | 151 | PTR_ERR(state->regmap)); |
133 | return PTR_ERR(state->regs); | 152 | |
153 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
154 | state->regs = devm_ioremap_resource(dev, res); | ||
155 | if (IS_ERR(state->regs)) | ||
156 | return PTR_ERR(state->regs); | ||
157 | } | ||
134 | 158 | ||
135 | dev_set_drvdata(dev, state); | 159 | dev_set_drvdata(dev, state); |
136 | spin_lock_init(&state->slock); | 160 | spin_lock_init(&state->slock); |
161 | mutex_init(&state->mutex); | ||
137 | 162 | ||
138 | for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) { | 163 | for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) { |
139 | struct phy *phy = devm_phy_create(dev, NULL, | 164 | struct phy *phy = devm_phy_create(dev, NULL, |
diff --git a/include/linux/mfd/syscon/exynos4-pmu.h b/include/linux/mfd/syscon/exynos4-pmu.h new file mode 100644 index 000000000000..278b1b1549e9 --- /dev/null +++ b/include/linux/mfd/syscon/exynos4-pmu.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Samsung Electronics Co., Ltd. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef _LINUX_MFD_SYSCON_PMU_EXYNOS4_H_ | ||
10 | #define _LINUX_MFD_SYSCON_PMU_EXYNOS4_H_ | ||
11 | |||
12 | /* Exynos4 PMU register definitions */ | ||
13 | |||
14 | /* MIPI_PHYn_CONTROL register offset: n = 0..1 */ | ||
15 | #define EXYNOS4_MIPI_PHY_CONTROL(n) (0x710 + (n) * 4) | ||
16 | #define EXYNOS4_MIPI_PHY_ENABLE (1 << 0) | ||
17 | #define EXYNOS4_MIPI_PHY_SRESETN (1 << 1) | ||
18 | #define EXYNOS4_MIPI_PHY_MRESETN (1 << 2) | ||
19 | #define EXYNOS4_MIPI_PHY_RESET_MASK (3 << 1) | ||
20 | |||
21 | #endif /* _LINUX_MFD_SYSCON_PMU_EXYNOS4_H_ */ | ||