aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/phy/samsung-phy.txt2
-rw-r--r--drivers/phy/phy-exynos-mipi-video.c89
-rw-r--r--include/linux/mfd/syscon/exynos4-pmu.h21
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
4Required properties: 4Required 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
9For "samsung,s5pv210-mipi-video-phy" compatible PHYs the second cell in 9For "samsung,s5pv210-mipi-video-phy" compatible PHYs the second cell in
10the PHY specifier identifies the PHY and its meaning is as follows: 10the 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
29enum exynos_mipi_phy_id { 28enum 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
40struct exynos_mipi_video_phy { 39struct 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
49static int __set_phy_state(struct exynos_mipi_video_phy *state, 50static 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_ */