aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorMarc St-Jean <stjeanma@pmc-sierra.com>2007-07-12 08:12:31 -0400
committerJean Delvare <khali@hyperion.delvare>2007-07-12 08:12:31 -0400
commit1b144df1d7d69d6dd3394205933c8951dd8b6784 (patch)
treef61286ee111a107d74516a3e1ad924a018ab8528 /drivers/i2c
parentc6e16295b71ec006c8cb6d13520e9194652a6026 (diff)
i2c: New PMC MSP71xx TWI bus driver
Add TWI driver for the PMC-Sierra MSP71xx devices. [JD: Drop the probe hack, don't set algo_data as we never use it, return the right error code if the driver registration fails.] Signed-off-by: Marc St-Jean <Marc_St-Jean@pmc-sierra.com> Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/Kconfig9
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-pmcmsp.c653
3 files changed, 663 insertions, 0 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index c093b0700158..c477dcfad4e7 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -652,4 +652,13 @@ config I2C_PNX
652 This driver can also be built as a module. If so, the module 652 This driver can also be built as a module. If so, the module
653 will be called i2c-pnx. 653 will be called i2c-pnx.
654 654
655config I2C_PMCMSP
656 tristate "PMC MSP I2C TWI Controller"
657 depends on PMC_MSP
658 help
659 This driver supports the PMC TWI controller on MSP devices.
660
661 This driver can also be built as module. If so, the module
662 will be called i2c-pmcmsp.
663
655endmenu 664endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index a49c0a386aee..d7bbb90056a8 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
32obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o 32obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
33obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o 33obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
34obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o 34obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
35obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o
35obj-$(CONFIG_I2C_PNX) += i2c-pnx.o 36obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
36obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o 37obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o
37obj-$(CONFIG_I2C_PXA) += i2c-pxa.o 38obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c
new file mode 100644
index 000000000000..03188d277af1
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pmcmsp.c
@@ -0,0 +1,653 @@
1/*
2 * Specific bus support for PMC-TWI compliant implementation on MSP71xx.
3 *
4 * Copyright 2005-2007 PMC-Sierra, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 *
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
12 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
14 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
15 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
16 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
17 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
18 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
20 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/init.h>
30#include <linux/platform_device.h>
31#include <linux/i2c.h>
32#include <linux/interrupt.h>
33#include <linux/completion.h>
34#include <linux/mutex.h>
35#include <linux/delay.h>
36#include <asm/io.h>
37
38#define DRV_NAME "pmcmsptwi"
39
40#define MSP_TWI_SF_CLK_REG_OFFSET 0x00
41#define MSP_TWI_HS_CLK_REG_OFFSET 0x04
42#define MSP_TWI_CFG_REG_OFFSET 0x08
43#define MSP_TWI_CMD_REG_OFFSET 0x0c
44#define MSP_TWI_ADD_REG_OFFSET 0x10
45#define MSP_TWI_DAT_0_REG_OFFSET 0x14
46#define MSP_TWI_DAT_1_REG_OFFSET 0x18
47#define MSP_TWI_INT_STS_REG_OFFSET 0x1c
48#define MSP_TWI_INT_MSK_REG_OFFSET 0x20
49#define MSP_TWI_BUSY_REG_OFFSET 0x24
50
51#define MSP_TWI_INT_STS_DONE (1 << 0)
52#define MSP_TWI_INT_STS_LOST_ARBITRATION (1 << 1)
53#define MSP_TWI_INT_STS_NO_RESPONSE (1 << 2)
54#define MSP_TWI_INT_STS_DATA_COLLISION (1 << 3)
55#define MSP_TWI_INT_STS_BUSY (1 << 4)
56#define MSP_TWI_INT_STS_ALL 0x1f
57
58#define MSP_MAX_BYTES_PER_RW 8
59#define MSP_MAX_POLL 5
60#define MSP_POLL_DELAY 10
61#define MSP_IRQ_TIMEOUT (MSP_MAX_POLL * MSP_POLL_DELAY)
62
63/* IO Operation macros */
64#define pmcmsptwi_readl __raw_readl
65#define pmcmsptwi_writel __raw_writel
66
67/* TWI command type */
68enum pmcmsptwi_cmd_type {
69 MSP_TWI_CMD_WRITE = 0, /* Write only */
70 MSP_TWI_CMD_READ = 1, /* Read only */
71 MSP_TWI_CMD_WRITE_READ = 2, /* Write then Read */
72};
73
74/* The possible results of the xferCmd */
75enum pmcmsptwi_xfer_result {
76 MSP_TWI_XFER_OK = 0,
77 MSP_TWI_XFER_TIMEOUT,
78 MSP_TWI_XFER_BUSY,
79 MSP_TWI_XFER_DATA_COLLISION,
80 MSP_TWI_XFER_NO_RESPONSE,
81 MSP_TWI_XFER_LOST_ARBITRATION,
82};
83
84/* Corresponds to a PMCTWI clock configuration register */
85struct pmcmsptwi_clock {
86 u8 filter; /* Bits 15:12, default = 0x03 */
87 u16 clock; /* Bits 9:0, default = 0x001f */
88};
89
90struct pmcmsptwi_clockcfg {
91 struct pmcmsptwi_clock standard; /* The standard/fast clock config */
92 struct pmcmsptwi_clock highspeed; /* The highspeed clock config */
93};
94
95/* Corresponds to the main TWI configuration register */
96struct pmcmsptwi_cfg {
97 u8 arbf; /* Bits 15:12, default=0x03 */
98 u8 nak; /* Bits 11:8, default=0x03 */
99 u8 add10; /* Bit 7, default=0x00 */
100 u8 mst_code; /* Bits 6:4, default=0x00 */
101 u8 arb; /* Bit 1, default=0x01 */
102 u8 highspeed; /* Bit 0, default=0x00 */
103};
104
105/* A single pmctwi command to issue */
106struct pmcmsptwi_cmd {
107 u16 addr; /* The slave address (7 or 10 bits) */
108 enum pmcmsptwi_cmd_type type; /* The command type */
109 u8 write_len; /* Number of bytes in the write buffer */
110 u8 read_len; /* Number of bytes in the read buffer */
111 u8 *write_data; /* Buffer of characters to send */
112 u8 *read_data; /* Buffer to fill with incoming data */
113};
114
115/* The private data */
116struct pmcmsptwi_data {
117 void __iomem *iobase; /* iomapped base for IO */
118 int irq; /* IRQ to use (0 disables) */
119 struct completion wait; /* Completion for xfer */
120 struct mutex lock; /* Used for threadsafeness */
121 enum pmcmsptwi_xfer_result last_result; /* result of last xfer */
122};
123
124/* The default settings */
125const static struct pmcmsptwi_clockcfg pmcmsptwi_defclockcfg = {
126 .standard = {
127 .filter = 0x3,
128 .clock = 0x1f,
129 },
130 .highspeed = {
131 .filter = 0x3,
132 .clock = 0x1f,
133 },
134};
135
136const static struct pmcmsptwi_cfg pmcmsptwi_defcfg = {
137 .arbf = 0x03,
138 .nak = 0x03,
139 .add10 = 0x00,
140 .mst_code = 0x00,
141 .arb = 0x01,
142 .highspeed = 0x00,
143};
144
145static struct pmcmsptwi_data pmcmsptwi_data;
146
147static struct i2c_adapter pmcmsptwi_adapter;
148
149/* inline helper functions */
150static inline u32 pmcmsptwi_clock_to_reg(
151 const struct pmcmsptwi_clock *clock)
152{
153 return ((clock->filter & 0xf) << 12) | (clock->clock & 0x03ff);
154}
155
156static inline void pmcmsptwi_reg_to_clock(
157 u32 reg, struct pmcmsptwi_clock *clock)
158{
159 clock->filter = (reg >> 12) & 0xf;
160 clock->clock = reg & 0x03ff;
161}
162
163static inline u32 pmcmsptwi_cfg_to_reg(const struct pmcmsptwi_cfg *cfg)
164{
165 return ((cfg->arbf & 0xf) << 12) |
166 ((cfg->nak & 0xf) << 8) |
167 ((cfg->add10 & 0x1) << 7) |
168 ((cfg->mst_code & 0x7) << 4) |
169 ((cfg->arb & 0x1) << 1) |
170 (cfg->highspeed & 0x1);
171}
172
173static inline void pmcmsptwi_reg_to_cfg(u32 reg, struct pmcmsptwi_cfg *cfg)
174{
175 cfg->arbf = (reg >> 12) & 0xf;
176 cfg->nak = (reg >> 8) & 0xf;
177 cfg->add10 = (reg >> 7) & 0x1;
178 cfg->mst_code = (reg >> 4) & 0x7;
179 cfg->arb = (reg >> 1) & 0x1;
180 cfg->highspeed = reg & 0x1;
181}
182
183/*
184 * Sets the current clock configuration
185 */
186static void pmcmsptwi_set_clock_config(const struct pmcmsptwi_clockcfg *cfg,
187 struct pmcmsptwi_data *data)
188{
189 mutex_lock(&data->lock);
190 pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->standard),
191 data->iobase + MSP_TWI_SF_CLK_REG_OFFSET);
192 pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->highspeed),
193 data->iobase + MSP_TWI_HS_CLK_REG_OFFSET);
194 mutex_unlock(&data->lock);
195}
196
197/*
198 * Gets the current TWI bus configuration
199 */
200static void pmcmsptwi_get_twi_config(struct pmcmsptwi_cfg *cfg,
201 struct pmcmsptwi_data *data)
202{
203 mutex_lock(&data->lock);
204 pmcmsptwi_reg_to_cfg(pmcmsptwi_readl(
205 data->iobase + MSP_TWI_CFG_REG_OFFSET), cfg);
206 mutex_unlock(&data->lock);
207}
208
209/*
210 * Sets the current TWI bus configuration
211 */
212static void pmcmsptwi_set_twi_config(const struct pmcmsptwi_cfg *cfg,
213 struct pmcmsptwi_data *data)
214{
215 mutex_lock(&data->lock);
216 pmcmsptwi_writel(pmcmsptwi_cfg_to_reg(cfg),
217 data->iobase + MSP_TWI_CFG_REG_OFFSET);
218 mutex_unlock(&data->lock);
219}
220
221/*
222 * Parses the 'int_sts' register and returns a well-defined error code
223 */
224static enum pmcmsptwi_xfer_result pmcmsptwi_get_result(u32 reg)
225{
226 if (reg & MSP_TWI_INT_STS_LOST_ARBITRATION) {
227 dev_dbg(&pmcmsptwi_adapter.dev,
228 "Result: Lost arbitration\n");
229 return MSP_TWI_XFER_LOST_ARBITRATION;
230 } else if (reg & MSP_TWI_INT_STS_NO_RESPONSE) {
231 dev_dbg(&pmcmsptwi_adapter.dev,
232 "Result: No response\n");
233 return MSP_TWI_XFER_NO_RESPONSE;
234 } else if (reg & MSP_TWI_INT_STS_DATA_COLLISION) {
235 dev_dbg(&pmcmsptwi_adapter.dev,
236 "Result: Data collision\n");
237 return MSP_TWI_XFER_DATA_COLLISION;
238 } else if (reg & MSP_TWI_INT_STS_BUSY) {
239 dev_dbg(&pmcmsptwi_adapter.dev,
240 "Result: Bus busy\n");
241 return MSP_TWI_XFER_BUSY;
242 }
243
244 dev_dbg(&pmcmsptwi_adapter.dev, "Result: Operation succeeded\n");
245 return MSP_TWI_XFER_OK;
246}
247
248/*
249 * In interrupt mode, handle the interrupt.
250 * NOTE: Assumes data->lock is held.
251 */
252static irqreturn_t pmcmsptwi_interrupt(int irq, void *ptr)
253{
254 struct pmcmsptwi_data *data = ptr;
255
256 u32 reason = pmcmsptwi_readl(data->iobase +
257 MSP_TWI_INT_STS_REG_OFFSET);
258 pmcmsptwi_writel(reason, data->iobase + MSP_TWI_INT_STS_REG_OFFSET);
259
260 dev_dbg(&pmcmsptwi_adapter.dev, "Got interrupt 0x%08x\n", reason);
261 if (!(reason & MSP_TWI_INT_STS_DONE))
262 return IRQ_NONE;
263
264 data->last_result = pmcmsptwi_get_result(reason);
265 complete(&data->wait);
266
267 return IRQ_HANDLED;
268}
269
270/*
271 * Probe for and register the device and return 0 if there is one.
272 */
273static int __devinit pmcmsptwi_probe(struct platform_device *pldev)
274{
275 struct resource *res;
276 int rc = -ENODEV;
277
278 /* get the static platform resources */
279 res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
280 if (!res) {
281 dev_err(&pldev->dev, "IOMEM resource not found\n");
282 goto ret_err;
283 }
284
285 /* reserve the memory region */
286 if (!request_mem_region(res->start, res->end - res->start + 1,
287 pldev->name)) {
288 dev_err(&pldev->dev,
289 "Unable to get memory/io address region 0x%08x\n",
290 res->start);
291 rc = -EBUSY;
292 goto ret_err;
293 }
294
295 /* remap the memory */
296 pmcmsptwi_data.iobase = ioremap_nocache(res->start,
297 res->end - res->start + 1);
298 if (!pmcmsptwi_data.iobase) {
299 dev_err(&pldev->dev,
300 "Unable to ioremap address 0x%08x\n", res->start);
301 rc = -EIO;
302 goto ret_unreserve;
303 }
304
305 /* request the irq */
306 pmcmsptwi_data.irq = platform_get_irq(pldev, 0);
307 if (pmcmsptwi_data.irq) {
308 rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt,
309 IRQF_SHARED | IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
310 pldev->name, &pmcmsptwi_data);
311 if (rc == 0) {
312 /*
313 * Enable 'DONE' interrupt only.
314 *
315 * If you enable all interrupts, you will get one on
316 * error and another when the operation completes.
317 * This way you only have to handle one interrupt,
318 * but you can still check all result flags.
319 */
320 pmcmsptwi_writel(MSP_TWI_INT_STS_DONE,
321 pmcmsptwi_data.iobase +
322 MSP_TWI_INT_MSK_REG_OFFSET);
323 } else {
324 dev_warn(&pldev->dev,
325 "Could not assign TWI IRQ handler "
326 "to irq %d (continuing with poll)\n",
327 pmcmsptwi_data.irq);
328 pmcmsptwi_data.irq = 0;
329 }
330 }
331
332 init_completion(&pmcmsptwi_data.wait);
333 mutex_init(&pmcmsptwi_data.lock);
334
335 pmcmsptwi_set_clock_config(&pmcmsptwi_defclockcfg, &pmcmsptwi_data);
336 pmcmsptwi_set_twi_config(&pmcmsptwi_defcfg, &pmcmsptwi_data);
337
338 printk(KERN_INFO DRV_NAME ": Registering MSP71xx I2C adapter\n");
339
340 pmcmsptwi_adapter.dev.parent = &pldev->dev;
341 platform_set_drvdata(pldev, &pmcmsptwi_adapter);
342 i2c_set_adapdata(&pmcmsptwi_adapter, &pmcmsptwi_data);
343
344 rc = i2c_add_adapter(&pmcmsptwi_adapter);
345 if (rc) {
346 dev_err(&pldev->dev, "Unable to register I2C adapter\n");
347 goto ret_unmap;
348 }
349
350 return 0;
351
352ret_unmap:
353 platform_set_drvdata(pldev, NULL);
354 if (pmcmsptwi_data.irq) {
355 pmcmsptwi_writel(0,
356 pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
357 free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
358 }
359
360 iounmap(pmcmsptwi_data.iobase);
361
362ret_unreserve:
363 release_mem_region(res->start, res->end - res->start + 1);
364
365ret_err:
366 return rc;
367}
368
369/*
370 * Release the device and return 0 if there is one.
371 */
372static int __devexit pmcmsptwi_remove(struct platform_device *pldev)
373{
374 struct resource *res;
375
376 i2c_del_adapter(&pmcmsptwi_adapter);
377
378 platform_set_drvdata(pldev, NULL);
379 if (pmcmsptwi_data.irq) {
380 pmcmsptwi_writel(0,
381 pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
382 free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
383 }
384
385 iounmap(pmcmsptwi_data.iobase);
386
387 res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
388 release_mem_region(res->start, res->end - res->start + 1);
389
390 return 0;
391}
392
393/*
394 * Polls the 'busy' register until the command is complete.
395 * NOTE: Assumes data->lock is held.
396 */
397static void pmcmsptwi_poll_complete(struct pmcmsptwi_data *data)
398{
399 int i;
400
401 for (i = 0; i < MSP_MAX_POLL; i++) {
402 u32 val = pmcmsptwi_readl(data->iobase +
403 MSP_TWI_BUSY_REG_OFFSET);
404 if (val == 0) {
405 u32 reason = pmcmsptwi_readl(data->iobase +
406 MSP_TWI_INT_STS_REG_OFFSET);
407 pmcmsptwi_writel(reason, data->iobase +
408 MSP_TWI_INT_STS_REG_OFFSET);
409 data->last_result = pmcmsptwi_get_result(reason);
410 return;
411 }
412 udelay(MSP_POLL_DELAY);
413 }
414
415 dev_dbg(&pmcmsptwi_adapter.dev, "Result: Poll timeout\n");
416 data->last_result = MSP_TWI_XFER_TIMEOUT;
417}
418
419/*
420 * Do the transfer (low level):
421 * May use interrupt-driven or polling, depending on if an IRQ is
422 * presently registered.
423 * NOTE: Assumes data->lock is held.
424 */
425static enum pmcmsptwi_xfer_result pmcmsptwi_do_xfer(
426 u32 reg, struct pmcmsptwi_data *data)
427{
428 dev_dbg(&pmcmsptwi_adapter.dev, "Writing cmd reg 0x%08x\n", reg);
429 pmcmsptwi_writel(reg, data->iobase + MSP_TWI_CMD_REG_OFFSET);
430 if (data->irq) {
431 unsigned long timeleft = wait_for_completion_timeout(
432 &data->wait, MSP_IRQ_TIMEOUT);
433 if (timeleft == 0) {
434 dev_dbg(&pmcmsptwi_adapter.dev,
435 "Result: IRQ timeout\n");
436 complete(&data->wait);
437 data->last_result = MSP_TWI_XFER_TIMEOUT;
438 }
439 } else
440 pmcmsptwi_poll_complete(data);
441
442 return data->last_result;
443}
444
445/*
446 * Helper routine, converts 'pmctwi_cmd' struct to register format
447 */
448static inline u32 pmcmsptwi_cmd_to_reg(const struct pmcmsptwi_cmd *cmd)
449{
450 return ((cmd->type & 0x3) << 8) |
451 (((cmd->write_len - 1) & 0x7) << 4) |
452 ((cmd->read_len - 1) & 0x7);
453}
454
455/*
456 * Do the transfer (high level)
457 */
458static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
459 struct pmcmsptwi_cmd *cmd,
460 struct pmcmsptwi_data *data)
461{
462 enum pmcmsptwi_xfer_result retval;
463
464 if ((cmd->type == MSP_TWI_CMD_WRITE && cmd->write_len == 0) ||
465 (cmd->type == MSP_TWI_CMD_READ && cmd->read_len == 0) ||
466 (cmd->type == MSP_TWI_CMD_WRITE_READ &&
467 (cmd->read_len == 0 || cmd->write_len == 0))) {
468 dev_err(&pmcmsptwi_adapter.dev,
469 "%s: Cannot transfer less than 1 byte\n",
470 __FUNCTION__);
471 return -EINVAL;
472 }
473
474 if (cmd->read_len > MSP_MAX_BYTES_PER_RW ||
475 cmd->write_len > MSP_MAX_BYTES_PER_RW) {
476 dev_err(&pmcmsptwi_adapter.dev,
477 "%s: Cannot transfer more than %d bytes\n",
478 __FUNCTION__, MSP_MAX_BYTES_PER_RW);
479 return -EINVAL;
480 }
481
482 mutex_lock(&data->lock);
483 dev_dbg(&pmcmsptwi_adapter.dev,
484 "Setting address to 0x%04x\n", cmd->addr);
485 pmcmsptwi_writel(cmd->addr, data->iobase + MSP_TWI_ADD_REG_OFFSET);
486
487 if (cmd->type == MSP_TWI_CMD_WRITE ||
488 cmd->type == MSP_TWI_CMD_WRITE_READ) {
489 __be64 tmp = cpu_to_be64p((u64 *)cmd->write_data);
490 tmp >>= (MSP_MAX_BYTES_PER_RW - cmd->write_len) * 8;
491 dev_dbg(&pmcmsptwi_adapter.dev, "Writing 0x%016llx\n", tmp);
492 pmcmsptwi_writel(tmp & 0x00000000ffffffffLL,
493 data->iobase + MSP_TWI_DAT_0_REG_OFFSET);
494 if (cmd->write_len > 4)
495 pmcmsptwi_writel(tmp >> 32,
496 data->iobase + MSP_TWI_DAT_1_REG_OFFSET);
497 }
498
499 retval = pmcmsptwi_do_xfer(pmcmsptwi_cmd_to_reg(cmd), data);
500 if (retval != MSP_TWI_XFER_OK)
501 goto xfer_err;
502
503 if (cmd->type == MSP_TWI_CMD_READ ||
504 cmd->type == MSP_TWI_CMD_WRITE_READ) {
505 int i;
506 u64 rmsk = ~(0xffffffffffffffffLL << (cmd->read_len * 8));
507 u64 tmp = (u64)pmcmsptwi_readl(data->iobase +
508 MSP_TWI_DAT_0_REG_OFFSET);
509 if (cmd->read_len > 4)
510 tmp |= (u64)pmcmsptwi_readl(data->iobase +
511 MSP_TWI_DAT_1_REG_OFFSET) << 32;
512 tmp &= rmsk;
513 dev_dbg(&pmcmsptwi_adapter.dev, "Read 0x%016llx\n", tmp);
514
515 for (i = 0; i < cmd->read_len; i++)
516 cmd->read_data[i] = tmp >> i;
517 }
518
519xfer_err:
520 mutex_unlock(&data->lock);
521
522 return retval;
523}
524
525/* -- Algorithm functions -- */
526
527/*
528 * Sends an i2c command out on the adapter
529 */
530static int pmcmsptwi_master_xfer(struct i2c_adapter *adap,
531 struct i2c_msg *msg, int num)
532{
533 struct pmcmsptwi_data *data = i2c_get_adapdata(adap);
534 struct pmcmsptwi_cmd cmd;
535 struct pmcmsptwi_cfg oldcfg, newcfg;
536 int ret;
537
538 if (num > 2) {
539 dev_dbg(&adap->dev, "%d messages unsupported\n", num);
540 return -EINVAL;
541 } else if (num == 2) {
542 /* Check for a dual write-then-read command */
543 struct i2c_msg *nextmsg = msg + 1;
544 if (!(msg->flags & I2C_M_RD) &&
545 (nextmsg->flags & I2C_M_RD) &&
546 msg->addr == nextmsg->addr) {
547 cmd.type = MSP_TWI_CMD_WRITE_READ;
548 cmd.write_len = msg->len;
549 cmd.write_data = msg->buf;
550 cmd.read_len = nextmsg->len;
551 cmd.read_data = nextmsg->buf;
552 } else {
553 dev_dbg(&adap->dev,
554 "Non write-read dual messages unsupported\n");
555 return -EINVAL;
556 }
557 } else if (msg->flags & I2C_M_RD) {
558 cmd.type = MSP_TWI_CMD_READ;
559 cmd.read_len = msg->len;
560 cmd.read_data = msg->buf;
561 cmd.write_len = 0;
562 cmd.write_data = NULL;
563 } else {
564 cmd.type = MSP_TWI_CMD_WRITE;
565 cmd.read_len = 0;
566 cmd.read_data = NULL;
567 cmd.write_len = msg->len;
568 cmd.write_data = msg->buf;
569 }
570
571 if (msg->len == 0) {
572 dev_err(&adap->dev, "Zero-byte messages unsupported\n");
573 return -EINVAL;
574 }
575
576 cmd.addr = msg->addr;
577
578 if (msg->flags & I2C_M_TEN) {
579 pmcmsptwi_get_twi_config(&newcfg, data);
580 memcpy(&oldcfg, &newcfg, sizeof(oldcfg));
581
582 /* Set the special 10-bit address flag */
583 newcfg.add10 = 1;
584
585 pmcmsptwi_set_twi_config(&newcfg, data);
586 }
587
588 /* Execute the command */
589 ret = pmcmsptwi_xfer_cmd(&cmd, data);
590
591 if (msg->flags & I2C_M_TEN)
592 pmcmsptwi_set_twi_config(&oldcfg, data);
593
594 dev_dbg(&adap->dev, "I2C %s of %d bytes ",
595 (msg->flags & I2C_M_RD) ? "read" : "write", msg->len);
596 if (ret != MSP_TWI_XFER_OK) {
597 /*
598 * TODO: We could potentially loop and retry in the case
599 * of MSP_TWI_XFER_TIMEOUT.
600 */
601 dev_dbg(&adap->dev, "failed\n");
602 return -1;
603 }
604
605 dev_dbg(&adap->dev, "succeeded\n");
606 return 0;
607}
608
609static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter)
610{
611 return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
612 I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
613 I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL;
614}
615
616/* -- Initialization -- */
617
618static struct i2c_algorithm pmcmsptwi_algo = {
619 .master_xfer = pmcmsptwi_master_xfer,
620 .functionality = pmcmsptwi_i2c_func,
621};
622
623static struct i2c_adapter pmcmsptwi_adapter = {
624 .owner = THIS_MODULE,
625 .class = I2C_CLASS_HWMON,
626 .algo = &pmcmsptwi_algo,
627 .name = DRV_NAME,
628};
629
630static struct platform_driver pmcmsptwi_driver = {
631 .probe = pmcmsptwi_probe,
632 .remove = __devexit_p(pmcmsptwi_remove),
633 .driver {
634 .name = DRV_NAME,
635 .owner = THIS_MODULE,
636 },
637};
638
639static int __init pmcmsptwi_init(void)
640{
641 return platform_driver_register(&pmcmsptwi_driver);
642}
643
644static void __exit pmcmsptwi_exit(void)
645{
646 platform_driver_unregister(&pmcmsptwi_driver);
647}
648
649MODULE_DESCRIPTION("PMC MSP TWI/SMBus/I2C driver");
650MODULE_LICENSE("GPL");
651
652module_init(pmcmsptwi_init);
653module_exit(pmcmsptwi_exit);