1 /***********************license start***************
2 * Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * * Neither the name of Cavium Networks nor the names of
19 * its contributors may be used to endorse or promote products
20 * derived from this software without specific prior written
23 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
24 * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
25 * OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
26 * RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
27 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
28 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
29 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
30 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
31 * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT
32 * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
35 * For any questions regarding licensing please contact marketing@caviumnetworks.com
37 ***********************license end**************************************/
47 * Interface to the TWSI / I2C bus
49 * <hr>$Revision: 41586 $<hr>
54 #include "cvmx-twsi.h"
61 * Do a twsi read from a 7 bit device address using an (optional) internal address.
62 * Up to 8 bytes can be read at a time.
64 * @param twsi_id which Octeon TWSI bus to use
65 * @param dev_addr Device address (7 bit)
66 * @param internal_addr
67 * Internal address. Can be 0, 1 or 2 bytes in width
68 * @param num_bytes Number of data bytes to read
69 * @param ia_width_bytes
70 * Internal address size in bytes (0, 1, or 2)
71 * @param data Pointer argument where the read data is returned.
73 * @return read data returned in 'data' argument
74 * Number of bytes read on success
77 int cvmx_twsix_read_ia(int twsi_id, uint8_t dev_addr, uint16_t internal_addr, int num_bytes, int ia_width_bytes, uint64_t *data)
79 cvmx_mio_twsx_sw_twsi_t sw_twsi_val;
80 cvmx_mio_twsx_sw_twsi_ext_t twsi_ext;
82 if (num_bytes < 1 || num_bytes > 8 || !data || ia_width_bytes < 0 || ia_width_bytes > 2)
89 sw_twsi_val.s.sovr = 1;
90 sw_twsi_val.s.size = num_bytes - 1;
91 sw_twsi_val.s.a = dev_addr;
93 if (ia_width_bytes > 0)
96 sw_twsi_val.s.ia = (internal_addr >> 3) & 0x1f;
97 sw_twsi_val.s.eop_ia = internal_addr & 0x7;
99 if (ia_width_bytes == 2)
101 sw_twsi_val.s.eia = 1;
102 twsi_ext.s.ia = internal_addr >> 8;
103 cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u64);
106 cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64);
107 while (((cvmx_mio_twsx_sw_twsi_t)(sw_twsi_val.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id)))).s.v)
109 if (!sw_twsi_val.s.r)
112 *data = (sw_twsi_val.s.d & (0xFFFFFFFF >> (32 - num_bytes*8)));
115 twsi_ext.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id));
116 *data |= ((unsigned long long)(twsi_ext.s.d & (0xFFFFFFFF >> (32 - num_bytes*8))) << 32);
126 * Read from a TWSI device (7 bit device address only) without generating any
127 * internal addresses.
128 * Read from 1-8 bytes and returns them in the data pointer.
130 * @param twsi_id TWSI interface on Octeon to use
131 * @param dev_addr TWSI device address (7 bit only)
132 * @param num_bytes number of bytes to read
133 * @param data Pointer to data read from TWSI device
135 * @return Number of bytes read on success
138 int cvmx_twsix_read(int twsi_id, uint8_t dev_addr, int num_bytes, uint64_t *data)
140 cvmx_mio_twsx_sw_twsi_t sw_twsi_val;
141 cvmx_mio_twsx_sw_twsi_ext_t twsi_ext;
143 if (num_bytes > 8 || num_bytes < 1)
149 sw_twsi_val.s.a = dev_addr;
150 sw_twsi_val.s.sovr = 1;
151 sw_twsi_val.s.size = num_bytes - 1;
153 cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64);
154 while (((cvmx_mio_twsx_sw_twsi_t)(sw_twsi_val.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id)))).s.v)
156 if (!sw_twsi_val.s.r)
159 *data = (sw_twsi_val.s.d & (0xFFFFFFFF >> (32 - num_bytes*8)));
162 twsi_ext.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id));
163 *data |= ((unsigned long long)(twsi_ext.s.d & (0xFFFFFFFF >> (32 - num_bytes*8))) << 32);
171 * Perform a twsi write operation to a 7 bit device address.
173 * Note that many eeprom devices have page restrictions regarding address boundaries
174 * that can be crossed in one write operation. This is device dependent, and this routine
175 * does nothing in this regard.
176 * This command does not generate any internal addressess.
178 * @param twsi_id Octeon TWSI interface to use
179 * @param dev_addr TWSI device address
180 * @param num_bytes Number of bytes to write (between 1 and 8 inclusive)
181 * @param data Data to write
183 * @return 0 on success
186 int cvmx_twsix_write(int twsi_id, uint8_t dev_addr, int num_bytes, uint64_t data)
188 cvmx_mio_twsx_sw_twsi_t sw_twsi_val;
190 if (num_bytes > 8 || num_bytes < 1)
195 sw_twsi_val.s.a = dev_addr;
196 sw_twsi_val.s.d = data & 0xffffffff;
197 sw_twsi_val.s.sovr = 1;
198 sw_twsi_val.s.size = num_bytes - 1;
201 /* Upper four bytes go into a separate register */
202 cvmx_mio_twsx_sw_twsi_ext_t twsi_ext;
204 twsi_ext.s.d = data >> 32;
205 cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u64);
207 cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64);
208 while (((cvmx_mio_twsx_sw_twsi_t)(sw_twsi_val.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id)))).s.v)
210 if (!sw_twsi_val.s.r)
217 * Write 1-8 bytes to a TWSI device using an internal address.
219 * @param twsi_id which TWSI interface on Octeon to use
220 * @param dev_addr TWSI device address (7 bit only)
221 * @param internal_addr
222 * TWSI internal address (0, 8, or 16 bits)
223 * @param num_bytes Number of bytes to write (1-8)
224 * @param ia_width_bytes
225 * internal address width, in bytes (0, 1, 2)
226 * @param data Data to write. Data is written MSB first on the twsi bus, and only the lower
227 * num_bytes bytes of the argument are valid. (If a 2 byte write is done, only
228 * the low 2 bytes of the argument is used.
230 * @return Number of bytes read on success,
233 int cvmx_twsix_write_ia(int twsi_id, uint8_t dev_addr, uint16_t internal_addr, int num_bytes, int ia_width_bytes, uint64_t data)
235 cvmx_mio_twsx_sw_twsi_t sw_twsi_val;
236 cvmx_mio_twsx_sw_twsi_ext_t twsi_ext;
239 if (num_bytes < 1 || num_bytes > 8 || ia_width_bytes < 0 || ia_width_bytes > 2)
246 sw_twsi_val.s.sovr = 1;
247 sw_twsi_val.s.size = num_bytes - 1;
248 sw_twsi_val.s.a = dev_addr;
249 sw_twsi_val.s.d = 0xFFFFFFFF & data;
251 if (ia_width_bytes > 0)
253 sw_twsi_val.s.op = 1;
254 sw_twsi_val.s.ia = (internal_addr >> 3) & 0x1f;
255 sw_twsi_val.s.eop_ia = internal_addr & 0x7;
257 if (ia_width_bytes == 2)
259 sw_twsi_val.s.eia = 1;
260 twsi_ext.s.ia = internal_addr >> 8;
261 cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u64);
264 twsi_ext.s.d = data >> 32;
267 cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u64);
268 cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64);
269 while (((cvmx_mio_twsx_sw_twsi_t)(sw_twsi_val.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id)))).s.v)
272 /* Poll until reads succeed, or polling times out */
277 if (cvmx_twsix_read(twsi_id, dev_addr, 1, &data) >= 0)