~ubuntu-branches/ubuntu/trusty/linux-armadaxp/trusty

« back to all changes in this revision

Viewing changes to drivers/staging/cx25821/cx25821-i2c.c

  • Committer: Package Import Robot
  • Author(s): Michael Casadevall, Bryan Wu, Dann Frazier, Michael Casadeall
  • Date: 2012-03-10 15:00:54 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20120310150054-flugb39zon8vvgwe
Tags: 3.2.0-1600.1
[ Bryan Wu ]
* UBUNTU: import debian/debian.env and debian.armadaxp

[ Dann Frazier ]
* ARM: Armada XP: remove trailing '/' in dirnames in mvRules.mk

[ Michael Casadeall ]
* tools: add some tools for Marvell Armada XP processor
* kernel: timer tick hacking from Marvell
* kernel: Sheeva Errata: add delay on Sheeva when powering down
* net: add Marvell NFP netfilter
* net: socket and skb modifications made by Marvell
* miscdevice: add minor IDs for some Marvell Armada drivers
* fs: introduce memory pool for splice()
* video: EDID detection updates from Marvell Armada XP patchset
* video: backlight: add Marvell Dove LCD backlight driver
* video: display: add THS8200 display driver
* video: framebuffer: add Marvell Dove and Armada XP processor onchip LCD controller driver
* usbtest: add Interrupt transfer testing by Marvell Armada XP code
* usb: ehci: add support for Marvell EHCI controler
* tty/serial: 8250: add support for Marvell Armada XP processor and DeviceTree work
* rtc: add support for Marvell Armada XP onchip RTC controller
* net: pppoe: add Marvell ethernet NFP hook in PPPoE networking driver
* mtd: nand: add support for Marvell Armada XP Nand Flash Controller
* mtd: maps: add Marvell Armada XP specific map driver
* mmc: add support for Marvell Armada XP MMC/SD host controller
* i2c: add support for Marvell Armada XP onchip i2c bus controller
* hwmon: add Kconfig option for Armada XP onchip thermal sensor driver
* dmaengine: add Net DMA support for splice and update Marvell XOR DMA engine driver
* ata: add support for Marvell Armada XP SATA controller and update some quirks
* ARM: add Marvell Armada XP machine to mach-types
* ARM: oprofile: add support for Marvell PJ4B core
* ARM: mm: more ARMv6 switches for Marvell Armada XP
* ARM: remove static declaration to allow compilation
* ARM: alignment access fault trick
* ARM: mm: skip some fault fixing when run on NONE SMP ARMv6 mode during early abort event
* ARM: mm: add Marvell Sheeva CPU Architecture for PJ4B
* ARM: introduce optimized copy operation for Marvell Armada XP
* ARM: SAUCE: hardware breakpoint trick for Marvell Armada XP
* ARM: big endian and little endian tricks for Marvell Armada XP
* ARM: SAUCE: Add Marvell Armada XP build rules to arch/arm/kernel/Makefile
* ARM: vfp: add special handling for Marvell Armada XP
* ARM: add support for Marvell U-Boot
* ARM: add mv_controller_num for ARM PCI drivers
* ARM: add support for local PMUs, general SMP tweaks and cache flushing
* ARM: add Marvell device identifies in glue-proc.h
* ARM: add IPC driver support for Marvell platforms
* ARM: add DMA mapping for Marvell platforms
* ARM: add Sheeva errata and PJ4B code for booting
* ARM: update Kconfig and Makefile to include Marvell Armada XP platforms
* ARM: Armada XP: import LSP from Marvell for Armada XP 3.2 kernel enablement

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *  Driver for the Conexant CX25821 PCIe bridge
3
 
 *
4
 
 *  Copyright (C) 2009 Conexant Systems Inc.
5
 
 *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
6
 
 *      Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
7
 
 *
8
 
 *  This program is free software; you can redistribute it and/or modify
9
 
 *  it under the terms of the GNU General Public License as published by
10
 
 *  the Free Software Foundation; either version 2 of the License, or
11
 
 *  (at your option) any later version.
12
 
 *
