1/* 2* Copyright c Realtek Semiconductor Corporation, 2006 3* All rights reserved. 4* 5* Program : Control smi connected RTL8366 6* Abstract : 7* Author : Yu-Mei Pan (ympan@realtek.com.cn) 8* $Id: smi.c,v 1.2 2008-04-10 03:04:19 shiehyy Exp $ 9*/ 10#include <rtk_types.h> 11#include <smi.h> 12#include "rtk_error.h" 13 14#include <typedefs.h> 15#include <bcmutils.h> 16#include <siutils.h> 17#include <bcmdevs.h> 18 19#ifndef _CFE_ 20#include <asm/uaccess.h> 21#include <linux/module.h> 22#include <linux/init.h> 23#include <linux/fs.h> 24#include <linux/miscdevice.h> 25#include <linux_gpio.h> 26#include <linux/delay.h> 27#endif 28 29#if defined(MDC_MDIO_OPERATION) 30/*******************************************************************************/ 31/* MDC/MDIO porting */ 32/*******************************************************************************/ 33/* define the PHY ID currently used */ 34#define MDC_MDIO_PHY_ID 0 /* PHY ID 0 or 29 */ 35 36/* MDC/MDIO, redefine/implement the following Macro */ 37#define MDC_MDIO_WRITE(preamableLength, phyID, regID, data) 38#define MDC_MDIO_READ(preamableLength, phyID, regID, pData) 39 40 41 42 43 44#elif defined(SPI_OPERATION) 45/*******************************************************************************/ 46/* SPI porting */ 47/*******************************************************************************/ 48/* SPI, redefine/implement the following Macro */ 49#define SPI_WRITE(data, length) 50#define SPI_READ(pData, length) 51 52 53 54 55 56#else 57/*******************************************************************************/ 58/* I2C porting */ 59/*******************************************************************************/ 60/* Define the GPIO ID for SCK & SDA */ 61rtk_uint32 smi_SCK = 6; /* GPIO used for SMI Clock Generation */ 62rtk_uint32 smi_SDA = 7; /* GPIO used for SMI Data signal */ 63 64/* I2C, redefine/implement the following Macro */ 65 66#ifdef _CFE_ 67#define rtlglue_drvMutexLock() do {} while (0) 68#define rtlglue_drvMutexUnlock() do {} while (0) 69extern void set_gpio_dir(rtk_uint32 gpioid, rtk_uint32 dir); 70extern void set_gpio_data(rtk_uint32 gpioid, rtk_uint32 data); 71extern void get_gpio_data(rtk_uint32 gpioid, rtk_uint32 *pdata); 72#define GPIO_DIRECTION_SET(gpioID, direction) set_gpio_dir(gpioID, direction) 73#define GPIO_DATA_SET(gpioID, data) set_gpio_data(gpioID, data) 74#define GPIO_DATA_GET(gpioID, pData) get_gpio_data(gpioID, pData) 75#else /* _CFE */ 76#define rtlglue_drvMutexLock() local_irq_save(flags); 77#define rtlglue_drvMutexUnlock() local_irq_restore(flags); 78extern uint32 _gpio_ctrl(unsigned int cmd, unsigned int mask, unsigned int val); 79#define GPIO_DIRECTION_SET(gpioID, direction) _gpio_ctrl(GPIO_IOC_OUTEN, 1<<gpioID, !direction?1<<gpioID:0) 80#define GPIO_DATA_SET(gpioID, data) ({ _gpio_ctrl(GPIO_IOC_RESERVE, 1<<gpioID, 1<<gpioID); \ 81 _gpio_ctrl(GPIO_IOC_OUT, 1<<gpioID, data?1<<gpioID:0); }) 82#define GPIO_DATA_GET(gpioID, pData) ({ *pData = (_gpio_ctrl(GPIO_IOC_IN, 0x07FF, 0) & 1<<gpioID) == 0 ? 0 : 1; }) 83#endif /*~_CFE_ */ 84#endif 85 86#if defined(MDC_MDIO_OPERATION) || defined(SPI_OPERATION) 87 /* No local function in MDC/MDIO & SPI mode */ 88#else 89static void _smi_start(void) 90{ 91 92 /* change GPIO pin to Output only */ 93 //GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_OUT); 94 GPIO_DIRECTION_SET(smi_SCK, GPIO_DIR_OUT); 95 GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_OUT); 96 97 /* Initial state: SCK: 0, SDA: 1 */ 98 GPIO_DATA_SET(smi_SCK, 0); 99 GPIO_DATA_SET(smi_SDA, 1); 100 CLK_DURATION(DELAY); 101 102 /* CLK 1: 0 -> 1, 1 -> 0 */ 103 GPIO_DATA_SET(smi_SCK, 1); 104 CLK_DURATION(DELAY); 105 GPIO_DATA_SET(smi_SCK, 0); 106 CLK_DURATION(DELAY); 107 108 /* CLK 2: */ 109 GPIO_DATA_SET(smi_SCK, 1); 110 CLK_DURATION(DELAY); 111 GPIO_DATA_SET(smi_SDA, 0); 112 CLK_DURATION(DELAY); 113 GPIO_DATA_SET(smi_SCK, 0); 114 CLK_DURATION(DELAY); 115 GPIO_DATA_SET(smi_SDA, 1); 116 117} 118 119void just_smi_start(void) 120{ 121 _smi_start(); 122} 123 124static void _smi_writeBit(rtk_uint16 signal, rtk_uint32 bitLen) 125{ 126 for( ; bitLen > 0; bitLen--) 127 { 128 CLK_DURATION(DELAY); 129 130 /* prepare data */ 131 if ( signal & (1<<(bitLen-1)) ) 132 GPIO_DATA_SET(smi_SDA, 1); 133 else 134 GPIO_DATA_SET(smi_SDA, 0); 135 CLK_DURATION(DELAY); 136 137 /* clocking */ 138 GPIO_DATA_SET(smi_SCK, 1); 139 CLK_DURATION(DELAY); 140 GPIO_DATA_SET(smi_SCK, 0); 141 } 142} 143 144 145 146static void _smi_readBit(rtk_uint32 bitLen, rtk_uint32 *rData) 147{ 148 rtk_uint32 u; 149 150 /* change GPIO pin to Input only */ 151 GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_IN); 152 153 for (*rData = 0; bitLen > 0; bitLen--) 154 { 155 CLK_DURATION(DELAY); 156 157 /* clocking */ 158 GPIO_DATA_SET(smi_SCK, 1); 159 CLK_DURATION(DELAY); 160 GPIO_DATA_GET(smi_SDA, &u); 161 GPIO_DATA_SET(smi_SCK, 0); 162 163 *rData |= (u << (bitLen - 1)); 164 } 165 166 /* change GPIO pin to Output only */ 167 GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_OUT); 168} 169 170 171 172static void _smi_stop(void) 173{ 174 175 CLK_DURATION(DELAY); 176 GPIO_DATA_SET(smi_SDA, 0); 177 GPIO_DATA_SET(smi_SCK, 1); 178 CLK_DURATION(DELAY); 179 GPIO_DATA_SET(smi_SDA, 1); 180 CLK_DURATION(DELAY); 181 GPIO_DATA_SET(smi_SCK, 1); 182 CLK_DURATION(DELAY); 183 GPIO_DATA_SET(smi_SCK, 0); 184 CLK_DURATION(DELAY); 185 GPIO_DATA_SET(smi_SCK, 1); 186 187 /* add a click */ 188 CLK_DURATION(DELAY); 189 GPIO_DATA_SET(smi_SCK, 0); 190 CLK_DURATION(DELAY); 191 GPIO_DATA_SET(smi_SCK, 1); 192 193 194 /* change GPIO pin to Input only */ 195 GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_IN); 196 GPIO_DIRECTION_SET(smi_SCK, GPIO_DIR_IN); 197} 198 199#endif /* End of #if defined(MDC_MDIO_OPERATION) || defined(SPI_OPERATION) */ 200 201rtk_int32 smi_read(rtk_uint32 mAddrs, rtk_uint32 *rData) 202{ 203#if (!defined(MDC_MDIO_OPERATION) && !defined(SPI_OPERATION)) 204 rtk_uint32 rawData=0, ACK; 205 rtk_uint8 con; 206 rtk_uint32 ret = RT_ERR_OK; 207#endif 208 209 if(mAddrs > 0xFFFF) 210 return RT_ERR_INPUT; 211 212 if(rData == NULL) 213 return RT_ERR_NULL_POINTER; 214 215#if defined(MDC_MDIO_OPERATION) 216 217 /* Lock */ 218 rtlglue_drvMutexLock(); 219 220 /* Write address control code to register 31 */ 221 MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP); 222 223 /* Write address to register 23 */ 224 MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_ADDRESS_REG, mAddrs); 225 226 /* Write read control code to register 21 */ 227 MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL1_REG, MDC_MDIO_READ_OP); 228 229 /* Read data from register 25 */ 230 MDC_MDIO_READ(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_DATA_READ_REG, rData); 231 232 /* Unlock */ 233 rtlglue_drvMutexUnlock(); 234 235 return RT_ERR_OK; 236 237#elif defined(SPI_OPERATION) 238 239 /* Lock */ 240 rtlglue_drvMutexLock(); 241 242 /* Write 8 bits READ OP_CODE */ 243 SPI_WRITE(SPI_READ_OP, SPI_READ_OP_LEN); 244 245 /* Write 16 bits register address */ 246 SPI_WRITE(mAddrs, SPI_REG_LEN); 247 248 /* Read 16 bits data */ 249 SPI_READ(rData, SPI_DATA_LEN); 250 251 /* Unlock */ 252 rtlglue_drvMutexUnlock(); 253 254 return RT_ERR_OK; 255 256#else 257#ifndef _CFE_ 258 unsigned long flags; 259#endif 260 /*Disable CPU interrupt to ensure that the SMI operation is atomic. 261 The API is based on RTL865X, rewrite the API if porting to other platform.*/ 262 rtlglue_drvMutexLock(); 263 264 _smi_start(); /* Start SMI */ 265 266 _smi_writeBit(0x0b, 4); /* CTRL code: 4'b1011 for RTL8370 */ 267 268 _smi_writeBit(0x4, 3); /* CTRL code: 3'b100 */ 269 270 _smi_writeBit(0x1, 1); /* 1: issue READ command */ 271 272 con = 0; 273 do { 274 con++; 275 _smi_readBit(1, &ACK); /* ACK for issuing READ command*/ 276 } while ((ACK != 0) && (con < ack_timer)); 277 278 if (ACK != 0) ret = RT_ERR_FAILED; 279 280 _smi_writeBit((mAddrs&0xff), 8); /* Set reg_addr[7:0] */ 281 282 con = 0; 283 do { 284 con++; 285 _smi_readBit(1, &ACK); /* ACK for setting reg_addr[7:0] */ 286 } while ((ACK != 0) && (con < ack_timer)); 287 288 if (ACK != 0) ret = RT_ERR_FAILED; 289 290 _smi_writeBit((mAddrs>>8), 8); /* Set reg_addr[15:8] */ 291 292 con = 0; 293 do { 294 con++; 295 _smi_readBit(1, &ACK); /* ACK by RTL8369 */ 296 } while ((ACK != 0) && (con < ack_timer)); 297 if (ACK != 0) ret = RT_ERR_FAILED; 298 299 _smi_readBit(8, &rawData); /* Read DATA [7:0] */ 300 *rData = rawData&0xff; 301 302 _smi_writeBit(0x00, 1); /* ACK by CPU */ 303 304 _smi_readBit(8, &rawData); /* Read DATA [15: 8] */ 305 306 _smi_writeBit(0x01, 1); /* ACK by CPU */ 307 *rData |= (rawData<<8); 308 309 _smi_stop(); 310 311 rtlglue_drvMutexUnlock();/*enable CPU interrupt*/ 312 313 return ret; 314#endif /* end of #if defined(MDC_MDIO_OPERATION) */ 315} 316 317 318 319rtk_int32 smi_write(rtk_uint32 mAddrs, rtk_uint32 rData) 320{ 321#if (!defined(MDC_MDIO_OPERATION) && !defined(SPI_OPERATION)) 322 rtk_int8 con; 323 rtk_uint32 ACK; 324 rtk_uint32 ret = RT_ERR_OK; 325#endif 326 327 if(mAddrs > 0xFFFF) 328 return RT_ERR_INPUT; 329 330 if(rData > 0xFFFF) 331 return RT_ERR_INPUT; 332 333#if defined(MDC_MDIO_OPERATION) 334 335 /* Lock */ 336 rtlglue_drvMutexLock(); 337 338 /* Write address control code to register 31 */ 339 MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP); 340 341 /* Write address to register 23 */ 342 MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_ADDRESS_REG, mAddrs); 343 344 /* Write data to register 24 */ 345 MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_DATA_WRITE_REG, rData); 346 347 /* Write data control code to register 21 */ 348 MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL1_REG, MDC_MDIO_WRITE_OP); 349 350 /* Unlock */ 351 rtlglue_drvMutexUnlock(); 352 353 return RT_ERR_OK; 354 355#elif defined(SPI_OPERATION) 356 357 /* Lock */ 358 rtlglue_drvMutexLock(); 359 360 /* Write 8 bits WRITE OP_CODE */ 361 SPI_WRITE(SPI_WRITE_OP, SPI_WRITE_OP_LEN); 362 363 /* Write 16 bits register address */ 364 SPI_WRITE(mAddrs, SPI_REG_LEN); 365 366 /* Write 16 bits data */ 367 SPI_WRITE(rData, SPI_DATA_LEN); 368 369 /* Unlock */ 370 rtlglue_drvMutexUnlock(); 371 372 return RT_ERR_OK; 373#else 374#ifndef _CFE_ 375 unsigned long flags; 376#endif 377 378 /*Disable CPU interrupt to ensure that the SMI operation is atomic. 379 The API is based on RTL865X, rewrite the API if porting to other platform.*/ 380 rtlglue_drvMutexLock(); 381 382 _smi_start(); /* Start SMI */ 383 384 _smi_writeBit(0x0b, 4); /* CTRL code: 4'b1011 for RTL8370*/ 385 386 _smi_writeBit(0x4, 3); /* CTRL code: 3'b100 */ 387 388 _smi_writeBit(0x0, 1); /* 0: issue WRITE command */ 389 390 con = 0; 391 do { 392 con++; 393 _smi_readBit(1, &ACK); /* ACK for issuing WRITE command*/ 394 } while ((ACK != 0) && (con < ack_timer)); 395 if (ACK != 0) ret = RT_ERR_FAILED; 396 397 _smi_writeBit((mAddrs&0xff), 8); /* Set reg_addr[7:0] */ 398 399 con = 0; 400 do { 401 con++; 402 _smi_readBit(1, &ACK); /* ACK for setting reg_addr[7:0] */ 403 } while ((ACK != 0) && (con < ack_timer)); 404 if (ACK != 0) ret = RT_ERR_FAILED; 405 406 _smi_writeBit((mAddrs>>8), 8); /* Set reg_addr[15:8] */ 407 408 con = 0; 409 do { 410 con++; 411 _smi_readBit(1, &ACK); /* ACK for setting reg_addr[15:8] */ 412 } while ((ACK != 0) && (con < ack_timer)); 413 if (ACK != 0) ret = RT_ERR_FAILED; 414 415 _smi_writeBit(rData&0xff, 8); /* Write Data [7:0] out */ 416 417 con = 0; 418 do { 419 con++; 420 _smi_readBit(1, &ACK); /* ACK for writting data [7:0] */ 421 } while ((ACK != 0) && (con < ack_timer)); 422 if (ACK != 0) ret = RT_ERR_FAILED; 423 424 _smi_writeBit(rData>>8, 8); /* Write Data [15:8] out */ 425 426 con = 0; 427 do { 428 con++; 429 _smi_readBit(1, &ACK); /* ACK for writting data [15:8] */ 430 } while ((ACK != 0) && (con < ack_timer)); 431 if (ACK != 0) ret = RT_ERR_FAILED; 432 433 _smi_stop(); 434 435 rtlglue_drvMutexUnlock();/*enable CPU interrupt*/ 436 437 return ret; 438#endif /* end of #if defined(MDC_MDIO_OPERATION) */ 439} 440 441