1210284Sjmallett/***********************license start*************** 2215990Sjmallett * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights 3215990Sjmallett * reserved. 4210284Sjmallett * 5210284Sjmallett * 6215990Sjmallett * Redistribution and use in source and binary forms, with or without 7215990Sjmallett * modification, are permitted provided that the following conditions are 8215990Sjmallett * met: 9210284Sjmallett * 10215990Sjmallett * * Redistributions of source code must retain the above copyright 11215990Sjmallett * notice, this list of conditions and the following disclaimer. 12210284Sjmallett * 13215990Sjmallett * * Redistributions in binary form must reproduce the above 14215990Sjmallett * copyright notice, this list of conditions and the following 15215990Sjmallett * disclaimer in the documentation and/or other materials provided 16215990Sjmallett * with the distribution. 17215990Sjmallett 18215990Sjmallett * * Neither the name of Cavium Networks nor the names of 19215990Sjmallett * its contributors may be used to endorse or promote products 20215990Sjmallett * derived from this software without specific prior written 21215990Sjmallett * permission. 22215990Sjmallett 23215990Sjmallett * This Software, including technical data, may be subject to U.S. export control 24215990Sjmallett * laws, including the U.S. Export Administration Act and its associated 25215990Sjmallett * regulations, and may be subject to export or import regulations in other 26215990Sjmallett * countries. 27215990Sjmallett 28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29215990Sjmallett * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR 30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38210284Sjmallett ***********************license end**************************************/ 39210284Sjmallett 40210284Sjmallett 41210284Sjmallett 42210284Sjmallett 43210284Sjmallett 44210284Sjmallett 45215990Sjmallett 46210284Sjmallett/** 47210284Sjmallett * @file 48210284Sjmallett * 49210284Sjmallett * Interface to the TWSI / I2C bus 50210284Sjmallett * 51215990Sjmallett * <hr>$Revision: 49448 $<hr> 52210284Sjmallett * 53210284Sjmallett */ 54215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 55215990Sjmallett#include <linux/i2c.h> 56210284Sjmallett 57215990Sjmallett#include <asm/octeon/cvmx.h> 58215990Sjmallett#include <asm/octeon/cvmx-twsi.h> 59215990Sjmallett#else 60210284Sjmallett#include "cvmx.h" 61210284Sjmallett#include "cvmx-twsi.h" 62215990Sjmallett#include "cvmx-csr-db.h" 63215990Sjmallett#endif 64210284Sjmallett 65215990Sjmallett//#define PRINT_TWSI_CONFIG 66215990Sjmallett#ifdef PRINT_TWSI_CONFIG 67215990Sjmallett#define twsi_printf printf 68215990Sjmallett#else 69215990Sjmallett#define twsi_printf(...) 70215990Sjmallett#define cvmx_csr_db_decode(...) 71215990Sjmallett#endif 72210284Sjmallett 73215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 74215990Sjmallettstatic struct i2c_adapter *__cvmx_twsix_get_adapter(int twsi_id) 75215990Sjmallett{ 76215990Sjmallett# if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 77215990Sjmallett struct octeon_i2c { 78215990Sjmallett wait_queue_head_t queue; 79215990Sjmallett struct i2c_adapter adap; 80215990Sjmallett int irq; 81215990Sjmallett int twsi_freq; 82215990Sjmallett int sys_freq; 83215990Sjmallett resource_size_t twsi_phys; 84215990Sjmallett void __iomem *twsi_base; 85215990Sjmallett resource_size_t regsize; 86215990Sjmallett struct device *dev; 87215990Sjmallett int broken_irq_mode; 88215990Sjmallett }; 89215990Sjmallett struct i2c_adapter *adapter; 90215990Sjmallett struct octeon_i2c *i2c; 91210284Sjmallett 92215990Sjmallett adapter = i2c_get_adapter(0); 93215990Sjmallett if (adapter == NULL) 94215990Sjmallett return NULL; 95215990Sjmallett i2c = container_of(adapter, struct octeon_i2c, adap); 96215990Sjmallett return &i2c[twsi_id].adap; 97215990Sjmallett#else 98215990Sjmallett return NULL; 99215990Sjmallett#endif 100215990Sjmallett} 101215990Sjmallett#endif 102210284Sjmallett 103210284Sjmallett 104210284Sjmallett/** 105210284Sjmallett * Do a twsi read from a 7 bit device address using an (optional) internal address. 106210284Sjmallett * Up to 8 bytes can be read at a time. 107215990Sjmallett * 108210284Sjmallett * @param twsi_id which Octeon TWSI bus to use 109210284Sjmallett * @param dev_addr Device address (7 bit) 110210284Sjmallett * @param internal_addr 111210284Sjmallett * Internal address. Can be 0, 1 or 2 bytes in width 112210284Sjmallett * @param num_bytes Number of data bytes to read 113210284Sjmallett * @param ia_width_bytes 114210284Sjmallett * Internal address size in bytes (0, 1, or 2) 115210284Sjmallett * @param data Pointer argument where the read data is returned. 116215990Sjmallett * 117210284Sjmallett * @return read data returned in 'data' argument 118210284Sjmallett * Number of bytes read on success 119210284Sjmallett * -1 on failure 120210284Sjmallett */ 121210284Sjmallettint 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) 122210284Sjmallett{ 123215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 124215990Sjmallett# if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 125215990Sjmallett struct i2c_adapter *adapter; 126215990Sjmallett u8 data_buf[8]; 127215990Sjmallett u8 addr_buf[8]; 128215990Sjmallett struct i2c_msg msg[2]; 129215990Sjmallett uint64_t r; 130215990Sjmallett int i, j; 131210284Sjmallett 132215990Sjmallett if (ia_width_bytes == 0) 133215990Sjmallett return cvmx_twsix_read(twsi_id, dev_addr, num_bytes, data); 134210284Sjmallett 135215990Sjmallett BUG_ON(ia_width_bytes > 2); 136215990Sjmallett BUG_ON(num_bytes > 8 || num_bytes < 1); 137210284Sjmallett 138215990Sjmallett adapter = __cvmx_twsix_get_adapter(twsi_id); 139215990Sjmallett if (adapter == NULL) 140215990Sjmallett return -1; 141210284Sjmallett 142215990Sjmallett for (j = 0, i = ia_width_bytes - 1; i >= 0; i--, j++) 143215990Sjmallett addr_buf[j] = (u8)(internal_addr >> (i * 8)); 144210284Sjmallett 145215990Sjmallett msg[0].addr = dev_addr; 146215990Sjmallett msg[0].flags = 0; 147215990Sjmallett msg[0].len = ia_width_bytes; 148215990Sjmallett msg[0].buf = addr_buf; 149210284Sjmallett 150215990Sjmallett msg[1].addr = dev_addr; 151215990Sjmallett msg[1].flags = I2C_M_RD; 152215990Sjmallett msg[1].len = num_bytes; 153215990Sjmallett msg[1].buf = data_buf; 154210284Sjmallett 155215990Sjmallett i = i2c_transfer(adapter, msg, 2); 156210284Sjmallett 157215990Sjmallett i2c_put_adapter(adapter); 158210284Sjmallett 159215990Sjmallett if (i == 2) { 160215990Sjmallett r = 0; 161215990Sjmallett for (i = 0; i < num_bytes; i++) 162215990Sjmallett r = (r << 8) | data_buf[i]; 163215990Sjmallett *data = r; 164215990Sjmallett return num_bytes; 165215990Sjmallett } else { 166215990Sjmallett return -1; 167215990Sjmallett } 168215990Sjmallett# else 169215990Sjmallett BUG(); /* The I2C driver is not compiled in */ 170215990Sjmallett# endif 171215990Sjmallett#else 172215990Sjmallett cvmx_mio_twsx_sw_twsi_t sw_twsi_val; 173215990Sjmallett cvmx_mio_twsx_sw_twsi_ext_t twsi_ext; 174210284Sjmallett 175215990Sjmallett if (num_bytes < 1 || num_bytes > 8 || !data || ia_width_bytes < 0 || ia_width_bytes > 2) 176215990Sjmallett return -1; 177215990Sjmallett 178215990Sjmallett twsi_ext.u64 = 0; 179215990Sjmallett sw_twsi_val.u64 = 0; 180215990Sjmallett sw_twsi_val.s.v = 1; 181215990Sjmallett sw_twsi_val.s.r = 1; 182215990Sjmallett sw_twsi_val.s.sovr = 1; 183215990Sjmallett sw_twsi_val.s.size = num_bytes - 1; 184215990Sjmallett sw_twsi_val.s.a = dev_addr; 185215990Sjmallett 186215990Sjmallett if (ia_width_bytes > 0) { 187215990Sjmallett sw_twsi_val.s.op = 1; 188215990Sjmallett sw_twsi_val.s.ia = (internal_addr >> 3) & 0x1f; 189215990Sjmallett sw_twsi_val.s.eop_ia = internal_addr & 0x7; 190215990Sjmallett } 191215990Sjmallett if (ia_width_bytes == 2) { 192215990Sjmallett sw_twsi_val.s.eia = 1; 193215990Sjmallett twsi_ext.s.ia = internal_addr >> 8; 194215990Sjmallett cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u64); 195215990Sjmallett } 196215990Sjmallett 197215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 198215990Sjmallett cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 199215990Sjmallett while (((cvmx_mio_twsx_sw_twsi_t)(sw_twsi_val.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id)))).s.v) 200215990Sjmallett ; 201215990Sjmallett twsi_printf("Results:\n"); 202215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 203215990Sjmallett if (!sw_twsi_val.s.r) 204215990Sjmallett return -1; 205215990Sjmallett 206215990Sjmallett *data = (sw_twsi_val.s.d & (0xFFFFFFFF >> (32 - num_bytes*8))); 207215990Sjmallett if (num_bytes > 4) { 208215990Sjmallett twsi_ext.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id)); 209215990Sjmallett *data |= ((unsigned long long)(twsi_ext.s.d & (0xFFFFFFFF >> (32 - num_bytes*8))) << 32); 210215990Sjmallett } 211215990Sjmallett return num_bytes; 212215990Sjmallett#endif 213215990Sjmallett} 214215990Sjmallett 215210284Sjmallett/** 216210284Sjmallett * Read from a TWSI device (7 bit device address only) without generating any 217210284Sjmallett * internal addresses. 218210284Sjmallett * Read from 1-8 bytes and returns them in the data pointer. 219215990Sjmallett * 220210284Sjmallett * @param twsi_id TWSI interface on Octeon to use 221210284Sjmallett * @param dev_addr TWSI device address (7 bit only) 222210284Sjmallett * @param num_bytes number of bytes to read 223210284Sjmallett * @param data Pointer to data read from TWSI device 224215990Sjmallett * 225210284Sjmallett * @return Number of bytes read on success 226210284Sjmallett * -1 on error 227210284Sjmallett */ 228210284Sjmallettint cvmx_twsix_read(int twsi_id, uint8_t dev_addr, int num_bytes, uint64_t *data) 229210284Sjmallett{ 230215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 231215990Sjmallett# if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 232215990Sjmallett struct i2c_adapter *adapter; 233215990Sjmallett u8 data_buf[8]; 234215990Sjmallett struct i2c_msg msg[1]; 235215990Sjmallett uint64_t r; 236215990Sjmallett int i; 237210284Sjmallett 238215990Sjmallett BUG_ON(num_bytes > 8 || num_bytes < 1); 239210284Sjmallett 240215990Sjmallett adapter = __cvmx_twsix_get_adapter(twsi_id); 241215990Sjmallett if (adapter == NULL) 242215990Sjmallett return -1; 243210284Sjmallett 244215990Sjmallett msg[0].addr = dev_addr; 245215990Sjmallett msg[0].flags = I2C_M_RD; 246215990Sjmallett msg[0].len = num_bytes; 247215990Sjmallett msg[0].buf = data_buf; 248210284Sjmallett 249215990Sjmallett i = i2c_transfer(adapter, msg, 1); 250210284Sjmallett 251215990Sjmallett i2c_put_adapter(adapter); 252215990Sjmallett 253215990Sjmallett if (i == 1) { 254215990Sjmallett r = 0; 255215990Sjmallett for (i = 0; i < num_bytes; i++) 256215990Sjmallett r = (r << 8) | data_buf[i]; 257215990Sjmallett *data = r; 258215990Sjmallett return num_bytes; 259215990Sjmallett } else { 260215990Sjmallett return -1; 261215990Sjmallett } 262215990Sjmallett# else 263215990Sjmallett BUG(); /* The I2C driver is not compiled in */ 264215990Sjmallett# endif 265215990Sjmallett#else 266215990Sjmallett cvmx_mio_twsx_sw_twsi_t sw_twsi_val; 267215990Sjmallett cvmx_mio_twsx_sw_twsi_ext_t twsi_ext; 268215990Sjmallett 269215990Sjmallett if (num_bytes > 8 || num_bytes < 1) 270215990Sjmallett return -1; 271215990Sjmallett 272215990Sjmallett sw_twsi_val.u64 = 0; 273215990Sjmallett sw_twsi_val.s.v = 1; 274215990Sjmallett sw_twsi_val.s.r = 1; 275215990Sjmallett sw_twsi_val.s.a = dev_addr; 276215990Sjmallett sw_twsi_val.s.sovr = 1; 277215990Sjmallett sw_twsi_val.s.size = num_bytes - 1; 278215990Sjmallett 279215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 280215990Sjmallett cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 281215990Sjmallett while (((cvmx_mio_twsx_sw_twsi_t)(sw_twsi_val.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id)))).s.v) 282215990Sjmallett ; 283215990Sjmallett twsi_printf("Results:\n"); 284215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 285215990Sjmallett if (!sw_twsi_val.s.r) 286215990Sjmallett return -1; 287215990Sjmallett 288215990Sjmallett *data = (sw_twsi_val.s.d & (0xFFFFFFFF >> (32 - num_bytes*8))); 289215990Sjmallett if (num_bytes > 4) { 290215990Sjmallett twsi_ext.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id)); 291215990Sjmallett *data |= ((unsigned long long)(twsi_ext.s.d & (0xFFFFFFFF >> (32 - num_bytes*8))) << 32); 292215990Sjmallett } 293215990Sjmallett return num_bytes; 294215990Sjmallett#endif 295210284Sjmallett} 296210284Sjmallett 297210284Sjmallett/** 298210284Sjmallett * Perform a twsi write operation to a 7 bit device address. 299215990Sjmallett * 300210284Sjmallett * Note that many eeprom devices have page restrictions regarding address boundaries 301210284Sjmallett * that can be crossed in one write operation. This is device dependent, and this routine 302210284Sjmallett * does nothing in this regard. 303210284Sjmallett * This command does not generate any internal addressess. 304215990Sjmallett * 305210284Sjmallett * @param twsi_id Octeon TWSI interface to use 306210284Sjmallett * @param dev_addr TWSI device address 307210284Sjmallett * @param num_bytes Number of bytes to write (between 1 and 8 inclusive) 308210284Sjmallett * @param data Data to write 309215990Sjmallett * 310210284Sjmallett * @return 0 on success 311210284Sjmallett * -1 on failure 312210284Sjmallett */ 313210284Sjmallettint cvmx_twsix_write(int twsi_id, uint8_t dev_addr, int num_bytes, uint64_t data) 314210284Sjmallett{ 315215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 316215990Sjmallett# if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 317215990Sjmallett struct i2c_adapter *adapter; 318215990Sjmallett u8 data_buf[8]; 319215990Sjmallett struct i2c_msg msg[1]; 320215990Sjmallett int i, j; 321210284Sjmallett 322215990Sjmallett BUG_ON(num_bytes > 8 || num_bytes < 1); 323210284Sjmallett 324215990Sjmallett adapter = __cvmx_twsix_get_adapter(twsi_id); 325215990Sjmallett if (adapter == NULL) 326215990Sjmallett return -1; 327210284Sjmallett 328215990Sjmallett for (j = 0, i = num_bytes - 1; i >= 0; i--, j++) 329215990Sjmallett data_buf[j] = (u8)(data >> (i * 8)); 330215990Sjmallett 331215990Sjmallett msg[1].addr = dev_addr; 332215990Sjmallett msg[1].flags = 0; 333215990Sjmallett msg[1].len = num_bytes; 334215990Sjmallett msg[1].buf = data_buf; 335215990Sjmallett 336215990Sjmallett i = i2c_transfer(adapter, msg, 1); 337215990Sjmallett 338215990Sjmallett i2c_put_adapter(adapter); 339215990Sjmallett 340215990Sjmallett if (i == 1) 341215990Sjmallett return num_bytes; 342215990Sjmallett else 343215990Sjmallett return -1; 344215990Sjmallett# else 345215990Sjmallett BUG(); /* The I2C driver is not compiled in */ 346215990Sjmallett# endif 347215990Sjmallett#else 348215990Sjmallett cvmx_mio_twsx_sw_twsi_t sw_twsi_val; 349215990Sjmallett 350215990Sjmallett if (num_bytes > 8 || num_bytes < 1) 351215990Sjmallett return -1; 352215990Sjmallett 353215990Sjmallett sw_twsi_val.u64 = 0; 354215990Sjmallett sw_twsi_val.s.v = 1; 355215990Sjmallett sw_twsi_val.s.a = dev_addr; 356215990Sjmallett sw_twsi_val.s.d = data & 0xffffffff; 357215990Sjmallett sw_twsi_val.s.sovr = 1; 358215990Sjmallett sw_twsi_val.s.size = num_bytes - 1; 359215990Sjmallett if (num_bytes > 4) { 360215990Sjmallett /* Upper four bytes go into a separate register */ 361215990Sjmallett cvmx_mio_twsx_sw_twsi_ext_t twsi_ext; 362215990Sjmallett twsi_ext.u64 = 0; 363215990Sjmallett twsi_ext.s.d = data >> 32; 364215990Sjmallett cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u64); 365215990Sjmallett } 366215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 367215990Sjmallett cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 368215990Sjmallett while (((cvmx_mio_twsx_sw_twsi_t)(sw_twsi_val.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id)))).s.v) 369215990Sjmallett ; 370215990Sjmallett twsi_printf("Results:\n"); 371215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 372215990Sjmallett if (!sw_twsi_val.s.r) 373215990Sjmallett return -1; 374215990Sjmallett 375215990Sjmallett return 0; 376215990Sjmallett#endif 377210284Sjmallett} 378210284Sjmallett 379210284Sjmallett/** 380210284Sjmallett * Write 1-8 bytes to a TWSI device using an internal address. 381215990Sjmallett * 382210284Sjmallett * @param twsi_id which TWSI interface on Octeon to use 383210284Sjmallett * @param dev_addr TWSI device address (7 bit only) 384210284Sjmallett * @param internal_addr 385210284Sjmallett * TWSI internal address (0, 8, or 16 bits) 386210284Sjmallett * @param num_bytes Number of bytes to write (1-8) 387210284Sjmallett * @param ia_width_bytes 388210284Sjmallett * internal address width, in bytes (0, 1, 2) 389210284Sjmallett * @param data Data to write. Data is written MSB first on the twsi bus, and only the lower 390210284Sjmallett * num_bytes bytes of the argument are valid. (If a 2 byte write is done, only 391210284Sjmallett * the low 2 bytes of the argument is used. 392215990Sjmallett * 393210284Sjmallett * @return Number of bytes read on success, 394210284Sjmallett * -1 on error 395210284Sjmallett */ 396210284Sjmallettint 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) 397210284Sjmallett{ 398215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 399215990Sjmallett# if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 400215990Sjmallett struct i2c_adapter *adapter; 401215990Sjmallett u8 data_buf[8]; 402215990Sjmallett u8 addr_buf[8]; 403215990Sjmallett struct i2c_msg msg[2]; 404215990Sjmallett int i, j; 405210284Sjmallett 406215990Sjmallett if (ia_width_bytes == 0) 407215990Sjmallett return cvmx_twsix_write(twsi_id, dev_addr, num_bytes, data); 408210284Sjmallett 409215990Sjmallett BUG_ON(ia_width_bytes > 2); 410215990Sjmallett BUG_ON(num_bytes > 8 || num_bytes < 1); 411210284Sjmallett 412215990Sjmallett adapter = __cvmx_twsix_get_adapter(twsi_id); 413215990Sjmallett if (adapter == NULL) 414215990Sjmallett return -1; 415210284Sjmallett 416210284Sjmallett 417215990Sjmallett for (j = 0, i = ia_width_bytes - 1; i >= 0; i--, j++) 418215990Sjmallett addr_buf[j] = (u8)(internal_addr >> (i * 8)); 419210284Sjmallett 420215990Sjmallett for (j = 0, i = num_bytes - 1; i >= 0; i--, j++) 421215990Sjmallett data_buf[j] = (u8)(data >> (i * 8)); 422210284Sjmallett 423215990Sjmallett msg[0].addr = dev_addr; 424215990Sjmallett msg[0].flags = 0; 425215990Sjmallett msg[0].len = ia_width_bytes; 426215990Sjmallett msg[0].buf = addr_buf; 427210284Sjmallett 428215990Sjmallett msg[1].addr = dev_addr; 429215990Sjmallett msg[1].flags = 0; 430215990Sjmallett msg[1].len = num_bytes; 431215990Sjmallett msg[1].buf = data_buf; 432215990Sjmallett 433215990Sjmallett i = i2c_transfer(adapter, msg, 2); 434215990Sjmallett 435215990Sjmallett i2c_put_adapter(adapter); 436215990Sjmallett 437215990Sjmallett if (i == 2) { 438215990Sjmallett /* Poll until reads succeed, or polling times out */ 439215990Sjmallett int to = 100; 440215990Sjmallett while (to-- > 0) { 441215990Sjmallett uint64_t data; 442215990Sjmallett if (cvmx_twsix_read(twsi_id, dev_addr, 1, &data) >= 0) 443215990Sjmallett break; 444215990Sjmallett } 445215990Sjmallett } 446215990Sjmallett 447215990Sjmallett if (i == 2) 448215990Sjmallett return num_bytes; 449215990Sjmallett else 450215990Sjmallett return -1; 451215990Sjmallett# else 452215990Sjmallett BUG(); /* The I2C driver is not compiled in */ 453215990Sjmallett# endif 454215990Sjmallett#else 455215990Sjmallett cvmx_mio_twsx_sw_twsi_t sw_twsi_val; 456215990Sjmallett cvmx_mio_twsx_sw_twsi_ext_t twsi_ext; 457215990Sjmallett int to; 458215990Sjmallett 459215990Sjmallett if (num_bytes < 1 || num_bytes > 8 || ia_width_bytes < 0 || ia_width_bytes > 2) 460215990Sjmallett return -1; 461215990Sjmallett 462215990Sjmallett twsi_ext.u64 = 0; 463215990Sjmallett 464215990Sjmallett sw_twsi_val.u64 = 0; 465215990Sjmallett sw_twsi_val.s.v = 1; 466215990Sjmallett sw_twsi_val.s.sovr = 1; 467215990Sjmallett sw_twsi_val.s.size = num_bytes - 1; 468215990Sjmallett sw_twsi_val.s.a = dev_addr; 469215990Sjmallett sw_twsi_val.s.d = 0xFFFFFFFF & data; 470215990Sjmallett 471215990Sjmallett if (ia_width_bytes > 0) { 472215990Sjmallett sw_twsi_val.s.op = 1; 473215990Sjmallett sw_twsi_val.s.ia = (internal_addr >> 3) & 0x1f; 474215990Sjmallett sw_twsi_val.s.eop_ia = internal_addr & 0x7; 475215990Sjmallett } 476215990Sjmallett if (ia_width_bytes == 2) { 477215990Sjmallett sw_twsi_val.s.eia = 1; 478215990Sjmallett twsi_ext.s.ia = internal_addr >> 8; 479215990Sjmallett } 480215990Sjmallett if (num_bytes > 4) 481215990Sjmallett twsi_ext.s.d = data >> 32; 482215990Sjmallett 483215990Sjmallett twsi_printf("%s: twsi_id=%x, dev_addr=%x, internal_addr=%x\n\tnum_bytes=%d, ia_width_bytes=%d, data=%lx\n", 484215990Sjmallett __FUNCTION__, twsi_id, dev_addr, internal_addr, num_bytes, ia_width_bytes, data); 485215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u64); 486215990Sjmallett cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u64); 487215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 488215990Sjmallett cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 489215990Sjmallett while (((cvmx_mio_twsx_sw_twsi_t)(sw_twsi_val.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id)))).s.v) 490215990Sjmallett ; 491215990Sjmallett twsi_printf("Results:\n"); 492215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 493215990Sjmallett 494215990Sjmallett /* Poll until reads succeed, or polling times out */ 495215990Sjmallett to = 100; 496215990Sjmallett while (to-- > 0) { 497215990Sjmallett uint64_t data; 498215990Sjmallett if (cvmx_twsix_read(twsi_id, dev_addr, 1, &data) >= 0) 499215990Sjmallett break; 500215990Sjmallett } 501215990Sjmallett if (to <= 0) 502215990Sjmallett return -1; 503215990Sjmallett 504215990Sjmallett return num_bytes; 505215990Sjmallett#endif 506210284Sjmallett} 507