13
 
 *  This program is distributed in the hope that it will be useful,
14
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
 *
17
 
 *  GNU General Public License for more details.
18
 
 *
19
 
 *  You should have received a copy of the GNU General Public License
20
 
 *  along with this program; if not, write to the Free Software
21
 
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
 
 */
23
 
 
24
 
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
25
 
 
26
 
#include "cx25821.h"
27
 
#include <linux/i2c.h>
28
 
 
29
 
static unsigned int i2c_debug;
30
 
module_param(i2c_debug, int, 0644);
31
 
MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
32
 
 
33
 
static unsigned int i2c_scan;
34
 
module_param(i2c_scan, int, 0444);
35
 
MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
36
 
 
37
 
#define dprintk(level, fmt, arg...)                                     \
38
 
do {                                                                    \
39
 
        if (i2c_debug >= level)                                         \
40
 
                printk(KERN_DEBUG "%s/0: " fmt, dev->name, ##arg);      \
41
 
} while (0)
42
 
 
43
 
#define I2C_WAIT_DELAY 32
44
 
#define I2C_WAIT_RETRY 64
45
 
 
46
 
#define I2C_EXTEND  (1 << 3)
47
 
#define I2C_NOSTOP  (1 << 4)
48
 
 
49
 
static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap)
50
 
{
51
 
        struct cx25821_i2c *bus = i2c_adap->algo_data;
52
 
        struct cx25821_dev *dev = bus->dev;
53
 
        return cx_read(bus->reg_stat) & 0x01;
54
 
}
55
 
 
56
 
static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
57
 
{
58
 
        struct cx25821_i2c *bus = i2c_adap->algo_data;
59
 
        struct cx25821_dev *dev = bus->dev;
60
 
        return cx_read(bus->reg_stat) & 0x02 ? 1 : 0;
61
 
}
62
 
 
63
 
static int i2c_wait_done(struct i2c_adapter *i2c_adap)
64
 
{
65
 
        int count;
66
 
 
67
 
        for (count = 0; count < I2C_WAIT_RETRY; count++) {
68
 
                if (!i2c_is_busy(i2c_adap))
69
 
                        break;
70
 
                udelay(I2C_WAIT_DELAY);
71
 
        }
72
 
 
73
 
        if (I2C_WAIT_RETRY == count)
74
 
                return 0;
75
 
 
76
 
        return 1;
77
 
}
78
 
 
79
 
static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
80
 
                         const struct i2c_msg *msg, int joined_rlen)
81
 
{
82
 
        struct cx25821_i2c *bus = i2c_adap->algo_data;
83
 
        struct cx25821_dev *dev = bus->dev;
84
 
        u32 wdata, addr, ctrl;
85
 
        int retval, cnt;
86
 
 
87
 
        if (joined_rlen)
88
 
                dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __func__,
89
 
                        msg->len, joined_rlen);
90
 
        else
91
 
                dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len);
92
 
 
93
 
        /* Deal with i2c probe functions with zero payload */
94
 
        if (msg->len == 0) {
95
 
                cx_write(bus->reg_addr, msg->addr << 25);
96
 
                cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2));
97
 
 
98
 
                if (!i2c_wait_done(i2c_adap))
99
 
                        return -EIO;
100
 
 
101
 
                if (!i2c_slave_did_ack(i2c_adap))
102
 
                        return -EIO;
103
 
 
104
 
                dprintk(1, "%s(): returns 0\n", __func__);
105
 
                return 0;
106
 
        }
107
 
 
108
 
        /* dev, reg + first byte */
109
 
        addr = (msg->addr << 25) | msg->buf[0];
110
 
        wdata = msg->buf[0];
111
 
 
112
 
        ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
113
 
 
114
 
        if (msg->len > 1)
115
 
                ctrl |= I2C_NOSTOP | I2C_EXTEND;
116
 
        else if (joined_rlen)
117
 
                ctrl |= I2C_NOSTOP;
118
 
 
119
 
        cx_write(bus->reg_addr, addr);
120
 
        cx_write(bus->reg_wdata, wdata);
