Commit | Line | Data |
---|---|---|
ca3355a9 DH |
1 | /* |
2 | Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc. | |
3 | All rights reserved. | |
4 | ||
5 | Redistribution and use in source and binary forms, with or without | |
6 | modification, are permitted provided that the following conditions are met: | |
7 | ||
8 | * Redistributions of source code must retain the above copyright notice, | |
9 | this list of conditions and the following disclaimer. | |
10 | * Redistributions in binary form must reproduce the above copyright notice, | |
11 | this list of conditions and the following disclaimer in the documentation | |
12 | and/or other materials provided with the distribution. | |
13 | * Neither the name of Trident Microsystems nor Hauppauge Computer Works | |
14 | nor the names of its contributors may be used to endorse or promote | |
15 | products derived from this software without specific prior written | |
16 | permission. | |
17 | ||
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
21 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
22 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
23 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
24 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
25 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
26 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
27 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
28 | POSSIBILITY OF SUCH DAMAGE. | |
29 | */ | |
30 | ||
38b2df95 DH |
31 | /******************************************************************************* |
32 | * FILENAME: $Id: drx_dap_fasi.c,v 1.7 2009/12/28 14:36:21 carlo Exp $ | |
33 | * | |
34 | * DESCRIPTION: | |
35 | * Part of DRX driver. | |
36 | * Data access protocol: Fast Access Sequential Interface (fasi) | |
37 | * Fast access, because of short addressing format (16 instead of 32 bits addr) | |
38 | * Sequential, because of I2C. | |
39 | * These functions know how the chip's memory and registers are to be accessed, | |
40 | * but nothing more. | |
41 | * | |
42 | * These functions should not need adapting to a new platform. | |
43 | * | |
44 | * USAGE: | |
45 | * - | |
46 | * | |
47 | * NOTES: | |
38b2df95 DH |
48 | * |
49 | * | |
50 | *******************************************************************************/ | |
51 | ||
52 | #include "drx_dap_fasi.h" | |
57afe2f0 | 53 | #include "drx_driver.h" /* for drxbsp_hst_memcpy() */ |
38b2df95 DH |
54 | |
55 | /*============================================================================*/ | |
56 | ||
57 | /* Function prototypes */ | |
57afe2f0 | 58 | static int drxdap_fasi_write_block(struct i2c_device_addr *dev_addr, /* address of I2C device */ |
1bfc9e15 | 59 | u32 addr, /* address of register/memory */ |
43a431e4 MCC |
60 | u16 datasize, /* size of data */ |
61 | u8 *data, /* data to send */ | |
1bfc9e15 | 62 | u32 flags); /* special device flags */ |
443f18d0 | 63 | |
57afe2f0 | 64 | static int drxdap_fasi_read_block(struct i2c_device_addr *dev_addr, /* address of I2C device */ |
1bfc9e15 | 65 | u32 addr, /* address of register/memory */ |
43a431e4 MCC |
66 | u16 datasize, /* size of data */ |
67 | u8 *data, /* data to send */ | |
1bfc9e15 | 68 | u32 flags); /* special device flags */ |
443f18d0 | 69 | |
57afe2f0 | 70 | static int drxdap_fasi_write_reg8(struct i2c_device_addr *dev_addr, /* address of I2C device */ |
1bfc9e15 | 71 | u32 addr, /* address of register */ |
43a431e4 | 72 | u8 data, /* data to write */ |
1bfc9e15 | 73 | u32 flags); /* special device flags */ |
443f18d0 | 74 | |
57afe2f0 | 75 | static int drxdap_fasi_read_reg8(struct i2c_device_addr *dev_addr, /* address of I2C device */ |
1bfc9e15 | 76 | u32 addr, /* address of register */ |
43a431e4 | 77 | u8 *data, /* buffer to receive data */ |
1bfc9e15 | 78 | u32 flags); /* special device flags */ |
443f18d0 | 79 | |
57afe2f0 | 80 | static int drxdap_fasi_read_modify_write_reg8(struct i2c_device_addr *dev_addr, /* address of I2C device */ |
1bfc9e15 MCC |
81 | u32 waddr, /* address of register */ |
82 | u32 raddr, /* address to read back from */ | |
43a431e4 MCC |
83 | u8 datain, /* data to send */ |
84 | u8 *dataout); /* data to receive back */ | |
443f18d0 | 85 | |
57afe2f0 | 86 | static int drxdap_fasi_write_reg16(struct i2c_device_addr *dev_addr, /* address of I2C device */ |
1bfc9e15 | 87 | u32 addr, /* address of register */ |
43a431e4 | 88 | u16 data, /* data to write */ |
1bfc9e15 | 89 | u32 flags); /* special device flags */ |
443f18d0 | 90 | |
57afe2f0 | 91 | static int drxdap_fasi_read_reg16(struct i2c_device_addr *dev_addr, /* address of I2C device */ |
1bfc9e15 | 92 | u32 addr, /* address of register */ |
43a431e4 | 93 | u16 *data, /* buffer to receive data */ |
1bfc9e15 | 94 | u32 flags); /* special device flags */ |
443f18d0 | 95 | |
57afe2f0 | 96 | static int drxdap_fasi_read_modify_write_reg16(struct i2c_device_addr *dev_addr, /* address of I2C device */ |
1bfc9e15 MCC |
97 | u32 waddr, /* address of register */ |
98 | u32 raddr, /* address to read back from */ | |
43a431e4 MCC |
99 | u16 datain, /* data to send */ |
100 | u16 *dataout); /* data to receive back */ | |
443f18d0 | 101 | |
57afe2f0 | 102 | static int drxdap_fasi_write_reg32(struct i2c_device_addr *dev_addr, /* address of I2C device */ |
1bfc9e15 | 103 | u32 addr, /* address of register */ |
43a431e4 | 104 | u32 data, /* data to write */ |
1bfc9e15 | 105 | u32 flags); /* special device flags */ |
443f18d0 | 106 | |
57afe2f0 | 107 | static int drxdap_fasi_read_reg32(struct i2c_device_addr *dev_addr, /* address of I2C device */ |
1bfc9e15 | 108 | u32 addr, /* address of register */ |
43a431e4 | 109 | u32 *data, /* buffer to receive data */ |
1bfc9e15 | 110 | u32 flags); /* special device flags */ |
443f18d0 | 111 | |
57afe2f0 | 112 | static int drxdap_fasi_read_modify_write_reg32(struct i2c_device_addr *dev_addr, /* address of I2C device */ |
1bfc9e15 MCC |
113 | u32 waddr, /* address of register */ |
114 | u32 raddr, /* address to read back from */ | |
43a431e4 MCC |
115 | u32 datain, /* data to send */ |
116 | u32 *dataout); /* data to receive back */ | |
38b2df95 DH |
117 | |
118 | /* The version structure of this protocol implementation */ | |
57afe2f0 MCC |
119 | char drx_dap_fasi_module_name[] = "FASI Data Access Protocol"; |
120 | char drx_dap_fasi_version_text[] = ""; | |
38b2df95 | 121 | |
1bfc9e15 | 122 | struct drx_version drx_dap_fasi_version = { |
443f18d0 | 123 | DRX_MODULE_DAP, /**< type identifier of the module */ |
57afe2f0 | 124 | drx_dap_fasi_module_name, /**< name or description of module */ |
38b2df95 | 125 | |
443f18d0 MCC |
126 | 0, /**< major version number */ |
127 | 0, /**< minor version number */ | |
128 | 0, /**< patch version number */ | |
57afe2f0 | 129 | drx_dap_fasi_version_text /**< version as text string */ |
38b2df95 DH |
130 | }; |
131 | ||
132 | /* The structure containing the protocol interface */ | |
1bfc9e15 | 133 | struct drx_access_func drx_dap_fasi_funct_g = { |
57afe2f0 MCC |
134 | &drx_dap_fasi_version, |
135 | drxdap_fasi_write_block, /* Supported */ | |
136 | drxdap_fasi_read_block, /* Supported */ | |
137 | drxdap_fasi_write_reg8, /* Not supported */ | |
138 | drxdap_fasi_read_reg8, /* Not supported */ | |
139 | drxdap_fasi_read_modify_write_reg8, /* Not supported */ | |
140 | drxdap_fasi_write_reg16, /* Supported */ | |
141 | drxdap_fasi_read_reg16, /* Supported */ | |
142 | drxdap_fasi_read_modify_write_reg16, /* Supported */ | |
143 | drxdap_fasi_write_reg32, /* Supported */ | |
144 | drxdap_fasi_read_reg32, /* Supported */ | |
145 | drxdap_fasi_read_modify_write_reg32 /* Not supported */ | |
38b2df95 DH |
146 | }; |
147 | ||
148 | /*============================================================================*/ | |
149 | ||
150 | /* Functions not supported by protocol*/ | |
151 | ||
57afe2f0 | 152 | static int drxdap_fasi_write_reg8(struct i2c_device_addr *dev_addr, /* address of I2C device */ |
1bfc9e15 | 153 | u32 addr, /* address of register */ |
43a431e4 | 154 | u8 data, /* data to write */ |
1bfc9e15 | 155 | u32 flags) |
443f18d0 MCC |
156 | { /* special device flags */ |
157 | return DRX_STS_ERROR; | |
38b2df95 DH |
158 | } |
159 | ||
57afe2f0 | 160 | static int drxdap_fasi_read_reg8(struct i2c_device_addr *dev_addr, /* address of I2C device */ |
1bfc9e15 | 161 | u32 addr, /* address of register */ |
43a431e4 | 162 | u8 *data, /* buffer to receive data */ |
1bfc9e15 | 163 | u32 flags) |
443f18d0 MCC |
164 | { /* special device flags */ |
165 | return DRX_STS_ERROR; | |
38b2df95 DH |
166 | } |
167 | ||
57afe2f0 | 168 | static int drxdap_fasi_read_modify_write_reg8(struct i2c_device_addr *dev_addr, /* address of I2C device */ |
1bfc9e15 MCC |
169 | u32 waddr, /* address of register */ |
170 | u32 raddr, /* address to read back from */ | |
43a431e4 MCC |
171 | u8 datain, /* data to send */ |
172 | u8 *dataout) | |
443f18d0 MCC |
173 | { /* data to receive back */ |
174 | return DRX_STS_ERROR; | |
38b2df95 DH |
175 | } |
176 | ||
57afe2f0 | 177 | static int drxdap_fasi_read_modify_write_reg32(struct i2c_device_addr *dev_addr, /* address of I2C device */ |
1bfc9e15 MCC |
178 | u32 waddr, /* address of register */ |
179 | u32 raddr, /* address to read back from */ | |
43a431e4 MCC |
180 | u32 datain, /* data to send */ |
181 | u32 *dataout) | |
443f18d0 MCC |
182 | { /* data to receive back */ |
183 | return DRX_STS_ERROR; | |
38b2df95 DH |
184 | } |
185 | ||
186 | /*============================================================================*/ | |
187 | ||
188 | /****************************** | |
189 | * | |
57afe2f0 MCC |
190 | * int drxdap_fasi_read_block ( |
191 | * struct i2c_device_addr *dev_addr, -- address of I2C device | |
1bfc9e15 | 192 | * u32 addr, -- address of chip register/memory |
43a431e4 MCC |
193 | * u16 datasize, -- number of bytes to read |
194 | * u8 *data, -- data to receive | |
1bfc9e15 | 195 | * u32 flags) -- special device flags |
38b2df95 DH |
196 | * |
197 | * Read block data from chip address. Because the chip is word oriented, | |
198 | * the number of bytes to read must be even. | |
199 | * | |
200 | * Make sure that the buffer to receive the data is large enough. | |
201 | * | |
202 | * Although this function expects an even number of bytes, it is still byte | |
203 | * oriented, and the data read back is NOT translated to the endianness of | |
204 | * the target platform. | |
205 | * | |
206 | * Output: | |
207 | * - DRX_STS_OK if reading was successful | |
208 | * in that case: data read is in *data. | |
209 | * - DRX_STS_ERROR if anything went wrong | |
210 | * | |
211 | ******************************/ | |
212 | ||
57afe2f0 | 213 | static int drxdap_fasi_read_block(struct i2c_device_addr *dev_addr, |
1bfc9e15 | 214 | u32 addr, |
43a431e4 | 215 | u16 datasize, |
1bfc9e15 | 216 | u8 *data, u32 flags) |
38b2df95 | 217 | { |
43a431e4 MCC |
218 | u8 buf[4]; |
219 | u16 bufx; | |
61263c75 | 220 | int rc; |
57afe2f0 | 221 | u16 overhead_size = 0; |
443f18d0 MCC |
222 | |
223 | /* Check parameters ******************************************************* */ | |
57afe2f0 | 224 | if (dev_addr == NULL) { |
443f18d0 MCC |
225 | return DRX_STS_INVALID_ARG; |
226 | } | |
227 | ||
57afe2f0 | 228 | overhead_size = (IS_I2C_10BIT(dev_addr->i2c_addr) ? 2 : 1) + |
443f18d0 MCC |
229 | (DRXDAP_FASI_LONG_FORMAT(addr) ? 4 : 2); |
230 | ||
231 | if ((DRXDAP_FASI_OFFSET_TOO_LARGE(addr)) || | |
232 | ((!(DRXDAPFASI_LONG_ADDR_ALLOWED)) && | |
233 | DRXDAP_FASI_LONG_FORMAT(addr)) || | |
57afe2f0 | 234 | (overhead_size > (DRXDAP_MAX_WCHUNKSIZE)) || |
443f18d0 MCC |
235 | ((datasize != 0) && (data == NULL)) || ((datasize & 1) == 1)) { |
236 | return DRX_STS_INVALID_ARG; | |
237 | } | |
238 | ||
239 | /* ReadModifyWrite & mode flag bits are not allowed */ | |
240 | flags &= (~DRXDAP_FASI_RMW & ~DRXDAP_FASI_MODEFLAGS); | |
38b2df95 | 241 | #if DRXDAP_SINGLE_MASTER |
443f18d0 | 242 | flags |= DRXDAP_FASI_SINGLE_MASTER; |
38b2df95 DH |
243 | #endif |
244 | ||
443f18d0 MCC |
245 | /* Read block from I2C **************************************************** */ |
246 | do { | |
43a431e4 | 247 | u16 todo = (datasize < DRXDAP_MAX_RCHUNKSIZE ? |
443f18d0 | 248 | datasize : DRXDAP_MAX_RCHUNKSIZE); |
38b2df95 | 249 | |
443f18d0 | 250 | bufx = 0; |
38b2df95 | 251 | |
443f18d0 MCC |
252 | addr &= ~DRXDAP_FASI_FLAGS; |
253 | addr |= flags; | |
38b2df95 | 254 | |
22892268 MCC |
255 | #if ((DRXDAPFASI_LONG_ADDR_ALLOWED == 1) && \ |
256 | (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1)) | |
443f18d0 MCC |
257 | /* short format address preferred but long format otherwise */ |
258 | if (DRXDAP_FASI_LONG_FORMAT(addr)) { | |
38b2df95 | 259 | #endif |
7ef66759 | 260 | #if (DRXDAPFASI_LONG_ADDR_ALLOWED == 1) |
43a431e4 MCC |
261 | buf[bufx++] = (u8) (((addr << 1) & 0xFF) | 0x01); |
262 | buf[bufx++] = (u8) ((addr >> 16) & 0xFF); | |
263 | buf[bufx++] = (u8) ((addr >> 24) & 0xFF); | |
264 | buf[bufx++] = (u8) ((addr >> 7) & 0xFF); | |
38b2df95 | 265 | #endif |
22892268 MCC |
266 | #if ((DRXDAPFASI_LONG_ADDR_ALLOWED == 1) && \ |
267 | (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1)) | |
443f18d0 | 268 | } else { |
38b2df95 | 269 | #endif |
7ef66759 | 270 | #if (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1) |
43a431e4 | 271 | buf[bufx++] = (u8) ((addr << 1) & 0xFF); |
443f18d0 | 272 | buf[bufx++] = |
43a431e4 | 273 | (u8) (((addr >> 16) & 0x0F) | |
443f18d0 | 274 | ((addr >> 18) & 0xF0)); |
38b2df95 | 275 | #endif |
22892268 MCC |
276 | #if ((DRXDAPFASI_LONG_ADDR_ALLOWED == 1) && \ |
277 | (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1)) | |
443f18d0 | 278 | } |
38b2df95 DH |
279 | #endif |
280 | ||
38b2df95 | 281 | #if DRXDAP_SINGLE_MASTER |
443f18d0 MCC |
282 | /* |
283 | * In single master mode, split the read and write actions. | |
284 | * No special action is needed for write chunks here. | |
285 | */ | |
57afe2f0 | 286 | rc = drxbsp_i2c_write_read(dev_addr, bufx, buf, 0, 0, 0); |
63713517 | 287 | if (rc == DRX_STS_OK) |
57afe2f0 | 288 | rc = drxbsp_i2c_write_read(0, 0, 0, dev_addr, todo, data); |
38b2df95 | 289 | #else |
443f18d0 | 290 | /* In multi master mode, do everything in one RW action */ |
57afe2f0 | 291 | rc = drxbsp_i2c_write_read(dev_addr, bufx, buf, dev_addr, todo, |
443f18d0 | 292 | data); |
38b2df95 | 293 | #endif |
443f18d0 MCC |
294 | data += todo; |
295 | addr += (todo >> 1); | |
296 | datasize -= todo; | |
297 | } while (datasize && rc == DRX_STS_OK); | |
38b2df95 | 298 | |
443f18d0 | 299 | return rc; |
38b2df95 DH |
300 | } |
301 | ||
38b2df95 DH |
302 | /****************************** |
303 | * | |
57afe2f0 MCC |
304 | * int drxdap_fasi_read_modify_write_reg16 ( |
305 | * struct i2c_device_addr *dev_addr, -- address of I2C device | |
1bfc9e15 MCC |
306 | * u32 waddr, -- address of chip register/memory |
307 | * u32 raddr, -- chip address to read back from | |
43a431e4 MCC |
308 | * u16 wdata, -- data to send |
309 | * u16 *rdata) -- data to receive back | |
38b2df95 DH |
310 | * |
311 | * Write 16-bit data, then read back the original contents of that location. | |
312 | * Requires long addressing format to be allowed. | |
313 | * | |
314 | * Before sending data, the data is converted to little endian. The | |
315 | * data received back is converted back to the target platform's endianness. | |
316 | * | |
317 | * WARNING: This function is only guaranteed to work if there is one | |
318 | * master on the I2C bus. | |
319 | * | |
320 | * Output: | |
321 | * - DRX_STS_OK if reading was successful | |
322 | * in that case: read back data is at *rdata | |
323 | * - DRX_STS_ERROR if anything went wrong | |
324 | * | |
325 | ******************************/ | |
326 | ||
57afe2f0 | 327 | static int drxdap_fasi_read_modify_write_reg16(struct i2c_device_addr *dev_addr, |
1bfc9e15 MCC |
328 | u32 waddr, |
329 | u32 raddr, | |
43a431e4 | 330 | u16 wdata, u16 *rdata) |
38b2df95 | 331 | { |
61263c75 | 332 | int rc = DRX_STS_ERROR; |
38b2df95 | 333 | |
7ef66759 | 334 | #if (DRXDAPFASI_LONG_ADDR_ALLOWED == 1) |
443f18d0 MCC |
335 | if (rdata == NULL) { |
336 | return DRX_STS_INVALID_ARG; | |
337 | } | |
338 | ||
57afe2f0 | 339 | rc = drxdap_fasi_write_reg16(dev_addr, waddr, wdata, DRXDAP_FASI_RMW); |
63713517 | 340 | if (rc == DRX_STS_OK) |
57afe2f0 | 341 | rc = drxdap_fasi_read_reg16(dev_addr, raddr, rdata, 0); |
38b2df95 DH |
342 | #endif |
343 | ||
443f18d0 | 344 | return rc; |
38b2df95 DH |
345 | } |
346 | ||
38b2df95 DH |
347 | /****************************** |
348 | * | |
57afe2f0 MCC |
349 | * int drxdap_fasi_read_reg16 ( |
350 | * struct i2c_device_addr *dev_addr, -- address of I2C device | |
1bfc9e15 | 351 | * u32 addr, -- address of chip register/memory |
43a431e4 | 352 | * u16 *data, -- data to receive |
1bfc9e15 | 353 | * u32 flags) -- special device flags |
38b2df95 DH |
354 | * |
355 | * Read one 16-bit register or memory location. The data received back is | |
356 | * converted back to the target platform's endianness. | |
357 | * | |
358 | * Output: | |
359 | * - DRX_STS_OK if reading was successful | |
360 | * in that case: read data is at *data | |
361 | * - DRX_STS_ERROR if anything went wrong | |
362 | * | |
363 | ******************************/ | |
364 | ||
57afe2f0 | 365 | static int drxdap_fasi_read_reg16(struct i2c_device_addr *dev_addr, |
1bfc9e15 MCC |
366 | u32 addr, |
367 | u16 *data, u32 flags) | |
38b2df95 | 368 | { |
43a431e4 | 369 | u8 buf[sizeof(*data)]; |
61263c75 | 370 | int rc; |
443f18d0 MCC |
371 | |
372 | if (!data) { | |
373 | return DRX_STS_INVALID_ARG; | |
374 | } | |
57afe2f0 | 375 | rc = drxdap_fasi_read_block(dev_addr, addr, sizeof(*data), buf, flags); |
43a431e4 | 376 | *data = buf[0] + (((u16) buf[1]) << 8); |
443f18d0 | 377 | return rc; |
38b2df95 DH |
378 | } |
379 | ||
38b2df95 DH |
380 | /****************************** |
381 | * | |
57afe2f0 MCC |
382 | * int drxdap_fasi_read_reg32 ( |
383 | * struct i2c_device_addr *dev_addr, -- address of I2C device | |
1bfc9e15 | 384 | * u32 addr, -- address of chip register/memory |
43a431e4 | 385 | * u32 *data, -- data to receive |
1bfc9e15 | 386 | * u32 flags) -- special device flags |
38b2df95 DH |
387 | * |
388 | * Read one 32-bit register or memory location. The data received back is | |
389 | * converted back to the target platform's endianness. | |
390 | * | |
391 | * Output: | |
392 | * - DRX_STS_OK if reading was successful | |
393 | * in that case: read data is at *data | |
394 | * - DRX_STS_ERROR if anything went wrong | |
395 | * | |
396 | ******************************/ | |
397 | ||
57afe2f0 | 398 | static int drxdap_fasi_read_reg32(struct i2c_device_addr *dev_addr, |
1bfc9e15 MCC |
399 | u32 addr, |
400 | u32 *data, u32 flags) | |
38b2df95 | 401 | { |
43a431e4 | 402 | u8 buf[sizeof(*data)]; |
61263c75 | 403 | int rc; |
443f18d0 MCC |
404 | |
405 | if (!data) { | |
406 | return DRX_STS_INVALID_ARG; | |
407 | } | |
57afe2f0 | 408 | rc = drxdap_fasi_read_block(dev_addr, addr, sizeof(*data), buf, flags); |
43a431e4 MCC |
409 | *data = (((u32) buf[0]) << 0) + |
410 | (((u32) buf[1]) << 8) + | |
411 | (((u32) buf[2]) << 16) + (((u32) buf[3]) << 24); | |
443f18d0 | 412 | return rc; |
38b2df95 DH |
413 | } |
414 | ||
38b2df95 DH |
415 | /****************************** |
416 | * | |
57afe2f0 MCC |
417 | * int drxdap_fasi_write_block ( |
418 | * struct i2c_device_addr *dev_addr, -- address of I2C device | |
1bfc9e15 | 419 | * u32 addr, -- address of chip register/memory |
43a431e4 MCC |
420 | * u16 datasize, -- number of bytes to read |
421 | * u8 *data, -- data to receive | |
1bfc9e15 | 422 | * u32 flags) -- special device flags |
38b2df95 DH |
423 | * |
424 | * Write block data to chip address. Because the chip is word oriented, | |
425 | * the number of bytes to write must be even. | |
426 | * | |
427 | * Although this function expects an even number of bytes, it is still byte | |
428 | * oriented, and the data being written is NOT translated from the endianness of | |
429 | * the target platform. | |
430 | * | |
431 | * Output: | |
432 | * - DRX_STS_OK if writing was successful | |
433 | * - DRX_STS_ERROR if anything went wrong | |
434 | * | |
435 | ******************************/ | |
436 | ||
57afe2f0 | 437 | static int drxdap_fasi_write_block(struct i2c_device_addr *dev_addr, |
1bfc9e15 | 438 | u32 addr, |
43a431e4 | 439 | u16 datasize, |
1bfc9e15 | 440 | u8 *data, u32 flags) |
38b2df95 | 441 | { |
43a431e4 | 442 | u8 buf[DRXDAP_MAX_WCHUNKSIZE]; |
61263c75 | 443 | int st = DRX_STS_ERROR; |
57afe2f0 MCC |
444 | int first_err = DRX_STS_OK; |
445 | u16 overhead_size = 0; | |
446 | u16 block_size = 0; | |
443f18d0 MCC |
447 | |
448 | /* Check parameters ******************************************************* */ | |
57afe2f0 | 449 | if (dev_addr == NULL) { |
443f18d0 MCC |
450 | return DRX_STS_INVALID_ARG; |
451 | } | |
452 | ||
57afe2f0 | 453 | overhead_size = (IS_I2C_10BIT(dev_addr->i2c_addr) ? 2 : 1) + |
443f18d0 MCC |
454 | (DRXDAP_FASI_LONG_FORMAT(addr) ? 4 : 2); |
455 | ||
456 | if ((DRXDAP_FASI_OFFSET_TOO_LARGE(addr)) || | |
457 | ((!(DRXDAPFASI_LONG_ADDR_ALLOWED)) && | |
458 | DRXDAP_FASI_LONG_FORMAT(addr)) || | |
57afe2f0 | 459 | (overhead_size > (DRXDAP_MAX_WCHUNKSIZE)) || |
443f18d0 MCC |
460 | ((datasize != 0) && (data == NULL)) || ((datasize & 1) == 1)) { |
461 | return DRX_STS_INVALID_ARG; | |
462 | } | |
463 | ||
464 | flags &= DRXDAP_FASI_FLAGS; | |
465 | flags &= ~DRXDAP_FASI_MODEFLAGS; | |
38b2df95 | 466 | #if DRXDAP_SINGLE_MASTER |
443f18d0 | 467 | flags |= DRXDAP_FASI_SINGLE_MASTER; |
38b2df95 DH |
468 | #endif |
469 | ||
443f18d0 | 470 | /* Write block to I2C ***************************************************** */ |
57afe2f0 | 471 | block_size = ((DRXDAP_MAX_WCHUNKSIZE) - overhead_size) & ~1; |
443f18d0 | 472 | do { |
43a431e4 MCC |
473 | u16 todo = 0; |
474 | u16 bufx = 0; | |
38b2df95 | 475 | |
443f18d0 MCC |
476 | /* Buffer device address */ |
477 | addr &= ~DRXDAP_FASI_FLAGS; | |
478 | addr |= flags; | |
22892268 MCC |
479 | #if (((DRXDAPFASI_LONG_ADDR_ALLOWED) == 1) && \ |
480 | ((DRXDAPFASI_SHORT_ADDR_ALLOWED) == 1)) | |
443f18d0 MCC |
481 | /* short format address preferred but long format otherwise */ |
482 | if (DRXDAP_FASI_LONG_FORMAT(addr)) { | |
38b2df95 | 483 | #endif |
7ef66759 | 484 | #if ((DRXDAPFASI_LONG_ADDR_ALLOWED) == 1) |
43a431e4 MCC |
485 | buf[bufx++] = (u8) (((addr << 1) & 0xFF) | 0x01); |
486 | buf[bufx++] = (u8) ((addr >> 16) & 0xFF); | |
487 | buf[bufx++] = (u8) ((addr >> 24) & 0xFF); | |
488 | buf[bufx++] = (u8) ((addr >> 7) & 0xFF); | |
38b2df95 | 489 | #endif |
22892268 MCC |
490 | #if (((DRXDAPFASI_LONG_ADDR_ALLOWED) == 1) && \ |
491 | ((DRXDAPFASI_SHORT_ADDR_ALLOWED) == 1)) | |
443f18d0 | 492 | } else { |
38b2df95 | 493 | #endif |
7ef66759 | 494 | #if ((DRXDAPFASI_SHORT_ADDR_ALLOWED) == 1) |
43a431e4 | 495 | buf[bufx++] = (u8) ((addr << 1) & 0xFF); |
443f18d0 | 496 | buf[bufx++] = |
43a431e4 | 497 | (u8) (((addr >> 16) & 0x0F) | |
443f18d0 | 498 | ((addr >> 18) & 0xF0)); |
38b2df95 | 499 | #endif |
22892268 MCC |
500 | #if (((DRXDAPFASI_LONG_ADDR_ALLOWED) == 1) && \ |
501 | ((DRXDAPFASI_SHORT_ADDR_ALLOWED) == 1)) | |
443f18d0 | 502 | } |
38b2df95 DH |
503 | #endif |
504 | ||
443f18d0 | 505 | /* |
57afe2f0 | 506 | In single master mode block_size can be 0. In such a case this I2C |
443f18d0 MCC |
507 | sequense will be visible: (1) write address {i2c addr, |
508 | 4 bytes chip address} (2) write data {i2c addr, 4 bytes data } | |
509 | (3) write address (4) write data etc... | |
510 | Addres must be rewriten because HI is reset after data transport and | |
511 | expects an address. | |
512 | */ | |
57afe2f0 | 513 | todo = (block_size < datasize ? block_size : datasize); |
443f18d0 | 514 | if (todo == 0) { |
e33f2193 | 515 | u16 overhead_size_i2c_addr = 0; |
57afe2f0 | 516 | u16 data_block_size = 0; |
443f18d0 | 517 | |
e33f2193 | 518 | overhead_size_i2c_addr = |
57afe2f0 MCC |
519 | (IS_I2C_10BIT(dev_addr->i2c_addr) ? 2 : 1); |
520 | data_block_size = | |
e33f2193 | 521 | (DRXDAP_MAX_WCHUNKSIZE - overhead_size_i2c_addr) & ~1; |
443f18d0 MCC |
522 | |
523 | /* write device address */ | |
57afe2f0 | 524 | st = drxbsp_i2c_write_read(dev_addr, |
43a431e4 | 525 | (u16) (bufx), |
443f18d0 | 526 | buf, |
22892268 MCC |
527 | (struct i2c_device_addr *)(NULL), |
528 | 0, (u8 *)(NULL)); | |
443f18d0 | 529 | |
57afe2f0 | 530 | if ((st != DRX_STS_OK) && (first_err == DRX_STS_OK)) { |
443f18d0 | 531 | /* at the end, return the first error encountered */ |
57afe2f0 | 532 | first_err = st; |
443f18d0 MCC |
533 | } |
534 | bufx = 0; | |
535 | todo = | |
57afe2f0 MCC |
536 | (data_block_size < |
537 | datasize ? data_block_size : datasize); | |
443f18d0 | 538 | } |
57afe2f0 | 539 | drxbsp_hst_memcpy(&buf[bufx], data, todo); |
443f18d0 | 540 | /* write (address if can do and) data */ |
57afe2f0 | 541 | st = drxbsp_i2c_write_read(dev_addr, |
43a431e4 | 542 | (u16) (bufx + todo), |
443f18d0 | 543 | buf, |
22892268 MCC |
544 | (struct i2c_device_addr *)(NULL), |
545 | 0, (u8 *)(NULL)); | |
443f18d0 | 546 | |
57afe2f0 | 547 | if ((st != DRX_STS_OK) && (first_err == DRX_STS_OK)) { |
443f18d0 | 548 | /* at the end, return the first error encountered */ |
57afe2f0 | 549 | first_err = st; |
443f18d0 MCC |
550 | } |
551 | datasize -= todo; | |
552 | data += todo; | |
553 | addr += (todo >> 1); | |
554 | } while (datasize); | |
555 | ||
57afe2f0 | 556 | return first_err; |
38b2df95 DH |
557 | } |
558 | ||
38b2df95 DH |
559 | /****************************** |
560 | * | |
57afe2f0 MCC |
561 | * int drxdap_fasi_write_reg16 ( |
562 | * struct i2c_device_addr *dev_addr, -- address of I2C device | |
1bfc9e15 | 563 | * u32 addr, -- address of chip register/memory |
43a431e4 | 564 | * u16 data, -- data to send |
1bfc9e15 | 565 | * u32 flags) -- special device flags |
38b2df95 DH |
566 | * |
567 | * Write one 16-bit register or memory location. The data being written is | |
568 | * converted from the target platform's endianness to little endian. | |
569 | * | |
570 | * Output: | |
571 | * - DRX_STS_OK if writing was successful | |
572 | * - DRX_STS_ERROR if anything went wrong | |
573 | * | |
574 | ******************************/ | |
575 | ||
57afe2f0 | 576 | static int drxdap_fasi_write_reg16(struct i2c_device_addr *dev_addr, |
1bfc9e15 MCC |
577 | u32 addr, |
578 | u16 data, u32 flags) | |
38b2df95 | 579 | { |
43a431e4 | 580 | u8 buf[sizeof(data)]; |
38b2df95 | 581 | |
43a431e4 MCC |
582 | buf[0] = (u8) ((data >> 0) & 0xFF); |
583 | buf[1] = (u8) ((data >> 8) & 0xFF); | |
38b2df95 | 584 | |
57afe2f0 | 585 | return drxdap_fasi_write_block(dev_addr, addr, sizeof(data), buf, flags); |
38b2df95 DH |
586 | } |
587 | ||
38b2df95 DH |
588 | /****************************** |
589 | * | |
57afe2f0 MCC |
590 | * int drxdap_fasi_write_reg32 ( |
591 | * struct i2c_device_addr *dev_addr, -- address of I2C device | |
1bfc9e15 | 592 | * u32 addr, -- address of chip register/memory |
43a431e4 | 593 | * u32 data, -- data to send |
1bfc9e15 | 594 | * u32 flags) -- special device flags |
38b2df95 DH |
595 | * |
596 | * Write one 32-bit register or memory location. The data being written is | |
597 | * converted from the target platform's endianness to little endian. | |
598 | * | |
599 | * Output: | |
600 | * - DRX_STS_OK if writing was successful | |
601 | * - DRX_STS_ERROR if anything went wrong | |
602 | * | |
603 | ******************************/ | |
604 | ||
57afe2f0 | 605 | static int drxdap_fasi_write_reg32(struct i2c_device_addr *dev_addr, |
1bfc9e15 MCC |
606 | u32 addr, |
607 | u32 data, u32 flags) | |
38b2df95 | 608 | { |
43a431e4 | 609 | u8 buf[sizeof(data)]; |
38b2df95 | 610 | |
43a431e4 MCC |
611 | buf[0] = (u8) ((data >> 0) & 0xFF); |
612 | buf[1] = (u8) ((data >> 8) & 0xFF); | |
613 | buf[2] = (u8) ((data >> 16) & 0xFF); | |
614 | buf[3] = (u8) ((data >> 24) & 0xFF); | |
38b2df95 | 615 | |
57afe2f0 | 616 | return drxdap_fasi_write_block(dev_addr, addr, sizeof(data), buf, flags); |
38b2df95 | 617 | } |