Merge branch 'for-torvalds' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
[pandora-kernel.git] / drivers / video / mb862xx / mb862xx-i2c.c
1 /*
2  * Coral-P(A)/Lime I2C adapter driver
3  *
4  * (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  */
11
12 #include <linux/fb.h>
13 #include <linux/i2c.h>
14 #include <linux/io.h>
15
16 #include "mb862xxfb.h"
17 #include "mb862xx_reg.h"
18
19 static int mb862xx_i2c_wait_event(struct i2c_adapter *adap)
20 {
21         struct mb862xxfb_par *par = adap->algo_data;
22         u32 reg;
23
24         do {
25                 udelay(1);
26                 reg = inreg(i2c, GC_I2C_BCR);
27                 if (reg & (I2C_INT | I2C_BER))
28                         break;
29         } while (1);
30
31         return (reg & I2C_BER) ? 0 : 1;
32 }
33
34 static int mb862xx_i2c_do_address(struct i2c_adapter *adap, int addr)
35 {
36         struct mb862xxfb_par *par = adap->algo_data;
37
38         outreg(i2c, GC_I2C_DAR, addr);
39         outreg(i2c, GC_I2C_CCR, I2C_CLOCK_AND_ENABLE);
40         outreg(i2c, GC_I2C_BCR, par->i2c_rs ? I2C_REPEATED_START : I2C_START);
41         if (!mb862xx_i2c_wait_event(adap))
42                 return -EIO;
43         par->i2c_rs = !(inreg(i2c, GC_I2C_BSR) & I2C_LRB);
44         return par->i2c_rs;
45 }
46
47 static int mb862xx_i2c_write_byte(struct i2c_adapter *adap, u8 byte)
48 {
49         struct mb862xxfb_par *par = adap->algo_data;
50
51         outreg(i2c, GC_I2C_DAR, byte);
52         outreg(i2c, GC_I2C_BCR, I2C_START);
53         if (!mb862xx_i2c_wait_event(adap))
54                 return -EIO;
55         return !(inreg(i2c, GC_I2C_BSR) & I2C_LRB);
56 }
57
58 static int mb862xx_i2c_read_byte(struct i2c_adapter *adap, u8 *byte, int last)
59 {
60         struct mb862xxfb_par *par = adap->algo_data;
61
62         outreg(i2c, GC_I2C_BCR, I2C_START | (last ? 0 : I2C_ACK));
63         if (!mb862xx_i2c_wait_event(adap))
64                 return 0;
65         *byte = inreg(i2c, GC_I2C_DAR);
66         return 1;
67 }
68
69 void mb862xx_i2c_stop(struct i2c_adapter *adap)
70 {
71         struct mb862xxfb_par *par = adap->algo_data;
72
73         outreg(i2c, GC_I2C_BCR, I2C_STOP);
74         outreg(i2c, GC_I2C_CCR, I2C_DISABLE);
75         par->i2c_rs = 0;
76 }
77
78 static int mb862xx_i2c_read(struct i2c_adapter *adap, struct i2c_msg *m)
79 {
80         int i, ret = 0;
81         int last = m->len - 1;
82
83         for (i = 0; i < m->len; i++) {
84                 if (!mb862xx_i2c_read_byte(adap, &m->buf[i], i == last)) {
85                         ret = -EIO;
86                         break;
87                 }
88         }
89         return ret;
90 }
91
92 static int mb862xx_i2c_write(struct i2c_adapter *adap, struct i2c_msg *m)
93 {
94         int i, ret = 0;
95
96         for (i = 0; i < m->len; i++) {
97                 if (!mb862xx_i2c_write_byte(adap, m->buf[i])) {
98                         ret = -EIO;
99                         break;
100                 }
101         }
102         return ret;
103 }
104
105 static int mb862xx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
106                         int num)
107 {
108         struct mb862xxfb_par *par = adap->algo_data;
109         struct i2c_msg *m;
110         int addr;
111         int i = 0, err = 0;
112
113         dev_dbg(par->dev, "%s: %d msgs\n", __func__, num);
114
115         for (i = 0; i < num; i++) {
116                 m = &msgs[i];
117                 if (!m->len) {
118                         dev_dbg(par->dev, "%s: null msgs\n", __func__);
119                         continue;
120                 }
121                 addr = m->addr;
122                 if (m->flags & I2C_M_RD)
123                         addr |= 1;
124
125                 err = mb862xx_i2c_do_address(adap, addr);
126                 if (err < 0)
127                         break;
128                 if (m->flags & I2C_M_RD)
129                         err = mb862xx_i2c_read(adap, m);
130                 else
131                         err = mb862xx_i2c_write(adap, m);
132         }
133
134         if (i)
135                 mb862xx_i2c_stop(adap);
136
137         return (err < 0) ? err : i;
138 }
139
140 static u32 mb862xx_func(struct i2c_adapter *adap)
141 {
142         return I2C_FUNC_SMBUS_BYTE_DATA;
143 }
144
145 static const struct i2c_algorithm mb862xx_algo = {
146         .master_xfer    = mb862xx_xfer,
147         .functionality  = mb862xx_func,
148 };
149
150 static struct i2c_adapter mb862xx_i2c_adapter = {
151         .name           = "MB862xx I2C adapter",
152         .algo           = &mb862xx_algo,
153         .owner          = THIS_MODULE,
154 };
155
156 int mb862xx_i2c_init(struct mb862xxfb_par *par)
157 {
158         int ret;
159
160         mb862xx_i2c_adapter.algo_data = par;
161         par->adap = &mb862xx_i2c_adapter;
162
163         ret = i2c_add_adapter(par->adap);
164         if (ret < 0) {
165                 dev_err(par->dev, "failed to add %s\n",
166                         mb862xx_i2c_adapter.name);
167         }
168         return ret;
169 }
170
171 void mb862xx_i2c_exit(struct mb862xxfb_par *par)
172 {
173         if (par->adap) {
174                 i2c_del_adapter(par->adap);
175                 par->adap = NULL;
176         }
177 }