blob: 3022a802edaa5c55b41dba97e4e8a6bdf5c501d1 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2009-2011, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12/*
13 * SSBI driver for Qualcomm MSM platforms
14 *
15 */
16#include <linux/kernel.h>
17#include <linux/platform_device.h>
18#include <linux/err.h>
19#include <linux/delay.h>
20#include <linux/io.h>
21#include <linux/i2c.h>
22#include <linux/remote_spinlock.h>
23#include <mach/board.h>
24#include <linux/slab.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070025#include <linux/module.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026
27/* SSBI 2.0 controller registers */
28#define SSBI2_CMD 0x0008
29#define SSBI2_RD 0x0010
30#define SSBI2_STATUS 0x0014
31#define SSBI2_MODE2 0x001C
32
33/* SSBI_CMD fields */
34#define SSBI_CMD_RDWRN (0x01 << 24)
35#define SSBI_CMD_REG_ADDR_SHFT (0x10)
36#define SSBI_CMD_REG_ADDR_MASK (0xFF << SSBI_CMD_REG_ADDR_SHFT)
37#define SSBI_CMD_REG_DATA_SHFT (0x00)
38#define SSBI_CMD_REG_DATA_MASK (0xFF << SSBI_CMD_REG_DATA_SHFT)
39
40/* SSBI_STATUS fields */
41#define SSBI_STATUS_DATA_IN 0x10
42#define SSBI_STATUS_RD_CLOBBERED 0x08
43#define SSBI_STATUS_RD_READY 0x04
44#define SSBI_STATUS_READY 0x02
45#define SSBI_STATUS_MCHN_BUSY 0x01
46
47/* SSBI_RD fields */
48#define SSBI_RD_RDWRN 0x01000000
49#define SSBI_RD_REG_ADDR_SHFT 0x10
50#define SSBI_RD_REG_ADDR_MASK (0xFF << SSBI_RD_REG_ADDR_SHFT)
51#define SSBI_RD_REG_DATA_SHFT (0x00)
52#define SSBI_RD_REG_DATA_MASK (0xFF << SSBI_RD_REG_DATA_SHFT)
53
54/* SSBI_MODE2 fields */
55#define SSBI_MODE2_REG_ADDR_15_8_SHFT 0x04
56#define SSBI_MODE2_REG_ADDR_15_8_MASK (0x7F << SSBI_MODE2_REG_ADDR_15_8_SHFT)
57#define SSBI_MODE2_ADDR_WIDTH_SHFT 0x01
58#define SSBI_MODE2_ADDR_WIDTH_MASK (0x07 << SSBI_MODE2_ADDR_WIDTH_SHFT)
59#define SSBI_MODE2_SSBI2_MODE 0x00000001
60
61#define SSBI_MODE2_REG_ADDR_15_8(MD, AD) \
62 (((MD) & 0x0F) | ((((AD) >> 8) << SSBI_MODE2_REG_ADDR_15_8_SHFT) & \
63 SSBI_MODE2_REG_ADDR_15_8_MASK))
64
65#define SSBI_MODE2_ADDR_WIDTH(N) \
66 ((((N) - 8) << SSBI_MODE2_ADDR_WIDTH_SHFT) & SSBI_MODE2_ADDR_WIDTH_MASK)
67
68#define SSBI_TIMEOUT_US 100
69
70#define SSBI_CMD_READ(AD) \
71 (SSBI_CMD_RDWRN | (((AD) & 0xFF) << SSBI_CMD_REG_ADDR_SHFT))
72
73#define SSBI_CMD_WRITE(AD, DT) \
74 ((((AD) & 0xFF) << SSBI_CMD_REG_ADDR_SHFT) | \
75 (((DT) & 0xFF) << SSBI_CMD_REG_DATA_SHFT))
76
77/* SSBI PMIC Arbiter command registers */
78#define SSBI_PA_CMD 0x0000
79#define SSBI_PA_RD_STATUS 0x0004
80
81/* SSBI_PA_CMD fields */
82#define SSBI_PA_CMD_RDWRN (0x01 << 24)
83#define SSBI_PA_CMD_REG_ADDR_14_8_SHFT (0x10)
84#define SSBI_PA_CMD_REG_ADDR_14_8_MASK (0x7F << SSBI_PA_CMD_REG_ADDR_14_8_SHFT)
85#define SSBI_PA_CMD_REG_ADDR_7_0_SHFT (0x08)
86#define SSBI_PA_CMD_REG_ADDR_7_0_MASK (0xFF << SSBI_PA_CMD_REG_ADDR_7_0_SHFT)
87#define SSBI_PA_CMD_REG_DATA_SHFT (0x00)
88#define SSBI_PA_CMD_REG_DATA_MASK (0xFF << SSBI_PA_CMD_REG_DATA_SHFT)
89
90#define SSBI_PA_CMD_REG_DATA(DT) \
91 (((DT) << SSBI_PA_CMD_REG_DATA_SHFT) & SSBI_PA_CMD_REG_DATA_MASK)
92
93#define SSBI_PA_CMD_REG_ADDR(AD) \
94 (((AD) << SSBI_PA_CMD_REG_ADDR_7_0_SHFT) & \
95 (SSBI_PA_CMD_REG_ADDR_14_8_MASK|SSBI_PA_CMD_REG_ADDR_7_0_MASK))
96
97/* SSBI_PA_RD_STATUS fields */
98#define SSBI_PA_RD_STATUS_TRANS_DONE (0x01 << 27)
99#define SSBI_PA_RD_STATUS_TRANS_DENIED (0x01 << 26)
100#define SSBI_PA_RD_STATUS_REG_DATA_SHFT (0x00)
101#define SSBI_PA_RD_STATUS_REG_DATA_MASK (0xFF << SSBI_PA_CMD_REG_DATA_SHFT)
102#define SSBI_PA_RD_STATUS_TRANS_COMPLETE \
103 (SSBI_PA_RD_STATUS_TRANS_DONE|SSBI_PA_RD_STATUS_TRANS_DENIED)
104
105/* SSBI_FSM Read and Write commands for the FSM9xxx SSBI implementation */
106#define SSBI_FSM_CMD_REG_ADDR_SHFT (0x08)
107
108#define SSBI_FSM_CMD_READ(AD) \
109 (SSBI_CMD_RDWRN | (((AD) & 0xFFFF) << SSBI_FSM_CMD_REG_ADDR_SHFT))
110
111#define SSBI_FSM_CMD_WRITE(AD, DT) \
112 ((((AD) & 0xFFFF) << SSBI_FSM_CMD_REG_ADDR_SHFT) | \
113 (((DT) & 0xFF) << SSBI_CMD_REG_DATA_SHFT))
114
115#define SSBI_MSM_NAME "i2c_ssbi"
116
117MODULE_LICENSE("GPL v2");
118MODULE_VERSION("2.0");
119MODULE_ALIAS("platform:i2c_ssbi");
120
121struct i2c_ssbi_dev {
122 void __iomem *base;
123 struct device *dev;
124 struct i2c_adapter adapter;
125 unsigned long mem_phys_addr;
126 size_t mem_size;
127 bool use_rlock;
128 remote_spinlock_t rspin_lock;
129 enum msm_ssbi_controller_type controller_type;
130 int (*read)(struct i2c_ssbi_dev *, struct i2c_msg *);
131 int (*write)(struct i2c_ssbi_dev *, struct i2c_msg *);
132};
133
134static inline u32 ssbi_readl(struct i2c_ssbi_dev *ssbi, u32 reg)
135{
136 return readl_relaxed(ssbi->base + reg);
137}
138
139static inline void ssbi_writel(struct i2c_ssbi_dev *ssbi, u32 reg, u32 val)
140{
141 writel_relaxed(val, ssbi->base + reg);
142}
143
144static inline int
145i2c_ssbi_poll_for_device_ready(struct i2c_ssbi_dev *ssbi)
146{
147 u32 timeout = SSBI_TIMEOUT_US;
148
149 while (!(ssbi_readl(ssbi, SSBI2_STATUS) & SSBI_STATUS_READY)) {
150 if (--timeout == 0) {
151 dev_err(ssbi->dev, "%s: timeout, status %x\n", __func__,
152 ssbi_readl(ssbi, SSBI2_STATUS));
153 return -ETIMEDOUT;
154 }
155 udelay(1);
156 }
157
158 return 0;
159}
160
161static inline int
162i2c_ssbi_poll_for_read_completed(struct i2c_ssbi_dev *ssbi)
163{
164 u32 timeout = SSBI_TIMEOUT_US;
165
166 while (!(ssbi_readl(ssbi, SSBI2_STATUS) & SSBI_STATUS_RD_READY)) {
167 if (--timeout == 0) {
168 dev_err(ssbi->dev, "%s: timeout, status %x\n", __func__,
169 ssbi_readl(ssbi, SSBI2_STATUS));
170 return -ETIMEDOUT;
171 }
172 udelay(1);
173 }
174
175 return 0;
176}
177
178static inline int
179i2c_ssbi_poll_for_transfer_completed(struct i2c_ssbi_dev *ssbi)
180{
181 u32 timeout = SSBI_TIMEOUT_US;
182
183 while ((ssbi_readl(ssbi, SSBI2_STATUS) & SSBI_STATUS_MCHN_BUSY)) {
184 if (--timeout == 0) {
185 dev_err(ssbi->dev, "%s: timeout, status %x\n", __func__,
186 ssbi_readl(ssbi, SSBI2_STATUS));
187 return -ETIMEDOUT;
188 }
189 udelay(1);
190 }
191
192 return 0;
193}
194
195static int
196i2c_ssbi_read_bytes(struct i2c_ssbi_dev *ssbi, struct i2c_msg *msg)
197{
198 int ret = 0;
199 u8 *buf = msg->buf;
200 u16 len = msg->len;
201 u16 addr = msg->addr;
202 u32 read_cmd;
203
204 if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) {
205 u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2);
206 ssbi_writel(ssbi, SSBI2_MODE2,
207 SSBI_MODE2_REG_ADDR_15_8(mode2, addr));
208 }
209
210 if (ssbi->controller_type == FSM_SBI_CTRL_SSBI)
211 read_cmd = SSBI_FSM_CMD_READ(addr);
212 else
213 read_cmd = SSBI_CMD_READ(addr);
214
215 while (len) {
216 ret = i2c_ssbi_poll_for_device_ready(ssbi);
217 if (ret)
218 goto read_failed;
219
220 ssbi_writel(ssbi, SSBI2_CMD, read_cmd);
221
222 ret = i2c_ssbi_poll_for_read_completed(ssbi);
223 if (ret)
224 goto read_failed;
225
226 *buf++ = ssbi_readl(ssbi, SSBI2_RD) & SSBI_RD_REG_DATA_MASK;
227 len--;
228 }
229
230read_failed:
231 return ret;
232}
233
234static int
235i2c_ssbi_write_bytes(struct i2c_ssbi_dev *ssbi, struct i2c_msg *msg)
236{
237 int ret = 0;
238 u8 *buf = msg->buf;
239 u16 len = msg->len;
240 u16 addr = msg->addr;
241
242 if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) {
243 u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2);
244 ssbi_writel(ssbi, SSBI2_MODE2,
245 SSBI_MODE2_REG_ADDR_15_8(mode2, addr));
246 }
247
248 while (len) {
249 ret = i2c_ssbi_poll_for_device_ready(ssbi);
250 if (ret)
251 goto write_failed;
252
253 if (ssbi->controller_type == FSM_SBI_CTRL_SSBI)
254 ssbi_writel(ssbi, SSBI2_CMD,
255 SSBI_FSM_CMD_WRITE(addr, *buf++));
256 else
257 ssbi_writel(ssbi, SSBI2_CMD,
258 SSBI_CMD_WRITE(addr, *buf++));
259
260 ret = i2c_ssbi_poll_for_transfer_completed(ssbi);
261 if (ret)
262 goto write_failed;
263
264 len--;
265 }
266
267write_failed:
268 return ret;
269}
270
271static inline int
272i2c_ssbi_pa_transfer(struct i2c_ssbi_dev *ssbi, u32 cmd, u8 *data)
273{
274 u32 rd_status;
275 u32 timeout = SSBI_TIMEOUT_US;
276
277 ssbi_writel(ssbi, SSBI_PA_CMD, cmd);
278 rd_status = ssbi_readl(ssbi, SSBI_PA_RD_STATUS);
279
280 while ((rd_status & (SSBI_PA_RD_STATUS_TRANS_COMPLETE)) == 0) {
281
282 if (--timeout == 0) {
283 dev_err(ssbi->dev, "%s: timeout, status %x\n",
284 __func__, rd_status);
285 return -ETIMEDOUT;
286 }
287 udelay(1);
288 rd_status = ssbi_readl(ssbi, SSBI_PA_RD_STATUS);
289 }
290
291 if (rd_status & SSBI_PA_RD_STATUS_TRANS_DENIED) {
292 dev_err(ssbi->dev, "%s: transaction denied, status %x\n",
293 __func__, rd_status);
294 return -EPERM;
295 }
296
297 if (data)
298 *data = (rd_status & SSBI_PA_RD_STATUS_REG_DATA_MASK) >>
299 SSBI_PA_CMD_REG_DATA_SHFT;
300 return 0;
301}
302
303static int
304i2c_ssbi_pa_read_bytes(struct i2c_ssbi_dev *ssbi, struct i2c_msg *msg)
305{
306 int ret = 0;
307 u8 data;
308 u8 *buf = msg->buf;
309 u16 len = msg->len;
310 u32 read_cmd = (SSBI_PA_CMD_RDWRN | SSBI_PA_CMD_REG_ADDR(msg->addr));
311
312 while (len) {
313
314 ret = i2c_ssbi_pa_transfer(ssbi, read_cmd, &data);
315 if (ret)
316 goto read_failed;
317
318 *buf++ = data;
319 len--;
320 }
321
322read_failed:
323 return ret;
324}
325
326static int
327i2c_ssbi_pa_write_bytes(struct i2c_ssbi_dev *ssbi, struct i2c_msg *msg)
328{
329 int ret = 0;
330 u8 *buf = msg->buf;
331 u16 len = msg->len;
332 u32 addr = SSBI_PA_CMD_REG_ADDR(msg->addr);
333
334 while (len) {
335
336 u32 write_cmd = addr | (*buf++ & SSBI_PA_CMD_REG_DATA_MASK);
337
338 ret = i2c_ssbi_pa_transfer(ssbi, write_cmd, NULL);
339 if (ret)
340 goto write_failed;
341 len--;
342 }
343
344write_failed:
345 return ret;
346}
347
348static int
349i2c_ssbi_transfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
350{
351 int ret = 0;
352 int rem = num;
353 unsigned long flags = 0;
354 struct i2c_ssbi_dev *ssbi = i2c_get_adapdata(adap);
355
356 if (ssbi->use_rlock)
357 remote_spin_lock_irqsave(&ssbi->rspin_lock, flags);
358
359 while (rem) {
360 if (msgs->flags & I2C_M_RD) {
361 ret = ssbi->read(ssbi, msgs);
362 if (ret)
363 goto transfer_failed;
364 } else {
365 ret = ssbi->write(ssbi, msgs);
366 if (ret)
367 goto transfer_failed;
368 }
369
370 msgs++;
371 rem--;
372 }
373
374 if (ssbi->use_rlock)
375 remote_spin_unlock_irqrestore(&ssbi->rspin_lock, flags);
376
377 return num;
378
379transfer_failed:
380 if (ssbi->use_rlock)
381 remote_spin_unlock_irqrestore(&ssbi->rspin_lock, flags);
382 return ret;
383}
384
385static u32 i2c_ssbi_i2c_func(struct i2c_adapter *adap)
386{
387 return I2C_FUNC_I2C;
388}
389
390static const struct i2c_algorithm msm_i2c_algo = {
391 .master_xfer = i2c_ssbi_transfer,
392 .functionality = i2c_ssbi_i2c_func,
393};
394
395static int __init i2c_ssbi_probe(struct platform_device *pdev)
396{
397 int ret = 0;
398 struct resource *ssbi_res;
399 struct i2c_ssbi_dev *ssbi;
400 const struct msm_i2c_ssbi_platform_data *pdata;
401
402 pdata = pdev->dev.platform_data;
403 if (!pdata) {
404 ret = -ENXIO;
405 dev_err(&pdev->dev, "platform data not initialized\n");
406 goto err_probe_exit;
407 }
408
409 ssbi = kzalloc(sizeof(struct i2c_ssbi_dev), GFP_KERNEL);
410 if (!ssbi) {
411 ret = -ENOMEM;
412 dev_err(&pdev->dev, "allocation failed\n");
413 goto err_probe_exit;
414 }
415
416 ssbi_res = platform_get_resource_byname(pdev,
417 IORESOURCE_MEM, "ssbi_base");
418 if (!ssbi_res) {
419 ret = -ENXIO;
420 dev_err(&pdev->dev, "get_resource_byname failed\n");
421 goto err_probe_res;
422 }
423
424 ssbi->mem_phys_addr = ssbi_res->start;
425 ssbi->mem_size = resource_size(ssbi_res);
426 if (!request_mem_region(ssbi->mem_phys_addr, ssbi->mem_size,
427 SSBI_MSM_NAME)) {
428 ret = -ENXIO;
429 dev_err(&pdev->dev, "request_mem_region failed\n");
430 goto err_probe_reqmem;
431 }
432
433 ssbi->base = ioremap(ssbi->mem_phys_addr, ssbi->mem_size);
434 if (!ssbi->base) {
435 dev_err(&pdev->dev, "ioremap failed\n");
436 goto err_probe_ioremap;
437 }
438
439 ssbi->dev = &pdev->dev;
440 platform_set_drvdata(pdev, ssbi);
441
442 ssbi->controller_type = pdata->controller_type;
443 if (ssbi->controller_type == MSM_SBI_CTRL_PMIC_ARBITER) {
444 ssbi->read = i2c_ssbi_pa_read_bytes;
445 ssbi->write = i2c_ssbi_pa_write_bytes;
446 } else {
447 ssbi->read = i2c_ssbi_read_bytes;
448 ssbi->write = i2c_ssbi_write_bytes;
449 }
450
451 i2c_set_adapdata(&ssbi->adapter, ssbi);
452 ssbi->adapter.algo = &msm_i2c_algo;
453 strlcpy(ssbi->adapter.name,
454 "MSM SSBI adapter",
455 sizeof(ssbi->adapter.name));
456
457 if (pdata->rsl_id) {
458 ret = remote_spin_lock_init(&ssbi->rspin_lock, pdata->rsl_id);
459 if (ret) {
460 dev_err(&pdev->dev, "remote spinlock init failed\n");
461 goto err_remote_spinlock_init_failed;
462 }
463 ssbi->use_rlock = 1;
464 }
465
466 ssbi->adapter.nr = pdev->id;
467 ret = i2c_add_numbered_adapter(&ssbi->adapter);
468 if (ret) {
469 dev_err(&pdev->dev, "i2c_add_numbered_adapter failed\n");
470 goto err_add_adapter_failed;
471 }
472 return 0;
473
474err_add_adapter_failed:
475err_remote_spinlock_init_failed:
476 iounmap(ssbi->base);
477 platform_set_drvdata(pdev, NULL);
478err_probe_ioremap:
479 release_mem_region(ssbi->mem_phys_addr, ssbi->mem_size);
480err_probe_reqmem:
481err_probe_res:
482 kfree(ssbi);
483err_probe_exit:
484 return ret;
485}
486
487static int __devexit i2c_ssbi_remove(struct platform_device *pdev)
488{
489 struct i2c_ssbi_dev *ssbi = platform_get_drvdata(pdev);
490
491 platform_set_drvdata(pdev, NULL);
492 i2c_del_adapter(&ssbi->adapter);
493 iounmap(ssbi->base);
494 release_mem_region(ssbi->mem_phys_addr, ssbi->mem_size);
495 kfree(ssbi);
496 return 0;
497}
498
499static struct platform_driver i2c_ssbi_driver = {
500 .driver = {
501 .name = "i2c_ssbi",
502 .owner = THIS_MODULE,
503 },
504 .remove = __exit_p(i2c_ssbi_remove),
505};
506
507static int __init i2c_ssbi_init(void)
508{
509 return platform_driver_probe(&i2c_ssbi_driver, i2c_ssbi_probe);
510}
511arch_initcall(i2c_ssbi_init);
512
513static void __exit i2c_ssbi_exit(void)
514{
515 platform_driver_unregister(&i2c_ssbi_driver);
516}
517module_exit(i2c_ssbi_exit);