121
 
        cx_write(bus->reg_ctrl, ctrl);
122
 
 
123
 
        retval = i2c_wait_done(i2c_adap);
124
 
        if (retval < 0)
125
 
                goto err;
126
 
 
127
 
        if (retval == 0)
128
 
                goto eio;
129
 
 
130
 
        if (i2c_debug) {
131
 
                if (!(ctrl & I2C_NOSTOP))
132
 
                        printk(" >\n");
133
 
        }
134
 
 
135
 
        for (cnt = 1; cnt < msg->len; cnt++) {
136
 
                /* following bytes */
137
 
                wdata = msg->buf[cnt];
138
 
                ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
139
 
 
140
 
                if (cnt < msg->len - 1)
141
 
                        ctrl |= I2C_NOSTOP | I2C_EXTEND;
142
 
                else if (joined_rlen)
143
 
                        ctrl |= I2C_NOSTOP;
144
 
 
145
 
                cx_write(bus->reg_addr, addr);
146
 
                cx_write(bus->reg_wdata, wdata);
147
 
                cx_write(bus->reg_ctrl, ctrl);
148
 
 
149
 
                retval = i2c_wait_done(i2c_adap);
150
 
                if (retval < 0)
151
 
                        goto err;
152
 
 
153
 
                if (retval == 0)
154
 
                        goto eio;
155
 
 
156
 
                if (i2c_debug) {
157
 
                        dprintk(1, " %02x", msg->buf[cnt]);
158
 
                        if (!(ctrl & I2C_NOSTOP))
159
 
                                dprintk(1, " >\n");
160
 
                }
161
 
        }
162
 
 
163
 
        return msg->len;
164
 
 
165
 
eio:
166
 
        retval = -EIO;
167
 
err:
168
 
        if (i2c_debug)
169
 
                pr_err(" ERR: %d\n", retval);
170
 
        return retval;
171
 
}
172
 
 
173
 
static int i2c_readbytes(struct i2c_adapter *i2c_adap,
174
 
                         const struct i2c_msg *msg, int joined)
175
 
{
176
 
        struct cx25821_i2c *bus = i2c_adap->algo_data;
177
 
        struct cx25821_dev *dev = bus->dev;
178
 
        u32 ctrl, cnt;
179
 
        int retval;
180
 
 
181
 
        if (i2c_debug && !joined)
182
 
                dprintk(1, "6-%s(msg->len=%d)\n", __func__, msg->len);
183
 
 
184
 
        /* Deal with i2c probe functions with zero payload */
185
 
        if (msg->len == 0) {
186
 
                cx_write(bus->reg_addr, msg->addr << 25);
187
 
                cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1);
188
 
                if (!i2c_wait_done(i2c_adap))
189
 
                        return -EIO;
190
 
                if (!i2c_slave_did_ack(i2c_adap))
191
 
                        return -EIO;
192
 
 
193
 
                dprintk(1, "%s(): returns 0\n", __func__);
194
 
                return 0;
195
 
        }
196
 
 
197
 
        if (i2c_debug) {
198
 
                if (joined)
199
 
                        dprintk(1, " R");
200
 
                else
201
 
                        dprintk(1, " <R %02x", (msg->addr << 1) + 1);
202
 
        }
203
 
 
204
 
        for (cnt = 0; cnt < msg->len; cnt++) {
205
 
 
206
 
                ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1;
207
 
 
208
 
                if (cnt < msg->len - 1)
209
 
                        ctrl |= I2C_NOSTOP | I2C_EXTEND;
210
 
 
211
 
                cx_write(bus->reg_addr, msg->addr << 25);
212
 
                cx_write(bus->reg_ctrl, ctrl);
213
 
 
214
 
                retval = i2c_wait_done(i2c_adap);
215
 
                if (retval < 0)
216
 
                        goto err;
217
 
                if (retval == 0)
218
 
                        goto eio;
219
 
                msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff;
220
 
 
221
 
                if (i2c_debug) {
222
 
                        dprintk(1, " %02x", msg->buf[cnt]);
223
 
                        if (!(ctrl & I2C_NOSTOP))
224
 
                                dprintk(1, " >\n");
225
 
                }
226
 
        }
