openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

w229b.c (23816B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * BCM56xx I2C Device Driver for Cypress W229B/W311 Clock generator (PLL) chip.
      8  * The W229b is a highly integrated frequency timing generator,
      9  * supplying a variety of common clock sources.
     10  *
     11  * The W311 is a more robust version of the W229b which allows for
     12  * read capability and arbitrary SMB byte, word, or block operations.
     13  *
     14  * This driver supports both the W229b (for downward compatibility
     15  * with older 5605 baseboards) as well as the W311 chip. In order to
     16  * determine if we are running in W311 mode, we attempt to read the
     17  * W311 device and vendor Id from register offset 8; if this succeeds,
     18  * then we assume that we are communicating with a W311.
     19  *
     20  * The W229b clock frequency configuration is table driven, the W311
     21  * uses M and N values to set the clock frequency. In addition, the
     22  * W311 allows setting of the clock frequency and then later reading
     23  * it back.
     24  *
     25  * On Broadcom BCM95605 baseboards, the W229b clock chip is used to
     26  * supply the 5605/5606 baseboard with a core clock. On new Broadcom
     27  * BCM5605 baseboards and 48port (p48) boards, the W311 chip is used
     28  * instead.
     29  *
     30  * In W229b data sheet, the CPU clock is the switch core clock in
     31  * Table 4. The same holds true for the W311.
     32  *
     33  * For W229b, in the ioctl interface to this driver, if the clock
     34  * value supplied is in between the higher and lower value, we pick
     35  * the lower value.
     36  *
     37  * See the Cypress W229B/W311 Clock chip data sheet(s) for more details.
     38  */
     39 #include <sal/types.h>
     40 #include <soc/debug.h>
     41 #include <soc/drv.h>
     42 #include <soc/error.h>
     43 #include <soc/i2c.h>
     44 #include <shared/bsl.h>
     45 /* W229B Command code : Always Zero */
     46 #define W229B_COMM_CODE     0x00000000
     47 #define W229B_N_REGS        7 /* Bytes 0 - 6 */
     48 
     49 /*
     50  * Definitions for Control Byte 4: SEL bits for freq select
     51  * Return byte represent SEL values with FS override set (SEL selects
     52  * the operating frequency). Used for both W229/W311 clock chips.
     53  */
     54 #define W229_SPEED(s4, s3, s2, s1, s0)\
     55 ( (s3 << 7) | (s2 << 6) | (s1 << 5)|(s0 << 4)|(1 << 3)|(s4 << 2) )
     56 
     57 #define W311_SPEED(s4, s3, s2, s1, s0)\
     58   ( (s4 << 5) | (s3 << 4) | (s2 << 3)|(s1 << 2)|(s0 << 1)|s0)
     59 
     60 
     61 /* W229b: Min Freq = 66Mhz, Max = 166Mhz */
     62 #define W229B_MIN_SPEED   66000000
     63 #define W229B_MAX_SPEED  166000000
     64 
     65 /* W229b: Default Control/Reserved registers: Bytes0-3 */
     66 #define W229B_R0    0x06
     67 #define W229B_R1    0xff
     68 #define W229B_R2    0xff
     69 #define W229B_R3    0x08
     70 #define W229B_CNT   5  /* 5 byte SMB block write */
     71 
     72 /* Constants for conversions */
     73 #define MHZ    1000*1000
     74 #define Megahertz(x) ((x)*MHZ)
     75 
     76 /* W311 Definitions */
     77 #define W311_ID_REG 0x08
     78 #define W311_CTRL_REG1 0x01
     79 #define W311_N_REG  0X0d /* N Register */
     80 #define W311_M_REG  0x0e /* M Register (and programmable freq enable)*/
     81 #ifdef	COMPILER_HAS_DOUBLE
     82 #define W311_GEAR_CONSTANT 48.00741
     83 #else
     84 #define W311_GEAR_CONSTANT 48007410
     85 #endif
     86 #define W311_M_LOWSPEED  93 /* 50-129 Mhz */
     87 #define W311_M_HIGHSPEED 45 /* 130-248 Mhz */
     88 #define W311_FS_REG  0x0f /* Reserved reg for latched FS_Sel bits */
     89 
     90 /* Byte or Word Command Operationse */
     91 #define W311_COMM_CODE(addr)    (0x80|(addr))
     92 
     93 /* Min and Max clock output values */
     94 #define W311_MIN_CLOCK     50
     95 #define W311_MAX_CLOCK     258
     96 
     97 /* Low scale Mhz range for LOWSPEED M value, in this range of
     98  * frequencies, clock output is tunable to 0.5Mhz resolution!
     99  * So, 126.5 is possible,  however 132.5 is not.
    100  */
    101 #define W311_LOW_MIN       50
    102 #define W311_LOW_MAX       129
    103 
    104 /* Spread spectrum defines for W311 clock chip.
    105  * Bit definitions for Byte 1 (Control register 1)
    106  */
    107 #define W311_SS_CLEAR            0x0f
    108 #define W311_SS_TRISTATE         (0x30)
    109 #define W311_SS_ENABLE_NEG5 	 (0x40)
    110 #define W311_SS_ENABLE_5_5	 (0x50)
    111 #define W311_SS_ENABLE_2_5	 (0x60)
    112 #define W311_SS_ENABLE_3_8	 (0x70)
    113 
    114 /* Useful macros */
    115 #define W311_SS_SET_DISABLE(x)       ((x) & W311_SS_CLEAR)
    116 #define W311_SS_SET_ENABLE_NEG5(x)   ((x) | W311_SS_ENABLE_NEG5) /* -0.50% */
    117 #define W311_SS_SET_ENABLE_5_5(x)    ((x) | W311_SS_ENABLE_5_5) /* +/- 0.50% */
    118 #define W311_SS_SET_ENABLE_2_5(x)    ((x) | W311_SS_ENABLE_2_5) /* +/- 0.25% */
    119 #define W311_SS_SET_ENABLE_3_8(x)    ((x) | W311_SS_ENABLE_3_8) /* +/- 0.38% */
    120 
    121 /* Decimal point formatting */
    122 #define INT_FRAC_2PT_4(x) (x) / 1000000, ((x) / 10000) % 100
    123 
    124 /* Whether we are in W311 mode or W229b mode */
    125 static int is311 = FALSE;
    126 
    127 /*
    128  * Data: w311_freq_tab
    129  * Purpose: Table 5 in W311 DataSheet.
    130  *          This table encodes the FS_Sel bits of the W311 clock speeds
    131  *          found in the pin strapping option which is read-only
    132  *          via reserved register 15 (0xf)
    133  * NOTE: This table is used for retrieving hardwired speeds, it does
    134  *       not need to be sorted by frequency.
    135  */
    136 #ifdef	COMPILER_HAS_DOUBLE
    137 static struct
    138 w311_freq_tab_s{
    139     uint8 control;
    140     double speed; /* In Mhz */
    141 } w311_freq_tab[] = {
    142     { W311_SPEED(0,0,0,0,0), 200.0},
    143     { W311_SPEED(0,0,0,0,1), 190.0},
    144     { W311_SPEED(0,0,0,1,0), 180.0},
    145     { W311_SPEED(0,0,0,1,1), 170.0},
    146     { W311_SPEED(0,0,1,0,0), 166.0},
    147     { W311_SPEED(0,0,1,0,1), 160.0},
    148     { W311_SPEED(0,0,1,1,0), 150.0},
    149     { W311_SPEED(0,0,1,1,1), 145.0},
    150     { W311_SPEED(0,1,0,0,0), 140.0},
    151     { W311_SPEED(0,1,0,0,1), 136.0},
    152     { W311_SPEED(0,1,0,1,0), 130.0},
    153     { W311_SPEED(0,1,0,1,1), 124.0},
    154     { W311_SPEED(0,1,1,0,0),  66.6},
    155     { W311_SPEED(0,1,1,0,1), 100.0},
    156     { W311_SPEED(0,1,1,1,0), 118.0},
    157     { W311_SPEED(0,1,1,1,1), 133.3},
    158     { W311_SPEED(1,0,0,0,0),  66.8},
    159     { W311_SPEED(1,0,0,0,1), 100.2},
    160     { W311_SPEED(1,0,0,1,0), 115.0},
    161     { W311_SPEED(1,0,0,1,1), 133.6},
    162     { W311_SPEED(1,0,1,0,0),  66.8},
    163     { W311_SPEED(1,0,1,0,1), 100.2},
    164     { W311_SPEED(1,0,1,1,0), 110.0},
    165     { W311_SPEED(1,0,1,1,1), 133.6},
    166     { W311_SPEED(1,1,0,0,0), 105.0},
    167     { W311_SPEED(1,1,0,0,1),  90.0},
    168     { W311_SPEED(1,1,0,1,0),  85.0},
    169     { W311_SPEED(1,1,0,1,1),  78.0},
    170     { W311_SPEED(1,1,1,0,0),  66.6},
    171     { W311_SPEED(1,1,1,0,1), 100.0},
    172     { W311_SPEED(1,1,1,1,0),  75.0},
    173     { W311_SPEED(1,1,1,1,1), 133.33},
    174 };
    175 #else
    176 static struct
    177 w311_freq_tab_s{
    178     uint8 control;
    179     int speed; /* In Hz */
    180 } w311_freq_tab[] = {
    181     { W311_SPEED(0,0,0,0,0), 200000000}, /* 200.00 MHz */
    182     { W311_SPEED(0,0,0,0,1), 190000000}, /* 190.00 MHz */
    183     { W311_SPEED(0,0,0,1,0), 180000000}, /* 180.00 MHz */
    184     { W311_SPEED(0,0,0,1,1), 170000000}, /* 170.00 MHz */
    185     { W311_SPEED(0,0,1,0,0), 166000000}, /* 166.00 MHz */
    186     { W311_SPEED(0,0,1,0,1), 160000000}, /* 160.00 MHz */
    187     { W311_SPEED(0,0,1,1,0), 150000000}, /* 150.00 MHz */
    188     { W311_SPEED(0,0,1,1,1), 145000000}, /* 145.00 MHz */
    189     { W311_SPEED(0,1,0,0,0), 140000000}, /* 140.00 MHz */
    190     { W311_SPEED(0,1,0,0,1), 136000000}, /* 136.00 MHz */
    191     { W311_SPEED(0,1,0,1,0), 130000000}, /* 130.00 MHz */
    192     { W311_SPEED(0,1,0,1,1), 124000000}, /* 124.00 MHz */
    193     { W311_SPEED(0,1,1,0,0),  66600000}, /*  66.60 MHz */
    194     { W311_SPEED(0,1,1,0,1), 100000000}, /* 100.00 MHz */
    195     { W311_SPEED(0,1,1,1,0), 118000000}, /* 118.00 MHz */
    196     { W311_SPEED(0,1,1,1,1), 133300000}, /* 133.30 MHz */
    197     { W311_SPEED(1,0,0,0,0),  66800000}, /*  66.80 MHz */
    198     { W311_SPEED(1,0,0,0,1), 100200000}, /* 100.20 MHz */
    199     { W311_SPEED(1,0,0,1,0), 115000000}, /* 115.00 MHz */
    200     { W311_SPEED(1,0,0,1,1), 133600000}, /* 133.60 MHz */
    201     { W311_SPEED(1,0,1,0,0),  66800000}, /*  66.80 MHz */
    202     { W311_SPEED(1,0,1,0,1), 100200000}, /* 100.20 MHz */
    203     { W311_SPEED(1,0,1,1,0), 110000000}, /* 110.00 MHz */
    204     { W311_SPEED(1,0,1,1,1), 133600000}, /* 133.60 MHz */
    205     { W311_SPEED(1,1,0,0,0), 105000000}, /* 105.00 MHz */
    206     { W311_SPEED(1,1,0,0,1),  90000000}, /*  90.00 MHz */
    207     { W311_SPEED(1,1,0,1,0),  85000000}, /*  85.00 MHz */
    208     { W311_SPEED(1,1,0,1,1),  78000000}, /*  78.00 MHz */
    209     { W311_SPEED(1,1,1,0,0),  66600000}, /*  66.60 MHz */
    210     { W311_SPEED(1,1,1,0,1), 100000000}, /* 100.00 MHz */
    211     { W311_SPEED(1,1,1,1,0),  75000000}, /*  75.00 MHz */
    212     { W311_SPEED(1,1,1,1,1), 133330000}, /* 133.33 MHz */
    213 };
    214 #endif
    215 #define N_W311_FREQS   COUNTOF(w311_freq_tab)
    216 
    217 /*
    218  * Data: w229b_freq_tab
    219  * Purpose: Table 4: Reserved Register Settings (CPU output frequencies and
    220  *          their SEL bits, sorted by frequency): Byte 4
    221  */
    222 static struct
    223 w229b_freq_tab_s{
    224     uint8 control;
    225     uint32 speed;
    226 } w229b_freq_tab[] = {
    227     { W229_SPEED(0,1,0,0,0),  66300000}, /* 66.3Mhz   */
    228     { W229_SPEED(1,1,1,0,0),  66600000}, /* 66.6Mhz   */
    229     { W229_SPEED(0,1,1,0,0),  66800000}, /* 66.8Mhz   */
    230     { W229_SPEED(0,0,0,0,0),  75300000}, /* 75.3Mhz   */
    231     { W229_SPEED(1,1,0,0,1),  78000000}, /* 78Mhz     */
    232     { W229_SPEED(1,1,0,0,0),  80000000}, /* 80Mhz     */
    233     { W229_SPEED(0,0,0,0,1),  95000000}, /* 95Mhz     */
    234     { W229_SPEED(1,1,1,0,1), 100000000}, /* 100Mhz    */
    235     { W229_SPEED(0,1,1,0,1), 100200000}, /* 100.2Mhz  */
    236     { W229_SPEED(0,1,0,0,1), 105000000}, /* 105Mhz    */
    237     { W229_SPEED(0,0,1,0,1), 110000000}, /* 110Mhz    */
    238     { W229_SPEED(1,0,1,1,1), 114000000}, /* 114Mhz    */
    239     { W229_SPEED(1,0,1,1,0), 117000000}, /* 117Mhz    */
    240     { W229_SPEED(1,0,0,1,1), 122000000}, /* 122Mhz    */
    241     { W229_SPEED(1,0,1,0,1), 122000000}, /* 122Mhz    */
    242     { W229_SPEED(1,0,1,0,0), 127000000}, /* 127Mhz    */
    243     { W229_SPEED(0,0,0,1,0), 129000000}, /* 129Mhz    */
    244     { W229_SPEED(1,1,1,1,0), 133300000}, /* 133.3Mhz  */
    245     { W229_SPEED(1,1,1,1,1), 133300000}, /* 133.3Mhz  */
    246     { W229_SPEED(1,1,0,1,1), 133600000}, /* 133.6Mhz  */
    247     { W229_SPEED(0,1,1,1,0), 133600000}, /* 133.6Mhz  */
    248     { W229_SPEED(0,1,1,1,1), 133600000}, /* 133.6Mhz  */
    249     { W229_SPEED(0,1,0,1,0), 138000000}, /* 138Mhz    */
    250     { W229_SPEED(0,0,1,1,0), 140000000}, /* 140Mhz    */
    251     { W229_SPEED(0,1,0,1,1), 140000000}, /* 140Mhz    */
    252     { W229_SPEED(0,0,1,1,1), 144000000}, /* 144Mhz    */
    253     { W229_SPEED(0,0,0,1,1), 150000000}, /* 150Mhz    */
    254     { W229_SPEED(0,0,1,0,0), 150000000}, /* 150Mhz    */
    255     { W229_SPEED(1,0,0,0,0), 157300000}, /* 157.3Mhz  */
    256     { W229_SPEED(1,0,0,0,1), 160000000}, /* 160Mhz    */
    257     { W229_SPEED(1,1,0,1,0), 166000000}, /* 166Mhz    */
    258 };
    259 #define N_W229B_FREQS   COUNTOF(w229b_freq_tab)
    260 
    261 static uint8 w229_regvals[W229B_N_REGS];
    262 
    263 /*
    264  * Create control word for SMB word write operation updating N and M.
    265  */
    266 STATIC uint16
    267 w311_control_word(uint8 n, uint8 m)
    268 {
    269     uint16 tmp;
    270     m |= 0x80; /* Programmable frequency enable */
    271     tmp = m;
    272     tmp <<= 8;
    273     tmp |= n;
    274     return tmp;
    275 }
    276 
    277 STATIC void
    278 w311_ss_print(char* pfx, uint8 cb)
    279 {
    280     char* modeStr = NULL;
    281     if( cb == W311_SS_CLEAR)
    282 	modeStr = "(off)";
    283     else if( cb == (W311_SS_ENABLE_NEG5 | W311_SS_CLEAR))
    284 	modeStr = "enabled (-0.5%)";
    285     else if( cb == (W311_SS_ENABLE_5_5 | W311_SS_CLEAR))
    286 	modeStr = "enabled (+/-0.5%)";
    287     else if( cb == (W311_SS_ENABLE_2_5 | W311_SS_CLEAR))
    288 	modeStr = "enabled (+/- 0.25%)";
    289     else if( cb == (W311_SS_ENABLE_3_8 | W311_SS_CLEAR))
    290 	modeStr = "enabled (+/- 0.38%)";
    291     else
    292 	modeStr = "unknown";
    293     LOG_CLI((BSL_META("w311: %s spread spectrum %s (0x%x)\n"), pfx, modeStr, cb));
    294 }
    295 
    296 /*
    297  * Function: w311_ioctl
    298  *
    299  * Purpose: Given an input speed (clock frequency), tell W311 to
    300  *          output that frequency for core switch clocks.
    301  *
    302  *          If the user provides a data pointer, we simply query the chip for
    303  *          the clock speed and return the data in an integer format.
    304  *
    305  *          The user provides speed value in opcode, we check that the value
    306  *          is in range, and if so, we compute M/N and program the
    307  *          chip. If data is non-null, we simply return the current speed.
    308  *
    309  * Parameters:
    310  *    unit - StrataSwitch device number or I2C bus number
    311  *    devno - chip device id
    312  *    opcode - clock speed value, if less than 1Mhz, multiplied by 1Mhz
    313  *    data - if not-null, we return the clock speed read from the device.
    314  *    len - unused
    315  *
    316  * Returns:
    317  *     SOC_E_NONE - no error
    318  *     SOC_E_TIMEOUT - chip temperature reading unavailable or IO error.
    319  */
    320 STATIC int
    321 w311_ioctl(int unit, int devno,
    322 	   int opcode, void* data, int len)
    323 {
    324     int  i, rv = SOC_E_NONE;
    325     uint8 m,n,saddr = soc_i2c_addr(unit, devno);
    326 #ifdef	COMPILER_HAS_DOUBLE
    327     double val = 0, speed = 0;
    328 #else
    329     int val = 0, speed = 0;
    330 #endif
    331     uint16 nm;
    332 
    333     if(!data)
    334         return SOC_E_PARAM;
    335 
    336     if( opcode == I2C_PLL_W311_SETSPEED ){
    337 
    338 	/* Grab requested value */
    339 #ifdef	COMPILER_HAS_DOUBLE
    340 	speed = *((double*)data);
    341 
    342 	/* Convert to MHZ if short form given */
    343 	if ( speed < MHZ  )
    344 	    speed *= MHZ;
    345 	LOG_VERBOSE(BSL_LS_SOC_COMMON,
    346                     (BSL_META_U(unit,
    347                                 "Speed requested = %2.2f\n"), speed));
    348 #else
    349 	speed = *((int*)data);
    350 	LOG_VERBOSE(BSL_LS_SOC_COMMON,
    351                     (BSL_META_U(unit,
    352                                 "Speed requested = %d.%02d\n"), 
    353                      INT_FRAC_2PT_4(speed)));
    354 #endif
    355 
    356 	if((int)speed < Megahertz(W311_MIN_CLOCK) ||
    357 	   (int)speed > Megahertz(W311_MAX_CLOCK)){
    358 	    LOG_ERROR(BSL_LS_SOC_I2C,
    359                       (BSL_META_U(unit,
    360                                   "unit %d i2c %s: invalid clock speed %dMhz,"
    361                                   " valid range %d:%dMHz\n"),
    362                        unit, soc_i2c_devname(unit,devno),
    363                        (int)speed / MHZ, W311_MIN_CLOCK, W311_MAX_CLOCK));
    364 	    return SOC_E_PARAM;
    365 	}
    366 
    367 	if( (int)speed >= Megahertz(W311_LOW_MIN) &&
    368 	    (int)speed <= Megahertz(W311_LOW_MAX))
    369 	    m = W311_M_LOWSPEED ;
    370 	else
    371 	    m = W311_M_HIGHSPEED ;
    372 	/*
    373 	 * The new frequency will start to load whenever there is an
    374 	 * update to either CPU_FSEL_N[7:0] or CPU_FSEL_M[6:0], therefore,
    375 	 * it is recommended by Cypress that Word or Block write be used
    376 	 * to update both registers in one SMBus transaction.
    377 	 */
    378 	/* FCpu = G * (N+3)/(M+3)
    379 	 * n = ((FCpu * (M+3)) / G) - 3
    380 	 */
    381 #ifdef	COMPILER_HAS_DOUBLE
    382 	speed /= MHZ;
    383 	val = ( ( (speed * (m + 3) ) / W311_GEAR_CONSTANT) - 3.0) + 0.5;
    384 #else
    385 	val = ( ( (speed * (m + 3) ) / W311_GEAR_CONSTANT) - 3);
    386 #endif
    387 	n = (uint8) val;
    388 	nm = w311_control_word(n, m);
    389 #ifdef	COMPILER_HAS_DOUBLE
    390 	LOG_VERBOSE(BSL_LS_SOC_COMMON,
    391                     (BSL_META_U(unit,
    392                                 "w311: set speed=%2.2f n(fp)=%f (m=%d n=%d) hwval=0x%x\n"),
    393                      speed, val, m, n, nm));
    394 #else
    395 	LOG_VERBOSE(BSL_LS_SOC_COMMON,
    396                     (BSL_META_U(unit,
    397                                 "w311: set speed=%d.%02d n(fp)=%d (m=%d n=%d) hwval=0x%x\n"),
    398                      INT_FRAC_2PT_4(speed), val, m, n, nm));
    399 #endif
    400 	rv = soc_i2c_write_word_data(unit, saddr,
    401 				     W311_COMM_CODE(W311_N_REG), nm);
    402 	return rv;
    403     }
    404 
    405 
    406     if( opcode == I2C_PLL_W311_GETSPEED ){
    407 
    408 	/* Read M/N values and compute frequency .. */
    409 	rv = soc_i2c_read_word_data(unit, saddr,
    410 				    W311_COMM_CODE(W311_N_REG), &nm);
    411 
    412 	m = (uint8)(nm >> 8 & 0x00ff);
    413 	m &= ~0x80;
    414 	n = (uint8)nm;
    415 
    416 
    417 	/*
    418 	 * User did not program clock via M/N method, read hardwired
    419 	 * freq from latched FS-Sel pins and do table-lookup for
    420 	 * frequency.
    421 	 */
    422 	if( nm == 0){
    423 	    rv = soc_i2c_read_byte_data(unit, saddr,
    424 					W311_COMM_CODE(W311_FS_REG), &n);
    425 	    n &= ~(0x07);
    426 	    n >>= 3;
    427 
    428 	    /* FS0,1,2 */
    429 #ifdef	COMPILER_HAS_DOUBLE
    430 #ifdef CLOCK_DEBUG
    431 	    LOG_VERBOSE(BSL_LS_SOC_COMMON,
    432                         (BSL_META_U(unit,
    433                                     "w311: FS_Sel[0:4]=0x%x f=%2.2f\n"),
    434                          n,0.0));
    435 #endif
    436 	    *((double*)data) = 0.0;
    437 #else
    438 	    *((int*)data) = 0;
    439 #endif
    440 
    441 	    /* Look for table match */
    442 	    for ( i = 0; i < N_W311_FREQS; i++) {
    443 #ifdef CLOCK_DEBUG
    444 		LOG_VERBOSE(BSL_LS_SOC_COMMON,
    445                             (BSL_META_U(unit,
    446                                         "n=0x%x tab=0x%x\n"),
    447                              n, w311_freq_tab[i].control));
    448 #endif
    449 		if(n == w311_freq_tab[i].control){
    450 #ifdef	COMPILER_HAS_DOUBLE
    451 		    *((double*)data) = w311_freq_tab[i].speed;
    452 #else
    453 		    *((int*)data) = w311_freq_tab[i].speed;
    454 #endif
    455 		}
    456 
    457 	    }
    458 	}
    459 	else {
    460 #ifdef	COMPILER_HAS_DOUBLE
    461 #ifdef CLOCK_DEBUG
    462 	    LOG_VERBOSE(BSL_LS_SOC_COMMON,
    463                         (BSL_META_U(unit,
    464                                     "w311: m/n=0x%x m=0x%x n=0x%x, f=%2.2f\n"),
    465                          nm, m, n,
    466                          (W311_GEAR_CONSTANT * (( n + 3.0)/(m + 3.0)))));
    467 #endif
    468 	    /* Compute freq from data-sheet */
    469 	    *((double*)data) = (W311_GEAR_CONSTANT * (( n + 3.0)/(m + 3.0)));
    470 #else
    471 	    *((int*)data) = (W311_GEAR_CONSTANT * (( n + 3)/(m + 3)));
    472 #endif
    473 	}
    474     }
    475 
    476     if(opcode == I2C_PLL_W311_GETSPREAD){
    477 	uint8 cb = 0;
    478 	rv =soc_i2c_read_byte_data(unit, saddr,
    479 				   W311_COMM_CODE(W311_CTRL_REG1),&cb);
    480 
    481 	if (cb == W311_SS_CLEAR)
    482 	    *((int*)data)=0;
    483 	else
    484 	    *((int*)data)=1;
    485     }
    486 
    487     if(opcode == I2C_PLL_W311_SPREAD){
    488 
    489 	uint8 cb = 0;
    490 	int mode = *((int*)data);
    491 	/*
    492 	 * W311 Byte1: Control Register 1
    493 	 */
    494 	if((rv =soc_i2c_read_byte_data(unit, saddr,
    495 				       W311_COMM_CODE(W311_CTRL_REG1),&cb))<0){
    496 	    LOG_ERROR(BSL_LS_SOC_I2C,
    497                       (BSL_META_U(unit,
    498                                   "w311: could not read W311 byte1, control reg1!\n")));
    499 	}
    500 
    501 	/* Show current mode decoding */
    502 	w311_ss_print("current",cb);
    503 
    504 	/* If user didn't input mode, just quit */
    505 	if((mode < I2C_PLL_SPREAD_NONE) || (mode > I2C_PLL_SPREAD_3_8)) {
    506 	    return rv;
    507         }
    508 
    509 	switch(mode){
    510 
    511 	case I2C_PLL_SPREAD_NONE:
    512 	    cb = W311_SS_SET_DISABLE(cb);
    513 	    break;
    514 	case I2C_PLL_SPREAD_NEG5:
    515 	    cb = W311_SS_SET_ENABLE_NEG5(cb);
    516 	    break;
    517 	case I2C_PLL_SPREAD_5_5:
    518 	    cb = W311_SS_SET_ENABLE_5_5(cb);
    519 	    break;
    520 	case I2C_PLL_SPREAD_2_5:
    521 	    cb = W311_SS_SET_ENABLE_2_5(cb);
    522 	    break;
    523 	case I2C_PLL_SPREAD_3_8:
    524 	    cb = W311_SS_SET_ENABLE_3_8(cb);
    525 	    break;
    526         /*
    527          mode is validated above. So the default case is never used.
    528 	default:
    529 	    LOG_ERROR(BSL_LS_SOC_I2C,
    530                       (BSL_META_U(unit,
    531                                   "w311: spread spectrum error: no mode %d\n"), mode));
    532 	    break;
    533         */
    534 	}
    535 
    536 	if((rv =soc_i2c_write_byte_data(unit, saddr,
    537 				       W311_COMM_CODE(W311_CTRL_REG1),cb))<0){
    538 	    LOG_ERROR(BSL_LS_SOC_I2C,
    539                       (BSL_META_U(unit,
    540                                   "w311: could not write W311 byte1, control reg1!\n")));
    541 	}
    542 
    543 	w311_ss_print("new", cb);
    544 	return rv;
    545     }
    546 
    547     return rv;
    548 }
    549 
    550 
    551 
    552 /*
    553  * Function: w229b_ioctl
    554  *
    555  * Purpose: Given an input speed (clock frequency), tell W229b to
    556  *          output that frequency for core switch clocks.
    557  *
    558  *          The user provides speed value in opcode, we check that the value
    559  *          is in range, and if so, we find the desired speed, and program the
    560  *          clock chip.
    561  *
    562  * Parameters:
    563  *    unit - StrataSwitch device number or I2C bus number
    564  *    devno - chip device id
    565  *    opcode - clock speed value, if less than 1Mhz, multiplied by 1Mhz
    566  *    data - unused
    567  *    len - unused
    568  *
    569  * Returns:
    570  *     SOC_E_NONE - no error
    571  *     SOC_E_TIMEOUT - chip temperature reading unavailable or IO error.
    572  */
    573 STATIC int
    574 w229b_ioctl(int unit, int devno,
    575 	   int opcode, void* data, int len)
    576 {
    577     int i, rv = SOC_E_NONE;
    578     uint8 saddr = soc_i2c_addr(unit, devno);
    579     uint32  speed = opcode;
    580 #ifdef	COMPILER_HAS_DOUBLE
    581     double val = 0;
    582 #else
    583     int val = 0;
    584 #endif
    585 
    586     /* Set Chip driver access mode first (W311 or W229b mode) */
    587     if ( data ) {
    588 	if( opcode == I2C_PLL_SETW311 ){
    589 	    is311 = * ((int*)data);
    590 	    return SOC_E_NONE;
    591 	}
    592     }
    593     /* Handle W311 differently : it does .5Mhz increments */
    594     if( is311)
    595 	return w311_ioctl(unit, devno, opcode, data, len);
    596 
    597     /* Convert to MHZ if short form given */
    598     if ( speed < MHZ  )
    599 	speed *= MHZ;
    600 
    601     if((speed > W229B_MAX_SPEED) || (speed < W229B_MIN_SPEED)){
    602 	LOG_CLI((BSL_META_U(unit,
    603                             "The following speeds are available on W229b:\n")));
    604 
    605 	for(i = 0; i < N_W229B_FREQS; i++){
    606 #ifdef	COMPILER_HAS_DOUBLE
    607 	    val = (double)w229b_freq_tab[i].speed  / (1000.0 * 1000.0) ;
    608 	    LOG_CLI((BSL_META_U(unit,
    609                                 "\t%2.2fMhz\n"), val));
    610 #else
    611 	    val = w229b_freq_tab[i].speed;
    612 	    LOG_CLI((BSL_META_U(unit,
    613                                 "\t%d.%02dMhz\n"), INT_FRAC_2PT_4(val)));
    614 #endif
    615 	}
    616 
    617 	return SOC_E_NONE;
    618     }
    619 
    620     /* Go through table, find speed match ... */
    621     for(i = 0; i < N_W229B_FREQS; i++) {
    622 
    623 	/* Load configuration defaults */
    624 	w229_regvals[0] = W229B_R0;
    625 	w229_regvals[1] = W229B_R1;
    626 	w229_regvals[2] = W229B_R2;
    627 	w229_regvals[3] = W229B_R3;
    628 
    629 	/* Load clock speed bytes : write to H/W */
    630 	w229_regvals[4] = w229b_freq_tab[i].control;
    631 
    632 	if ( speed <= w229b_freq_tab[i].speed ) {
    633 
    634 	    if ( (rv = soc_i2c_block_write(unit, saddr,
    635 					   W229B_COMM_CODE,
    636 					   W229B_CNT, w229_regvals ) ) < 0 ) {
    637 
    638             LOG_ERROR(BSL_LS_SOC_I2C,
    639                       (BSL_META_U(unit,
    640                                   "unit %d i2c %s: error on SMB block write: %s\n"),
    641                        unit, soc_i2c_devname(unit,devno),
    642                        soc_errmsg(rv)));
    643 
    644 		return rv;
    645 	    }
    646 	    soc_i2c_device(unit, devno)->tbyte += 5;
    647 #ifdef	COMPILER_HAS_DOUBLE
    648 	    val = (double)w229b_freq_tab[i].speed  / (1000.0 * 1000.0) ;
    649 	    LOG_VERBOSE(BSL_LS_SOC_COMMON,
    650                         (BSL_META_U(unit,
    651                                     "unit %d i2c %s: set W229B Clock Speed=%.2fMhz"
    652                                     " (CB=0x%x)\n"),
    653                          unit, soc_i2c_devname(unit,devno),
    654                          val, w229_regvals[4]));
    655 #else
    656 	    val = w229b_freq_tab[i].speed;
    657 	    LOG_VERBOSE(BSL_LS_SOC_COMMON,
    658                         (BSL_META_U(unit,
    659                                     "unit %d i2c %s: set W229B Clock Speed=%d.%02dMHz"
    660                                     " (CB=0x%x)\n"),
    661                          unit, soc_i2c_devname(unit,devno),
    662                          INT_FRAC_2PT_4(val), w229_regvals[4]));
    663 #endif
    664 	    break;
    665 	}
    666     }
    667     return rv;
    668 }
    669 
    670 /*
    671  * Function: w229b_init
    672  * Purpose: Initialize the W229b clock chip
    673  *
    674  * Parameters:
    675  *    unit - StrataSwitch device number or I2C bus number
    676  *    devno - chip device id
    677  *    data - not used
    678  *    len - not used
    679  *
    680  * Returns:
    681  *     SOC_E_NONE - no failure
    682  */
    683 STATIC int
    684 w229b_init(int unit, int devno,
    685 	  void* data, int len)
    686 {
    687     uint8 saddr = soc_i2c_addr(unit, devno);
    688     uint8 rev;
    689 
    690     if(is311){
    691 	/* 5615 and higher boards should have it ... */
    692 	if((soc_i2c_read_byte_data(unit, saddr, W311_ID_REG, &rev)) < 0){
    693 	    is311 = FALSE;
    694 	    soc_i2c_devdesc_set(unit, devno, "Cypress W229B Clock Chip");
    695 	} else {
    696 	    is311 = TRUE;
    697 	    soc_i2c_devdesc_set(unit, devno, "Cypress W311 Clock Chip");
    698 	    LOG_VERBOSE(BSL_LS_SOC_COMMON,
    699                         (BSL_META_U(unit,
    700                                     "%s: vendor 0x%x revision 0x%x\n"),
    701                          soc_i2c_devname(unit,devno),
    702                          rev & 0xf0,		/* Bits 0-3 */
    703                          rev & 0x0f));		/* Bits 4-7 */
    704 	}
    705     } else {
    706 	/* In a perfect world, the above detection algorithm would work,
    707 	 * but, however the w229 does not like being read from in a byte
    708 	 * read operation and hangs the I2c bus.
    709 	 */
    710 	soc_i2c_devdesc_set(unit, devno, "Cypress W229B/W311 Clock Chip");
    711     }
    712     return SOC_E_NONE;
    713 }
    714 
    715 /* NOT USED */
    716 STATIC int
    717 w229b_read(int unit, int devno,
    718 	  uint16 addr, uint8* data, uint32* len)
    719 {
    720     return SOC_E_NONE;
    721 }
    722 
    723 /* NOT USED */
    724 STATIC int
    725 w229b_write(int unit, int devno,
    726 	   uint16 addr, uint8* data, uint32 len)
    727 {
    728     return SOC_E_NONE;
    729 }
    730 
    731 /* W229B/W311 Clock Chip Driver callout */
    732 i2c_driver_t _soc_i2c_w229b_driver = {
    733     0x0, 0x0, /* System assigned bytes */
    734     W229B_DEVICE_TYPE,
    735     w229b_read,
    736     w229b_write,
    737     w229b_ioctl,
    738     w229b_init,
    739     NULL,
    740 };