blob: e70e91a646c21c443f42025990a7638b96656bcc [file] [log] [blame]
yuezonghe824eb0c2024-06-27 02:32:26 -07001#include <linux/kernel.h>
2#include <linux/module.h>
3
4#include <linux/i2c.h>
5#include <linux/init.h>
6#include <linux/time.h>
7#include <linux/interrupt.h>
8#include <linux/delay.h>
9#include <linux/errno.h>
10#include <linux/err.h>
11#include <linux/platform_device.h>
12#include <linux/clk.h>
13#include <linux/slab.h>
14#include <linux/io.h>
15#include <linux/of_gpio.h>
16#include <linux/clk/zx29-clk.h>
17
18
19#include <asm/irq.h>
20#include <mach/i2c_private.h>
21#include <mach/spinlock.h>
22
23
24#define I2C_FIFO_DEPTH 32
25
26#define MAX_BUS_CLK 400000
27#define MIN_BUS_CLK 100000
28
29#define I2C_WCLK_FREQ (26*1000*1000)
30
31
32
33#define i2c_if_tx_fifo_empty(d) ((zx_read_reg(d->regs+I2C_TXF_STATUS) & WFIFO_EMPTY)>>1)
34#define i2c_if_rx_fifo_full(d) (zx_read_reg(d->regs+I2C_RXF_STATUS) & RFIFO_FULL)
35
36static int zx29_i2c_init(struct zx29_i2c *i2c)
37{
38 unsigned int bus_clk;
39 unsigned int pdiv;
40
41
42 /*reset*/
43 zx29_i2c_reset_fifo(i2c);
44 udelay(1);
45
46 /*calculate bus clock division, fix input clock is 26M*/
47 bus_clk = MIN_BUS_CLK/1000; /*in KHz*/
48 pdiv = ((I2C_WCLK_FREQ/1000)/4)/bus_clk - 1;
49#if 0
50 i2c->clkrate = (I2C_WCLK_FREQ/4)/(pdiv+1); /*actul bus clock rate*/
51
52 if ((i2c->clkrate >MAX_BUS_CLK)||(i2c->clkrate < MIN_BUS_CLK)){
53 printk(KERN_ERR"bus clock rate error!\n");
54 BUG();
55 }
56#endif
57
58 i2c_set_clk_div(i2c, pdiv);
59
60 /*master mode, disable interrupt, clear interrupt*/
61 i2c_set_cmd(i2c, 0x1);
62
63 return 0;
64}
65
66static void zx29_i2c_start(struct zx29_i2c *i2c, struct i2c_msg *msg)
67{
68 unsigned int addr = msg->addr;
69 unsigned long ctrl = 0;
70 unsigned int addr_mode = 0;
71
72 /*set slave device address*/
73 addr_mode = msg->flags & I2C_M_TEN;
74
75 i2c_set_addr(i2c, addr, addr_mode);
76
77 /*set cmd register for rx or tx*/
78 ctrl = i2c_get_cmd(i2c);
79 if (msg->flags & I2C_M_RD) {
80 ctrl |= CMD_I2C_RW;
81 }
82 else{
83 ctrl &= ~CMD_I2C_RW;
84 }
85
86 if (addr_mode){
87 /*10 bit address mode :clear interrupt conditions, set master mode,set 10bit address mode and start*/
88 ctrl |= CMD_I2C_START|CMD_I2C_MODE|CMD_TENBIT_MODE;
89 }
90 else{
91 /*7 bit address mode:clear interrupt conditions, set master mode and start*/
92 ctrl &= ~CMD_TENBIT_MODE;
93 ctrl |= CMD_I2C_START|CMD_I2C_MODE;
94 }
95
96 i2c_set_cmd(i2c, ctrl);
97}
98
99static int zx29_i2c_read(struct zx29_i2c *i2c, struct i2c_msg *msg)
100{
101 u8 *buf = msg->buf;
102 u16 len_rx = 0;
103 unsigned int ret=0;
104 u8 val, msg_ptr = 0;
105
106 if ((msg->len > 0) && (msg->len <= I2C_FIFO_DEPTH))
107 len_rx = msg->len;
108 else
109 return -EINVAL;
110
111 while((ret=i2c_get_bus_status(i2c)));
112
113 zx29_i2c_init(i2c); //zx29_i2c_reset_fifo(i2c);
114
115 i2c_set_rx_fifo_depth(i2c, len_rx-1);
116
117 zx29_i2c_start(i2c, msg);
118
119 while(!i2c_if_rx_fifo_full(i2c));
120
121 while (len_rx--) {
122 val = (u8)i2c_read_data(i2c);
123 *(buf + msg_ptr) = val;
124 msg_ptr++;
125 }
126
127 return 0;
128}
129
130static int zx29_i2c_write(struct zx29_i2c *i2c, struct i2c_msg *msg)
131{
132 u8 val, msg_ptr = 0;
133 u8 *buf = msg->buf;
134 u16 len_tx = 0;
135 unsigned int ret=0;
136
137 if ((msg->len > 0) && (msg->len <= I2C_FIFO_DEPTH))
138 len_tx = msg->len;
139 else
140 return -EINVAL;
141
142 while((ret=i2c_get_bus_status(i2c)));
143
144 zx29_i2c_init(i2c); //zx29_i2c_reset_fifo(i2c);
145
146 i2c_set_tx_fifo_depth(i2c, len_tx-1);
147
148 /*write data to fifo*/
149 while(len_tx--){
150 val = *(buf + msg_ptr);
151 i2c_write_data(i2c, val);
152 msg_ptr++;
153 }
154 barrier();
155
156 zx29_i2c_start(i2c, msg);
157
158 while(!i2c_if_tx_fifo_empty(i2c));
159
160 return 0;
161}
162
163static int zx29_i2c_doxfer(struct zx29_i2c *i2c, struct i2c_msg *msg)
164{
165 int ret;
166
167 if (msg->flags & I2C_M_RD) {
168 ret = zx29_i2c_read(i2c, msg);
169 } else {
170 ret = zx29_i2c_write(i2c, msg);
171 }
172
173 return ret;
174}
175
176int zx29_i2c_xfer_PSM(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
177{
178 struct zx29_i2c *i2c = (struct zx29_i2c *)adap->algo_data;
179 int ret = 0;
180 int i;
181
182 if (msgs->len == 0)
183 return -EINVAL;
184
185// i2c->msg_num = num;
186
187 for (i = 0; i < num; i++) {
188 ret = zx29_i2c_doxfer(i2c, &msgs[i]);
189// i2c->msg_idx=i;
190 if (ret)
191 break;
192 }
193
194 return ret ?: i;
195}