227
 
 
228
 
        return msg->len;
229
 
eio:
230
 
        retval = -EIO;
231
 
err:
232
 
        if (i2c_debug)
233
 
                pr_err(" ERR: %d\n", retval);
234
 
        return retval;
235
 
}
236
 
 
237
 
static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
238
 
{
239
 
        struct cx25821_i2c *bus = i2c_adap->algo_data;
240
 
        struct cx25821_dev *dev = bus->dev;
241
 
        int i, retval = 0;
242
 
 
243
 
        dprintk(1, "%s(num = %d)\n", __func__, num);
244
 
 
245
 
        for (i = 0; i < num; i++) {
246
 
                dprintk(1, "%s(num = %d) addr = 0x%02x  len = 0x%x\n",
247
 
                        __func__, num, msgs[i].addr, msgs[i].len);
248
 
 
249
 
                if (msgs[i].flags & I2C_M_RD) {
250
 
                        /* read */
251
 
                        retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
252
 
                } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
253
 
                           msgs[i].addr == msgs[i + 1].addr) {
254
 
                        /* write then read from same address */
255
 
                        retval =
256
 
                            i2c_sendbytes(i2c_adap, &msgs[i], msgs[i + 1].len);
257
 
 
258
 
                        if (retval < 0)
259
 
                                goto err;
260
 
                        i++;
261
 
                        retval = i2c_readbytes(i2c_adap, &msgs[i], 1);
262
 
                } else {
263
 
                        /* write */
264
 
                        retval = i2c_sendbytes(i2c_adap, &msgs[i], 0);
265
 
                }
266
 
 
267
 
                if (retval < 0)
268
 
                        goto err;
269
 
        }
270
 
        return num;
271
 
 
272
 
err:
273
 
        return retval;
274
 
}
275
 
 
276
 
 
277
 
static u32 cx25821_functionality(struct i2c_adapter *adap)
278
 
{
279
 
        return I2C_FUNC_SMBUS_EMUL |
280
 
            I2C_FUNC_I2C |
281
 
            I2C_FUNC_SMBUS_WORD_DATA |
282
 
            I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA;
283
 
}
284
 
 
285
 
static struct i2c_algorithm cx25821_i2c_algo_template = {
286
 
        .master_xfer = i2c_xfer,
287
 
        .functionality = cx25821_functionality,
288
 
#ifdef NEED_ALGO_CONTROL
289
 
        .algo_control = dummy_algo_control,
290
 
#endif
291
 
};
292
 
 
293
 
static struct i2c_adapter cx25821_i2c_adap_template = {
294
 
        .name = "cx25821",
295
 
        .owner = THIS_MODULE,
296
 
        .algo = &cx25821_i2c_algo_template,
297
 
};
298
 
 
299
 
static struct i2c_client cx25821_i2c_client_template = {
300
 
        .name = "cx25821 internal",
301
 
};
302
 
 
303
 
/* init + register i2c algo-bit adapter */
304
 
int cx25821_i2c_register(struct cx25821_i2c *bus)
305
 
{
306
 
        struct cx25821_dev *dev = bus->dev;
307
 
 
308
 
        dprintk(1, "%s(bus = %d)\n", __func__, bus->nr);
309
 
 
310
 
        memcpy(&bus->i2c_adap, &cx25821_i2c_adap_template,
311
 
               sizeof(bus->i2c_adap));
312
 
        memcpy(&bus->i2c_algo, &cx25821_i2c_algo_template,
313
 
               sizeof(bus->i2c_algo));
314
 
        memcpy(&bus->i2c_client, &cx25821_i2c_client_template,
315
 
               sizeof(bus->i2c_client));
316
 
 
317
 
        bus->i2c_adap.dev.parent = &dev->pci->dev;
318
 
 
319
 
        strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name));
320
 
 
321
 
        bus->i2c_algo.data = bus;
322
 
        bus->i2c_adap.algo_data = bus;
