1210284Sjmallett/***********************license start*************** 2232812Sjmallett * Copyright (c) 2003-2010 Cavium Inc. (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 18232812Sjmallett * * Neither the name of Cavium Inc. 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" 29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. 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 * 51232812Sjmallett * <hr>$Revision: 70030 $<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" 62232915Sjmallett#if !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL) 63215990Sjmallett#include "cvmx-csr-db.h" 64215990Sjmallett#endif 65232915Sjmallett#endif 66210284Sjmallett 67215990Sjmallett//#define PRINT_TWSI_CONFIG 68215990Sjmallett#ifdef PRINT_TWSI_CONFIG 69215990Sjmallett#define twsi_printf printf 70215990Sjmallett#else 71215990Sjmallett#define twsi_printf(...) 72215990Sjmallett#define cvmx_csr_db_decode(...) 73215990Sjmallett#endif 74210284Sjmallett 75215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 76232812Sjmallett# if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 77215990Sjmallettstatic struct i2c_adapter *__cvmx_twsix_get_adapter(int twsi_id) 78215990Sjmallett{ 79215990Sjmallett struct octeon_i2c { 80215990Sjmallett wait_queue_head_t queue; 81215990Sjmallett struct i2c_adapter adap; 82215990Sjmallett int irq; 83215990Sjmallett int twsi_freq; 84215990Sjmallett int sys_freq; 85215990Sjmallett resource_size_t twsi_phys; 86215990Sjmallett void __iomem *twsi_base; 87215990Sjmallett resource_size_t regsize; 88215990Sjmallett struct device *dev; 89215990Sjmallett int broken_irq_mode; 90215990Sjmallett }; 91215990Sjmallett struct i2c_adapter *adapter; 92215990Sjmallett struct octeon_i2c *i2c; 93210284Sjmallett 94215990Sjmallett adapter = i2c_get_adapter(0); 95215990Sjmallett if (adapter == NULL) 96215990Sjmallett return NULL; 97215990Sjmallett i2c = container_of(adapter, struct octeon_i2c, adap); 98215990Sjmallett return &i2c[twsi_id].adap; 99215990Sjmallett} 100215990Sjmallett#endif 101232812Sjmallett#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; 174232812Sjmallett int retry_limit = 5; 175210284Sjmallett 176215990Sjmallett if (num_bytes < 1 || num_bytes > 8 || !data || ia_width_bytes < 0 || ia_width_bytes > 2) 177215990Sjmallett return -1; 178232812Sjmallettretry: 179215990Sjmallett twsi_ext.u64 = 0; 180215990Sjmallett sw_twsi_val.u64 = 0; 181215990Sjmallett sw_twsi_val.s.v = 1; 182215990Sjmallett sw_twsi_val.s.r = 1; 183215990Sjmallett sw_twsi_val.s.sovr = 1; 184215990Sjmallett sw_twsi_val.s.size = num_bytes - 1; 185215990Sjmallett sw_twsi_val.s.a = dev_addr; 186215990Sjmallett 187215990Sjmallett if (ia_width_bytes > 0) { 188215990Sjmallett sw_twsi_val.s.op = 1; 189215990Sjmallett sw_twsi_val.s.ia = (internal_addr >> 3) & 0x1f; 190215990Sjmallett sw_twsi_val.s.eop_ia = internal_addr & 0x7; 191215990Sjmallett } 192215990Sjmallett if (ia_width_bytes == 2) { 193215990Sjmallett sw_twsi_val.s.eia = 1; 194215990Sjmallett twsi_ext.s.ia = internal_addr >> 8; 195215990Sjmallett cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u64); 196215990Sjmallett } 197215990Sjmallett 198215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 199215990Sjmallett cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 200215990Sjmallett while (((cvmx_mio_twsx_sw_twsi_t)(sw_twsi_val.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id)))).s.v) 201232812Sjmallett cvmx_wait(1000); 202215990Sjmallett twsi_printf("Results:\n"); 203215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 204215990Sjmallett if (!sw_twsi_val.s.r) 205232812Sjmallett { 206232812Sjmallett /* Check the reason for the failure. We may need to retry to handle multi-master 207232812Sjmallett ** configurations. 208232812Sjmallett ** Lost arbitration : 0x38, 0x68, 0xB0, 0x78 209232812Sjmallett ** Core busy as slave: 0x80, 0x88, 0xA0, 0xA8, 0xB8, 0xC0, 0xC8 210232812Sjmallett */ 211232812Sjmallett if (sw_twsi_val.s.d == 0x38 212232812Sjmallett || sw_twsi_val.s.d == 0x68 213232812Sjmallett || sw_twsi_val.s.d == 0xB0 214232812Sjmallett || sw_twsi_val.s.d == 0x78 215232812Sjmallett || sw_twsi_val.s.d == 0x80 216232812Sjmallett || sw_twsi_val.s.d == 0x88 217232812Sjmallett || sw_twsi_val.s.d == 0xA0 218232812Sjmallett || sw_twsi_val.s.d == 0xA8 219232812Sjmallett || sw_twsi_val.s.d == 0xB8 220232812Sjmallett || sw_twsi_val.s.d == 0xC8) 221232812Sjmallett { 222232812Sjmallett if (retry_limit-- > 0) 223232812Sjmallett { 224232812Sjmallett cvmx_wait_usec(100); 225232812Sjmallett goto retry; 226232812Sjmallett } 227232812Sjmallett } 228232812Sjmallett /* For all other errors, return an error code */ 229232812Sjmallett return -1; 230232812Sjmallett } 231215990Sjmallett 232215990Sjmallett *data = (sw_twsi_val.s.d & (0xFFFFFFFF >> (32 - num_bytes*8))); 233215990Sjmallett if (num_bytes > 4) { 234215990Sjmallett twsi_ext.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id)); 235215990Sjmallett *data |= ((unsigned long long)(twsi_ext.s.d & (0xFFFFFFFF >> (32 - num_bytes*8))) << 32); 236215990Sjmallett } 237215990Sjmallett return num_bytes; 238215990Sjmallett#endif 239215990Sjmallett} 240215990Sjmallett 241210284Sjmallett/** 242210284Sjmallett * Read from a TWSI device (7 bit device address only) without generating any 243210284Sjmallett * internal addresses. 244210284Sjmallett * Read from 1-8 bytes and returns them in the data pointer. 245215990Sjmallett * 246210284Sjmallett * @param twsi_id TWSI interface on Octeon to use 247210284Sjmallett * @param dev_addr TWSI device address (7 bit only) 248210284Sjmallett * @param num_bytes number of bytes to read 249210284Sjmallett * @param data Pointer to data read from TWSI device 250215990Sjmallett * 251210284Sjmallett * @return Number of bytes read on success 252210284Sjmallett * -1 on error 253210284Sjmallett */ 254210284Sjmallettint cvmx_twsix_read(int twsi_id, uint8_t dev_addr, int num_bytes, uint64_t *data) 255210284Sjmallett{ 256215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 257215990Sjmallett# if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 258215990Sjmallett struct i2c_adapter *adapter; 259215990Sjmallett u8 data_buf[8]; 260215990Sjmallett struct i2c_msg msg[1]; 261215990Sjmallett uint64_t r; 262215990Sjmallett int i; 263210284Sjmallett 264215990Sjmallett BUG_ON(num_bytes > 8 || num_bytes < 1); 265210284Sjmallett 266215990Sjmallett adapter = __cvmx_twsix_get_adapter(twsi_id); 267215990Sjmallett if (adapter == NULL) 268215990Sjmallett return -1; 269210284Sjmallett 270215990Sjmallett msg[0].addr = dev_addr; 271215990Sjmallett msg[0].flags = I2C_M_RD; 272215990Sjmallett msg[0].len = num_bytes; 273215990Sjmallett msg[0].buf = data_buf; 274210284Sjmallett 275215990Sjmallett i = i2c_transfer(adapter, msg, 1); 276210284Sjmallett 277215990Sjmallett i2c_put_adapter(adapter); 278215990Sjmallett 279215990Sjmallett if (i == 1) { 280215990Sjmallett r = 0; 281215990Sjmallett for (i = 0; i < num_bytes; i++) 282215990Sjmallett r = (r << 8) | data_buf[i]; 283215990Sjmallett *data = r; 284215990Sjmallett return num_bytes; 285215990Sjmallett } else { 286215990Sjmallett return -1; 287215990Sjmallett } 288215990Sjmallett# else 289215990Sjmallett BUG(); /* The I2C driver is not compiled in */ 290215990Sjmallett# endif 291215990Sjmallett#else 292215990Sjmallett cvmx_mio_twsx_sw_twsi_t sw_twsi_val; 293215990Sjmallett cvmx_mio_twsx_sw_twsi_ext_t twsi_ext; 294232812Sjmallett int retry_limit = 5; 295215990Sjmallett 296215990Sjmallett if (num_bytes > 8 || num_bytes < 1) 297215990Sjmallett return -1; 298232812Sjmallettretry: 299215990Sjmallett sw_twsi_val.u64 = 0; 300215990Sjmallett sw_twsi_val.s.v = 1; 301215990Sjmallett sw_twsi_val.s.r = 1; 302215990Sjmallett sw_twsi_val.s.a = dev_addr; 303215990Sjmallett sw_twsi_val.s.sovr = 1; 304215990Sjmallett sw_twsi_val.s.size = num_bytes - 1; 305215990Sjmallett 306215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 307215990Sjmallett cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 308215990Sjmallett while (((cvmx_mio_twsx_sw_twsi_t)(sw_twsi_val.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id)))).s.v) 309232812Sjmallett cvmx_wait(1000); 310215990Sjmallett twsi_printf("Results:\n"); 311215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 312215990Sjmallett if (!sw_twsi_val.s.r) 313232812Sjmallett if (!sw_twsi_val.s.r) 314232812Sjmallett { 315232812Sjmallett /* Check the reason for the failure. We may need to retry to handle multi-master 316232812Sjmallett ** configurations. 317232812Sjmallett ** Lost arbitration : 0x38, 0x68, 0xB0, 0x78 318232812Sjmallett ** Core busy as slave: 0x80, 0x88, 0xA0, 0xA8, 0xB8, 0xC0, 0xC8 319232812Sjmallett */ 320232812Sjmallett if (sw_twsi_val.s.d == 0x38 321232812Sjmallett || sw_twsi_val.s.d == 0x68 322232812Sjmallett || sw_twsi_val.s.d == 0xB0 323232812Sjmallett || sw_twsi_val.s.d == 0x78 324232812Sjmallett || sw_twsi_val.s.d == 0x80 325232812Sjmallett || sw_twsi_val.s.d == 0x88 326232812Sjmallett || sw_twsi_val.s.d == 0xA0 327232812Sjmallett || sw_twsi_val.s.d == 0xA8 328232812Sjmallett || sw_twsi_val.s.d == 0xB8 329232812Sjmallett || sw_twsi_val.s.d == 0xC8) 330232812Sjmallett { 331232812Sjmallett if (retry_limit-- > 0) 332232812Sjmallett { 333232812Sjmallett cvmx_wait_usec(100); 334232812Sjmallett goto retry; 335232812Sjmallett } 336232812Sjmallett } 337232812Sjmallett /* For all other errors, return an error code */ 338232812Sjmallett return -1; 339232812Sjmallett } 340215990Sjmallett 341215990Sjmallett *data = (sw_twsi_val.s.d & (0xFFFFFFFF >> (32 - num_bytes*8))); 342215990Sjmallett if (num_bytes > 4) { 343215990Sjmallett twsi_ext.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id)); 344215990Sjmallett *data |= ((unsigned long long)(twsi_ext.s.d & (0xFFFFFFFF >> (32 - num_bytes*8))) << 32); 345215990Sjmallett } 346215990Sjmallett return num_bytes; 347215990Sjmallett#endif 348210284Sjmallett} 349210284Sjmallett 350210284Sjmallett/** 351210284Sjmallett * Perform a twsi write operation to a 7 bit device address. 352215990Sjmallett * 353210284Sjmallett * Note that many eeprom devices have page restrictions regarding address boundaries 354210284Sjmallett * that can be crossed in one write operation. This is device dependent, and this routine 355210284Sjmallett * does nothing in this regard. 356210284Sjmallett * This command does not generate any internal addressess. 357215990Sjmallett * 358210284Sjmallett * @param twsi_id Octeon TWSI interface to use 359210284Sjmallett * @param dev_addr TWSI device address 360210284Sjmallett * @param num_bytes Number of bytes to write (between 1 and 8 inclusive) 361210284Sjmallett * @param data Data to write 362215990Sjmallett * 363210284Sjmallett * @return 0 on success 364210284Sjmallett * -1 on failure 365210284Sjmallett */ 366210284Sjmallettint cvmx_twsix_write(int twsi_id, uint8_t dev_addr, int num_bytes, uint64_t data) 367210284Sjmallett{ 368215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 369215990Sjmallett# if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 370215990Sjmallett struct i2c_adapter *adapter; 371215990Sjmallett u8 data_buf[8]; 372215990Sjmallett struct i2c_msg msg[1]; 373215990Sjmallett int i, j; 374210284Sjmallett 375215990Sjmallett BUG_ON(num_bytes > 8 || num_bytes < 1); 376210284Sjmallett 377215990Sjmallett adapter = __cvmx_twsix_get_adapter(twsi_id); 378215990Sjmallett if (adapter == NULL) 379215990Sjmallett return -1; 380210284Sjmallett 381215990Sjmallett for (j = 0, i = num_bytes - 1; i >= 0; i--, j++) 382215990Sjmallett data_buf[j] = (u8)(data >> (i * 8)); 383215990Sjmallett 384232812Sjmallett msg[0].addr = dev_addr; 385232812Sjmallett msg[0].flags = 0; 386232812Sjmallett msg[0].len = num_bytes; 387232812Sjmallett msg[0].buf = data_buf; 388215990Sjmallett 389215990Sjmallett i = i2c_transfer(adapter, msg, 1); 390215990Sjmallett 391215990Sjmallett i2c_put_adapter(adapter); 392215990Sjmallett 393215990Sjmallett if (i == 1) 394215990Sjmallett return num_bytes; 395215990Sjmallett else 396215990Sjmallett return -1; 397215990Sjmallett# else 398215990Sjmallett BUG(); /* The I2C driver is not compiled in */ 399215990Sjmallett# endif 400215990Sjmallett#else 401215990Sjmallett cvmx_mio_twsx_sw_twsi_t sw_twsi_val; 402215990Sjmallett 403215990Sjmallett if (num_bytes > 8 || num_bytes < 1) 404215990Sjmallett return -1; 405215990Sjmallett 406215990Sjmallett sw_twsi_val.u64 = 0; 407215990Sjmallett sw_twsi_val.s.v = 1; 408215990Sjmallett sw_twsi_val.s.a = dev_addr; 409215990Sjmallett sw_twsi_val.s.d = data & 0xffffffff; 410215990Sjmallett sw_twsi_val.s.sovr = 1; 411215990Sjmallett sw_twsi_val.s.size = num_bytes - 1; 412215990Sjmallett if (num_bytes > 4) { 413215990Sjmallett /* Upper four bytes go into a separate register */ 414215990Sjmallett cvmx_mio_twsx_sw_twsi_ext_t twsi_ext; 415215990Sjmallett twsi_ext.u64 = 0; 416215990Sjmallett twsi_ext.s.d = data >> 32; 417215990Sjmallett cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u64); 418215990Sjmallett } 419215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 420215990Sjmallett cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 421215990Sjmallett while (((cvmx_mio_twsx_sw_twsi_t)(sw_twsi_val.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id)))).s.v) 422215990Sjmallett ; 423215990Sjmallett twsi_printf("Results:\n"); 424215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 425215990Sjmallett if (!sw_twsi_val.s.r) 426215990Sjmallett return -1; 427215990Sjmallett 428215990Sjmallett return 0; 429215990Sjmallett#endif 430210284Sjmallett} 431210284Sjmallett 432210284Sjmallett/** 433210284Sjmallett * Write 1-8 bytes to a TWSI device using an internal address. 434215990Sjmallett * 435210284Sjmallett * @param twsi_id which TWSI interface on Octeon to use 436210284Sjmallett * @param dev_addr TWSI device address (7 bit only) 437210284Sjmallett * @param internal_addr 438210284Sjmallett * TWSI internal address (0, 8, or 16 bits) 439210284Sjmallett * @param num_bytes Number of bytes to write (1-8) 440210284Sjmallett * @param ia_width_bytes 441210284Sjmallett * internal address width, in bytes (0, 1, 2) 442210284Sjmallett * @param data Data to write. Data is written MSB first on the twsi bus, and only the lower 443210284Sjmallett * num_bytes bytes of the argument are valid. (If a 2 byte write is done, only 444210284Sjmallett * the low 2 bytes of the argument is used. 445215990Sjmallett * 446210284Sjmallett * @return Number of bytes read on success, 447210284Sjmallett * -1 on error 448210284Sjmallett */ 449210284Sjmallettint 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) 450210284Sjmallett{ 451215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 452215990Sjmallett# if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 453215990Sjmallett struct i2c_adapter *adapter; 454215990Sjmallett u8 data_buf[8]; 455215990Sjmallett u8 addr_buf[8]; 456215990Sjmallett struct i2c_msg msg[2]; 457215990Sjmallett int i, j; 458210284Sjmallett 459215990Sjmallett if (ia_width_bytes == 0) 460215990Sjmallett return cvmx_twsix_write(twsi_id, dev_addr, num_bytes, data); 461210284Sjmallett 462215990Sjmallett BUG_ON(ia_width_bytes > 2); 463215990Sjmallett BUG_ON(num_bytes > 8 || num_bytes < 1); 464210284Sjmallett 465215990Sjmallett adapter = __cvmx_twsix_get_adapter(twsi_id); 466215990Sjmallett if (adapter == NULL) 467215990Sjmallett return -1; 468210284Sjmallett 469210284Sjmallett 470215990Sjmallett for (j = 0, i = ia_width_bytes - 1; i >= 0; i--, j++) 471215990Sjmallett addr_buf[j] = (u8)(internal_addr >> (i * 8)); 472210284Sjmallett 473215990Sjmallett for (j = 0, i = num_bytes - 1; i >= 0; i--, j++) 474215990Sjmallett data_buf[j] = (u8)(data >> (i * 8)); 475210284Sjmallett 476215990Sjmallett msg[0].addr = dev_addr; 477215990Sjmallett msg[0].flags = 0; 478215990Sjmallett msg[0].len = ia_width_bytes; 479215990Sjmallett msg[0].buf = addr_buf; 480210284Sjmallett 481215990Sjmallett msg[1].addr = dev_addr; 482215990Sjmallett msg[1].flags = 0; 483215990Sjmallett msg[1].len = num_bytes; 484215990Sjmallett msg[1].buf = data_buf; 485215990Sjmallett 486215990Sjmallett i = i2c_transfer(adapter, msg, 2); 487215990Sjmallett 488215990Sjmallett i2c_put_adapter(adapter); 489215990Sjmallett 490215990Sjmallett if (i == 2) { 491215990Sjmallett /* Poll until reads succeed, or polling times out */ 492215990Sjmallett int to = 100; 493215990Sjmallett while (to-- > 0) { 494215990Sjmallett uint64_t data; 495215990Sjmallett if (cvmx_twsix_read(twsi_id, dev_addr, 1, &data) >= 0) 496215990Sjmallett break; 497215990Sjmallett } 498215990Sjmallett } 499215990Sjmallett 500215990Sjmallett if (i == 2) 501215990Sjmallett return num_bytes; 502215990Sjmallett else 503215990Sjmallett return -1; 504215990Sjmallett# else 505215990Sjmallett BUG(); /* The I2C driver is not compiled in */ 506215990Sjmallett# endif 507215990Sjmallett#else 508215990Sjmallett cvmx_mio_twsx_sw_twsi_t sw_twsi_val; 509215990Sjmallett cvmx_mio_twsx_sw_twsi_ext_t twsi_ext; 510215990Sjmallett int to; 511215990Sjmallett 512215990Sjmallett if (num_bytes < 1 || num_bytes > 8 || ia_width_bytes < 0 || ia_width_bytes > 2) 513215990Sjmallett return -1; 514215990Sjmallett 515215990Sjmallett twsi_ext.u64 = 0; 516215990Sjmallett 517215990Sjmallett sw_twsi_val.u64 = 0; 518215990Sjmallett sw_twsi_val.s.v = 1; 519215990Sjmallett sw_twsi_val.s.sovr = 1; 520215990Sjmallett sw_twsi_val.s.size = num_bytes - 1; 521215990Sjmallett sw_twsi_val.s.a = dev_addr; 522215990Sjmallett sw_twsi_val.s.d = 0xFFFFFFFF & data; 523215990Sjmallett 524215990Sjmallett if (ia_width_bytes > 0) { 525215990Sjmallett sw_twsi_val.s.op = 1; 526215990Sjmallett sw_twsi_val.s.ia = (internal_addr >> 3) & 0x1f; 527215990Sjmallett sw_twsi_val.s.eop_ia = internal_addr & 0x7; 528215990Sjmallett } 529215990Sjmallett if (ia_width_bytes == 2) { 530215990Sjmallett sw_twsi_val.s.eia = 1; 531215990Sjmallett twsi_ext.s.ia = internal_addr >> 8; 532215990Sjmallett } 533215990Sjmallett if (num_bytes > 4) 534215990Sjmallett twsi_ext.s.d = data >> 32; 535215990Sjmallett 536215990Sjmallett twsi_printf("%s: twsi_id=%x, dev_addr=%x, internal_addr=%x\n\tnum_bytes=%d, ia_width_bytes=%d, data=%lx\n", 537215990Sjmallett __FUNCTION__, twsi_id, dev_addr, internal_addr, num_bytes, ia_width_bytes, data); 538215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u64); 539215990Sjmallett cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u64); 540215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 541215990Sjmallett cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 542215990Sjmallett while (((cvmx_mio_twsx_sw_twsi_t)(sw_twsi_val.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id)))).s.v) 543215990Sjmallett ; 544215990Sjmallett twsi_printf("Results:\n"); 545215990Sjmallett cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64); 546215990Sjmallett 547215990Sjmallett /* Poll until reads succeed, or polling times out */ 548215990Sjmallett to = 100; 549215990Sjmallett while (to-- > 0) { 550215990Sjmallett uint64_t data; 551215990Sjmallett if (cvmx_twsix_read(twsi_id, dev_addr, 1, &data) >= 0) 552215990Sjmallett break; 553215990Sjmallett } 554215990Sjmallett if (to <= 0) 555215990Sjmallett return -1; 556215990Sjmallett 557215990Sjmallett return num_bytes; 558215990Sjmallett#endif 559210284Sjmallett} 560