1 /* 2 * Copyright 2013 Freescale Semiconductor, Inc. 3 * Author: Shaveta Leekha <shaveta@freescale.com> 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of 8 * the License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 18 * MA 02111-1307 USA 19 */ 20 21 #include "idt8t49n222a_serdes_clk.h" 22 23 #define DEVICE_ID_REG 0x00 24 25 static int check_pll_status(u8 idt_addr) 26 { 27 u8 val = 0; 28 int ret; 29 30 ret = i2c_read(idt_addr, 0x17, 1, &val, 1); 31 if (ret < 0) { 32 printf("IDT:0x%x could not read status register from device.\n", 33 idt_addr); 34 return ret; 35 } 36 37 if (val & 0x04) { 38 debug("idt8t49n222a PLL is LOCKED: %x\n", val); 39 } else { 40 printf("idt8t49n222a PLL is not LOCKED: %x\n", val); 41 return -1; 42 } 43 44 return 0; 45 } 46 47 int set_serdes_refclk(u8 idt_addr, u8 serdes_num, 48 enum serdes_refclk refclk1, 49 enum serdes_refclk refclk2, u8 feedback) 50 { 51 u8 dev_id = 0; 52 int i, ret; 53 54 debug("IDT:Configuring idt8t49n222a device at I2C address: 0x%2x\n", 55 idt_addr); 56 57 ret = i2c_read(idt_addr, DEVICE_ID_REG, 1, &dev_id, 1); 58 if (ret < 0) { 59 debug("IDT:0x%x could not read DEV_ID from device.\n", 60 idt_addr); 61 return ret; 62 } 63 64 if ((dev_id != 0x00) && (dev_id != 0x24) && (dev_id != 0x2a)) { 65 debug("IDT: device at address 0x%x is not idt8t49n222a.\n", 66 idt_addr); 67 } 68 69 if (serdes_num != 1 && serdes_num != 2) { 70 debug("serdes_num should be 1 for SerDes1 and" 71 " 2 for SerDes2.\n"); 72 return -1; 73 } 74 75 if ((refclk1 == SERDES_REFCLK_122_88 && refclk2 != SERDES_REFCLK_122_88) 76 || (refclk1 != SERDES_REFCLK_122_88 77 && refclk2 == SERDES_REFCLK_122_88)) { 78 debug("Only one refclk at 122.88MHz is not supported." 79 " Please set both refclk1 & refclk2 to 122.88MHz" 80 " or both not to 122.88MHz.\n"); 81 return -1; 82 } 83 84 if (refclk1 != SERDES_REFCLK_100 && refclk1 != SERDES_REFCLK_122_88 85 && refclk1 != SERDES_REFCLK_125 86 && refclk1 != SERDES_REFCLK_156_25) { 87 debug("refclk1 should be 100MHZ, 122.88MHz, 125MHz" 88 " or 156.25MHz.\n"); 89 return -1; 90 } 91 92 if (refclk2 != SERDES_REFCLK_100 && refclk2 != SERDES_REFCLK_122_88 93 && refclk2 != SERDES_REFCLK_125 94 && refclk2 != SERDES_REFCLK_156_25) { 95 debug("refclk2 should be 100MHZ, 122.88MHz, 125MHz" 96 " or 156.25MHz.\n"); 97 return -1; 98 } 99 100 if (feedback != 0 && feedback != 1) { 101 debug("valid values for feedback are 0(default) or 1.\n"); 102 return -1; 103 } 104 105 /* Configuring IDT for output refclks as 106 * Refclk1 = 122.88MHz Refclk2 = 122.88MHz 107 */ 108 if (refclk1 == SERDES_REFCLK_122_88 && 109 refclk2 == SERDES_REFCLK_122_88) { 110 printf("Setting refclk1:122.88 and refclk2:122.88\n"); 111 for (i = 0; i < NUM_IDT_REGS; i++) 112 i2c_reg_write(idt_addr, idt_conf_122_88[i][0], 113 idt_conf_122_88[i][1]); 114 115 if (feedback) { 116 for (i = 0; i < NUM_IDT_REGS_FEEDBACK; i++) 117 i2c_reg_write(idt_addr, 118 idt_conf_122_88_feedback[i][0], 119 idt_conf_122_88_feedback[i][1]); 120 } 121 } 122 123 if (refclk1 != SERDES_REFCLK_122_88 && 124 refclk2 != SERDES_REFCLK_122_88) { 125 for (i = 0; i < NUM_IDT_REGS; i++) 126 i2c_reg_write(idt_addr, idt_conf_not_122_88[i][0], 127 idt_conf_not_122_88[i][1]); 128 } 129 130 /* Configuring IDT for output refclks as 131 * Refclk1 = 100MHz Refclk2 = 125MHz 132 */ 133 if (refclk1 == SERDES_REFCLK_100 && refclk2 == SERDES_REFCLK_125) { 134 printf("Setting refclk1:100 and refclk2:125\n"); 135 i2c_reg_write(idt_addr, 0x11, 0x10); 136 } 137 138 /* Configuring IDT for output refclks as 139 * Refclk1 = 125MHz Refclk2 = 125MHz 140 */ 141 if (refclk1 == SERDES_REFCLK_125 && refclk2 == SERDES_REFCLK_125) { 142 printf("Setting refclk1:125 and refclk2:125\n"); 143 i2c_reg_write(idt_addr, 0x10, 0x10); 144 i2c_reg_write(idt_addr, 0x11, 0x10); 145 } 146 147 /* Configuring IDT for output refclks as 148 * Refclk1 = 125MHz Refclk2 = 100MHz 149 */ 150 if (refclk1 == SERDES_REFCLK_125 && refclk2 == SERDES_REFCLK_100) { 151 printf("Setting refclk1:125 and refclk2:100\n"); 152 i2c_reg_write(idt_addr, 0x10, 0x10); 153 } 154 155 /* Configuring IDT for output refclks as 156 * Refclk1 = 156.25MHz Refclk2 = 156.25MHz 157 */ 158 if (refclk1 == SERDES_REFCLK_156_25 && 159 refclk2 == SERDES_REFCLK_156_25) { 160 printf("Setting refclk1:156.25 and refclk2:156.25\n"); 161 for (i = 0; i < NUM_IDT_REGS_156_25; i++) 162 i2c_reg_write(idt_addr, idt_conf_156_25[i][0], 163 idt_conf_156_25[i][1]); 164 } 165 166 /* Configuring IDT for output refclks as 167 * Refclk1 = 100MHz Refclk2 = 156.25MHz 168 */ 169 if (refclk1 == SERDES_REFCLK_100 && 170 refclk2 == SERDES_REFCLK_156_25) { 171 printf("Setting refclk1:100 and refclk2:156.25\n"); 172 for (i = 0; i < NUM_IDT_REGS_156_25; i++) 173 i2c_reg_write(idt_addr, idt_conf_100_156_25[i][0], 174 idt_conf_100_156_25[i][1]); 175 } 176 177 /* Configuring IDT for output refclks as 178 * Refclk1 = 125MHz Refclk2 = 156.25MHz 179 */ 180 if (refclk1 == SERDES_REFCLK_125 && 181 refclk2 == SERDES_REFCLK_156_25) { 182 printf("Setting refclk1:125 and refclk2:156.25\n"); 183 for (i = 0; i < NUM_IDT_REGS_156_25; i++) 184 i2c_reg_write(idt_addr, idt_conf_125_156_25[i][0], 185 idt_conf_125_156_25[i][1]); 186 } 187 188 /* Configuring IDT for output refclks as 189 * Refclk1 = 156.25MHz Refclk2 = 100MHz 190 */ 191 if (refclk1 == SERDES_REFCLK_156_25 && 192 refclk2 == SERDES_REFCLK_100) { 193 printf("Setting refclk1:156.25 and refclk2:100\n"); 194 for (i = 0; i < NUM_IDT_REGS_156_25; i++) 195 i2c_reg_write(idt_addr, idt_conf_156_25_100[i][0], 196 idt_conf_156_25_100[i][1]); 197 } 198 199 /* Configuring IDT for output refclks as 200 * Refclk1 = 156.25MHz Refclk2 = 125MHz 201 */ 202 if (refclk1 == SERDES_REFCLK_156_25 && 203 refclk2 == SERDES_REFCLK_125) { 204 printf("Setting refclk1:156.25 and refclk2:125\n"); 205 for (i = 0; i < NUM_IDT_REGS_156_25; i++) 206 i2c_reg_write(idt_addr, idt_conf_156_25_125[i][0], 207 idt_conf_156_25_125[i][1]); 208 } 209 210 /* waiting for maximum of 1 second if PLL doesn'r get locked 211 * initially. then check the status again. 212 */ 213 if (check_pll_status(idt_addr)) { 214 mdelay(1000); 215 if (check_pll_status(idt_addr)) 216 return -1; 217 } 218 219 return 0; 220 } 221