323
 
        i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev);
324
 
        i2c_add_adapter(&bus->i2c_adap);
325
 
 
326
 
        bus->i2c_client.adapter = &bus->i2c_adap;
327
 
 
328
 
        /* set up the I2c */
329
 
        bus->i2c_client.addr = (0x88 >> 1);
330
 
 
331
 
        return bus->i2c_rc;
332
 
}
333
 
 
334
 
int cx25821_i2c_unregister(struct cx25821_i2c *bus)
335
 
{
336
 
        i2c_del_adapter(&bus->i2c_adap);
337
 
        return 0;
338
 
}
339
 
 
340
 
void cx25821_av_clk(struct cx25821_dev *dev, int enable)
341
 
{
342
 
        /* write 0 to bus 2 addr 0x144 via i2x_xfer() */
343
 
        char buffer[3];
344
 
        struct i2c_msg msg;
345
 
        dprintk(1, "%s(enabled = %d)\n", __func__, enable);
346
 
 
347
 
        /* Register 0x144 */
348
 
        buffer[0] = 0x01;
349
 
        buffer[1] = 0x44;
350
 
        if (enable == 1)
351
 
                buffer[2] = 0x05;
352
 
        else
353
 
                buffer[2] = 0x00;
354
 
 
355
 
        msg.addr = 0x44;
356
 
        msg.flags = I2C_M_TEN;
357
 
        msg.len = 3;
358
 
        msg.buf = buffer;
359
 
 
360
 
        i2c_xfer(&dev->i2c_bus[0].i2c_adap, &msg, 1);
361
 
}
362
 
 
363
 
int cx25821_i2c_read(struct cx25821_i2c *bus, u16 reg_addr, int *value)
364
 
{
365
 
        struct i2c_client *client = &bus->i2c_client;
366
 
        int retval = 0;
367
 
        int v = 0;
368
 
        u8 addr[2] = { 0, 0 };
369
 
        u8 buf[4] = { 0, 0, 0, 0 };
370
 
 
371
 
        struct i2c_msg msgs[2] = {
372
 
                {
373
 
                 .addr = client->addr,
374
 
                 .flags = 0,
375
 
                 .len = 2,
376
 
                 .buf = addr,
377
 
                 }, {
378
 
                     .addr = client->addr,
379
 
                     .flags = I2C_M_RD,
380
 
                     .len = 4,
381
 
                     .buf = buf,
382
 
                     }
383
 
        };
384
 
 
385
 
        addr[0] = (reg_addr >> 8);
386
 
        addr[1] = (reg_addr & 0xff);
387
 
        msgs[0].addr = 0x44;
388
 
        msgs[1].addr = 0x44;
389
 
 
390
 
        retval = i2c_xfer(client->adapter, msgs, 2);
391
 
 
392
 
        v = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
393
 
        *value = v;
394
 
 
395
 
        return v;
396
 
}
397
 
 
398
 
int cx25821_i2c_write(struct cx25821_i2c *bus, u16 reg_addr, int value)
399
 
{
400
 
        struct i2c_client *client = &bus->i2c_client;
401
 
        int retval = 0;
402
 
        u8 buf[6] = { 0, 0, 0, 0, 0, 0 };
403
 
 
404
 
        struct i2c_msg msgs[1] = {
405
 
                {
406
 
                 .addr = client->addr,
407
 
                 .flags = 0,
408
 
                 .len = 6,
409
 
                 .buf = buf,
410
 
                 }
411
 
        };
412
 
 
413
 
        buf[0] = reg_addr >> 8;
414
 
        buf[1] = reg_addr & 0xff;
415
 
        buf[5] = (value >> 24) & 0xff;
416
 
        buf[4] = (value >> 16) & 0xff;
417
 
        buf[3] = (value >> 8) & 0xff;
418
 
        buf[2] = value & 0xff;
419
 
        client->flags = 0;
420
 
        msgs[0].addr = 0x44;
421
 
 
422
 
        retval = i2c_xfer(client->adapter, msgs, 1);
423
 
 
424
 
        return retval;
425
 
}