diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-sun6i-p2wi.c')
-rw-r--r-- | drivers/i2c/busses/i2c-sun6i-p2wi.c | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-sun6i-p2wi.c b/drivers/i2c/busses/i2c-sun6i-p2wi.c new file mode 100644 index 000000000000..09de4fd12d57 --- /dev/null +++ b/drivers/i2c/busses/i2c-sun6i-p2wi.c | |||
@@ -0,0 +1,345 @@ | |||
1 | /* | ||
2 | * P2WI (Push-Pull Two Wire Interface) bus driver. | ||
3 | * | ||
4 | * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> | ||
5 | * | ||
6 | * This file is licensed under the terms of the GNU General Public License | ||
7 | * version 2. This program is licensed "as is" without any warranty of any | ||
8 | * kind, whether express or implied. | ||
9 | * | ||
10 | * The P2WI controller looks like an SMBus controller which only supports byte | ||
11 | * data transfers. But, it differs from standard SMBus protocol on several | ||
12 | * aspects: | ||
13 | * - it supports only one slave device, and thus drop the address field | ||
14 | * - it adds a parity bit every 8bits of data | ||
15 | * - only one read access is required to read a byte (instead of a write | ||
16 | * followed by a read access in standard SMBus protocol) | ||
17 | * - there's no Ack bit after each byte transfer | ||
18 | * | ||
19 | * This means this bus cannot be used to interface with standard SMBus | ||
20 | * devices (the only known device to support this interface is the AXP221 | ||
21 | * PMIC). | ||
22 | * | ||
23 | */ | ||
24 | #include <linux/clk.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/of.h> | ||
31 | #include <linux/platform_device.h> | ||
32 | #include <linux/reset.h> | ||
33 | |||
34 | |||
35 | /* P2WI registers */ | ||
36 | #define P2WI_CTRL 0x0 | ||
37 | #define P2WI_CCR 0x4 | ||
38 | #define P2WI_INTE 0x8 | ||
39 | #define P2WI_INTS 0xc | ||
40 | #define P2WI_DADDR0 0x10 | ||
41 | #define P2WI_DADDR1 0x14 | ||
42 | #define P2WI_DLEN 0x18 | ||
43 | #define P2WI_DATA0 0x1c | ||
44 | #define P2WI_DATA1 0x20 | ||
45 | #define P2WI_LCR 0x24 | ||
46 | #define P2WI_PMCR 0x28 | ||
47 | |||
48 | /* CTRL fields */ | ||
49 | #define P2WI_CTRL_START_TRANS BIT(7) | ||
50 | #define P2WI_CTRL_ABORT_TRANS BIT(6) | ||
51 | #define P2WI_CTRL_GLOBAL_INT_ENB BIT(1) | ||
52 | #define P2WI_CTRL_SOFT_RST BIT(0) | ||
53 | |||
54 | /* CLK CTRL fields */ | ||
55 | #define P2WI_CCR_SDA_OUT_DELAY(v) (((v) & 0x7) << 8) | ||
56 | #define P2WI_CCR_MAX_CLK_DIV 0xff | ||
57 | #define P2WI_CCR_CLK_DIV(v) ((v) & P2WI_CCR_MAX_CLK_DIV) | ||
58 | |||
59 | /* STATUS fields */ | ||
60 | #define P2WI_INTS_TRANS_ERR_ID(v) (((v) >> 8) & 0xff) | ||
61 | #define P2WI_INTS_LOAD_BSY BIT(2) | ||
62 | #define P2WI_INTS_TRANS_ERR BIT(1) | ||
63 | #define P2WI_INTS_TRANS_OVER BIT(0) | ||
64 | |||
65 | /* DATA LENGTH fields*/ | ||
66 | #define P2WI_DLEN_READ BIT(4) | ||
67 | #define P2WI_DLEN_DATA_LENGTH(v) ((v - 1) & 0x7) | ||
68 | |||
69 | /* LINE CTRL fields*/ | ||
70 | #define P2WI_LCR_SCL_STATE BIT(5) | ||
71 | #define P2WI_LCR_SDA_STATE BIT(4) | ||
72 | #define P2WI_LCR_SCL_CTL BIT(3) | ||
73 | #define P2WI_LCR_SCL_CTL_EN BIT(2) | ||
74 | #define P2WI_LCR_SDA_CTL BIT(1) | ||
75 | #define P2WI_LCR_SDA_CTL_EN BIT(0) | ||
76 | |||
77 | /* PMU MODE CTRL fields */ | ||
78 | #define P2WI_PMCR_PMU_INIT_SEND BIT(31) | ||
79 | #define P2WI_PMCR_PMU_INIT_DATA(v) (((v) & 0xff) << 16) | ||
80 | #define P2WI_PMCR_PMU_MODE_REG(v) (((v) & 0xff) << 8) | ||
81 | #define P2WI_PMCR_PMU_DEV_ADDR(v) ((v) & 0xff) | ||
82 | |||
83 | #define P2WI_MAX_FREQ 6000000 | ||
84 | |||
85 | struct p2wi { | ||
86 | struct i2c_adapter adapter; | ||
87 | struct completion complete; | ||
88 | unsigned int status; | ||
89 | void __iomem *regs; | ||
90 | struct clk *clk; | ||
91 | struct reset_control *rstc; | ||
92 | int slave_addr; | ||
93 | }; | ||
94 | |||
95 | static irqreturn_t p2wi_interrupt(int irq, void *dev_id) | ||
96 | { | ||
97 | struct p2wi *p2wi = dev_id; | ||
98 | unsigned long status; | ||
99 | |||
100 | status = readl(p2wi->regs + P2WI_INTS); | ||
101 | p2wi->status = status; | ||
102 | |||
103 | /* Clear interrupts */ | ||
104 | status &= (P2WI_INTS_LOAD_BSY | P2WI_INTS_TRANS_ERR | | ||
105 | P2WI_INTS_TRANS_OVER); | ||
106 | writel(status, p2wi->regs + P2WI_INTS); | ||
107 | |||
108 | complete(&p2wi->complete); | ||
109 | |||
110 | return IRQ_HANDLED; | ||
111 | } | ||
112 | |||
113 | static u32 p2wi_functionality(struct i2c_adapter *adap) | ||
114 | { | ||
115 | return I2C_FUNC_SMBUS_BYTE_DATA; | ||
116 | } | ||
117 | |||
118 | static int p2wi_smbus_xfer(struct i2c_adapter *adap, u16 addr, | ||
119 | unsigned short flags, char read_write, | ||
120 | u8 command, int size, union i2c_smbus_data *data) | ||
121 | { | ||
122 | struct p2wi *p2wi = i2c_get_adapdata(adap); | ||
123 | unsigned long dlen = P2WI_DLEN_DATA_LENGTH(1); | ||
124 | |||
125 | if (p2wi->slave_addr >= 0 && addr != p2wi->slave_addr) { | ||
126 | dev_err(&adap->dev, "invalid P2WI address\n"); | ||
127 | return -EINVAL; | ||
128 | } | ||
129 | |||
130 | if (!data) | ||
131 | return -EINVAL; | ||
132 | |||
133 | writel(command, p2wi->regs + P2WI_DADDR0); | ||
134 | |||
135 | if (read_write == I2C_SMBUS_READ) | ||
136 | dlen |= P2WI_DLEN_READ; | ||
137 | else | ||
138 | writel(data->byte, p2wi->regs + P2WI_DATA0); | ||
139 | |||
140 | writel(dlen, p2wi->regs + P2WI_DLEN); | ||
141 | |||
142 | if (readl(p2wi->regs + P2WI_CTRL) & P2WI_CTRL_START_TRANS) { | ||
143 | dev_err(&adap->dev, "P2WI bus busy\n"); | ||
144 | return -EBUSY; | ||
145 | } | ||
146 | |||
147 | reinit_completion(&p2wi->complete); | ||
148 | |||
149 | writel(P2WI_INTS_LOAD_BSY | P2WI_INTS_TRANS_ERR | P2WI_INTS_TRANS_OVER, | ||
150 | p2wi->regs + P2WI_INTE); | ||
151 | |||
152 | writel(P2WI_CTRL_START_TRANS | P2WI_CTRL_GLOBAL_INT_ENB, | ||
153 | p2wi->regs + P2WI_CTRL); | ||
154 | |||
155 | wait_for_completion(&p2wi->complete); | ||
156 | |||
157 | if (p2wi->status & P2WI_INTS_LOAD_BSY) { | ||
158 | dev_err(&adap->dev, "P2WI bus busy\n"); | ||
159 | return -EBUSY; | ||
160 | } | ||
161 | |||
162 | if (p2wi->status & P2WI_INTS_TRANS_ERR) { | ||
163 | dev_err(&adap->dev, "P2WI bus xfer error\n"); | ||
164 | return -ENXIO; | ||
165 | } | ||
166 | |||
167 | if (read_write == I2C_SMBUS_READ) | ||
168 | data->byte = readl(p2wi->regs + P2WI_DATA0); | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static const struct i2c_algorithm p2wi_algo = { | ||
174 | .smbus_xfer = p2wi_smbus_xfer, | ||
175 | .functionality = p2wi_functionality, | ||
176 | }; | ||
177 | |||
178 | static const struct of_device_id p2wi_of_match_table[] = { | ||
179 | { .compatible = "allwinner,sun6i-a31-p2wi" }, | ||
180 | {} | ||
181 | }; | ||
182 | MODULE_DEVICE_TABLE(of, p2wi_of_match_table); | ||
183 | |||
184 | static int p2wi_probe(struct platform_device *pdev) | ||
185 | { | ||
186 | struct device *dev = &pdev->dev; | ||
187 | struct device_node *np = dev->of_node; | ||
188 | struct device_node *childnp; | ||
189 | unsigned long parent_clk_freq; | ||
190 | u32 clk_freq = 100000; | ||
191 | struct resource *r; | ||
192 | struct p2wi *p2wi; | ||
193 | u32 slave_addr; | ||
194 | int clk_div; | ||
195 | int irq; | ||
196 | int ret; | ||
197 | |||
198 | of_property_read_u32(np, "clock-frequency", &clk_freq); | ||
199 | if (clk_freq > P2WI_MAX_FREQ) { | ||
200 | dev_err(dev, | ||
201 | "required clock-frequency (%u Hz) is too high (max = 6MHz)", | ||
202 | clk_freq); | ||
203 | return -EINVAL; | ||
204 | } | ||
205 | |||
206 | if (of_get_child_count(np) > 1) { | ||
207 | dev_err(dev, "P2WI only supports one slave device\n"); | ||
208 | return -EINVAL; | ||
209 | } | ||
210 | |||
211 | p2wi = devm_kzalloc(dev, sizeof(struct p2wi), GFP_KERNEL); | ||
212 | if (!p2wi) | ||
213 | return -ENOMEM; | ||
214 | |||
215 | p2wi->slave_addr = -1; | ||
216 | |||
217 | /* | ||
218 | * Authorize a p2wi node without any children to be able to use an | ||
219 | * i2c-dev from userpace. | ||
220 | * In this case the slave_addr is set to -1 and won't be checked when | ||
221 | * launching a P2WI transfer. | ||
222 | */ | ||
223 | childnp = of_get_next_available_child(np, NULL); | ||
224 | if (childnp) { | ||
225 | ret = of_property_read_u32(childnp, "reg", &slave_addr); | ||
226 | if (ret) { | ||
227 | dev_err(dev, "invalid slave address on node %s\n", | ||
228 | childnp->full_name); | ||
229 | return -EINVAL; | ||
230 | } | ||
231 | |||
232 | p2wi->slave_addr = slave_addr; | ||
233 | } | ||
234 | |||
235 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
236 | p2wi->regs = devm_ioremap_resource(dev, r); | ||
237 | if (IS_ERR(p2wi->regs)) | ||
238 | return PTR_ERR(p2wi->regs); | ||
239 | |||
240 | strlcpy(p2wi->adapter.name, pdev->name, sizeof(p2wi->adapter.name)); | ||
241 | irq = platform_get_irq(pdev, 0); | ||
242 | if (irq < 0) { | ||
243 | dev_err(dev, "failed to retrieve irq: %d\n", irq); | ||
244 | return irq; | ||
245 | } | ||
246 | |||
247 | p2wi->clk = devm_clk_get(dev, NULL); | ||
248 | if (IS_ERR(p2wi->clk)) { | ||
249 | ret = PTR_ERR(p2wi->clk); | ||
250 | dev_err(dev, "failed to retrieve clk: %d\n", ret); | ||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | ret = clk_prepare_enable(p2wi->clk); | ||
255 | if (ret) { | ||
256 | dev_err(dev, "failed to enable clk: %d\n", ret); | ||
257 | return ret; | ||
258 | } | ||
259 | |||
260 | parent_clk_freq = clk_get_rate(p2wi->clk); | ||
261 | |||
262 | p2wi->rstc = devm_reset_control_get(dev, NULL); | ||
263 | if (IS_ERR(p2wi->rstc)) { | ||
264 | ret = PTR_ERR(p2wi->rstc); | ||
265 | dev_err(dev, "failed to retrieve reset controller: %d\n", ret); | ||
266 | goto err_clk_disable; | ||
267 | } | ||
268 | |||
269 | ret = reset_control_deassert(p2wi->rstc); | ||
270 | if (ret) { | ||
271 | dev_err(dev, "failed to deassert reset line: %d\n", ret); | ||
272 | goto err_clk_disable; | ||
273 | } | ||
274 | |||
275 | init_completion(&p2wi->complete); | ||
276 | p2wi->adapter.dev.parent = dev; | ||
277 | p2wi->adapter.algo = &p2wi_algo; | ||
278 | p2wi->adapter.owner = THIS_MODULE; | ||
279 | p2wi->adapter.dev.of_node = pdev->dev.of_node; | ||
280 | platform_set_drvdata(pdev, p2wi); | ||
281 | i2c_set_adapdata(&p2wi->adapter, p2wi); | ||
282 | |||
283 | ret = devm_request_irq(dev, irq, p2wi_interrupt, 0, pdev->name, p2wi); | ||
284 | if (ret) { | ||
285 | dev_err(dev, "can't register interrupt handler irq%d: %d\n", | ||
286 | irq, ret); | ||
287 | goto err_reset_assert; | ||
288 | } | ||
289 | |||
290 | writel(P2WI_CTRL_SOFT_RST, p2wi->regs + P2WI_CTRL); | ||
291 | |||
292 | clk_div = parent_clk_freq / clk_freq; | ||
293 | if (!clk_div) { | ||
294 | dev_warn(dev, | ||
295 | "clock-frequency is too high, setting it to %lu Hz\n", | ||
296 | parent_clk_freq); | ||
297 | clk_div = 1; | ||
298 | } else if (clk_div > P2WI_CCR_MAX_CLK_DIV) { | ||
299 | dev_warn(dev, | ||
300 | "clock-frequency is too low, setting it to %lu Hz\n", | ||
301 | parent_clk_freq / P2WI_CCR_MAX_CLK_DIV); | ||
302 | clk_div = P2WI_CCR_MAX_CLK_DIV; | ||
303 | } | ||
304 | |||
305 | writel(P2WI_CCR_SDA_OUT_DELAY(1) | P2WI_CCR_CLK_DIV(clk_div), | ||
306 | p2wi->regs + P2WI_CCR); | ||
307 | |||
308 | ret = i2c_add_adapter(&p2wi->adapter); | ||
309 | if (!ret) | ||
310 | return 0; | ||
311 | |||
312 | err_reset_assert: | ||
313 | reset_control_assert(p2wi->rstc); | ||
314 | |||
315 | err_clk_disable: | ||
316 | clk_disable_unprepare(p2wi->clk); | ||
317 | |||
318 | return ret; | ||
319 | } | ||
320 | |||
321 | static int p2wi_remove(struct platform_device *dev) | ||
322 | { | ||
323 | struct p2wi *p2wi = platform_get_drvdata(dev); | ||
324 | |||
325 | reset_control_assert(p2wi->rstc); | ||
326 | clk_disable_unprepare(p2wi->clk); | ||
327 | i2c_del_adapter(&p2wi->adapter); | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static struct platform_driver p2wi_driver = { | ||
333 | .probe = p2wi_probe, | ||
334 | .remove = p2wi_remove, | ||
335 | .driver = { | ||
336 | .owner = THIS_MODULE, | ||
337 | .name = "i2c-sunxi-p2wi", | ||
338 | .of_match_table = p2wi_of_match_table, | ||
339 | }, | ||
340 | }; | ||
341 | module_platform_driver(p2wi_driver); | ||
342 | |||
343 | MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>"); | ||
344 | MODULE_DESCRIPTION("Allwinner P2WI driver"); | ||
345 | MODULE_LICENSE("GPL v2"); | ||