Commit a4bdfff74464f86d7e3b8feaf42d18960adc5514
Committed by
David S. Miller
1 parent
7d9974666e
Exists in
master
and in
39 other branches
ks8851: Low level functions for read/write to companion eeprom
Low-level functions provide 16bits words read and write capability to ks8851 companion eeprom. Signed-off-by: Sebastien Jan <s-jan@ti.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 2 changed files with 241 additions and 1 deletions Side-by-side Diff
drivers/net/ks8851.c
... | ... | @@ -1034,6 +1034,234 @@ |
1034 | 1034 | .ndo_validate_addr = eth_validate_addr, |
1035 | 1035 | }; |
1036 | 1036 | |
1037 | +/* Companion eeprom access */ | |
1038 | + | |
1039 | +enum { /* EEPROM programming states */ | |
1040 | + EEPROM_CONTROL, | |
1041 | + EEPROM_ADDRESS, | |
1042 | + EEPROM_DATA, | |
1043 | + EEPROM_COMPLETE | |
1044 | +}; | |
1045 | + | |
1046 | +/** | |
1047 | + * ks8851_eeprom_read - read a 16bits word in ks8851 companion EEPROM | |
1048 | + * @dev: The network device the PHY is on. | |
1049 | + * @addr: EEPROM address to read | |
1050 | + * | |
1051 | + * eeprom_size: used to define the data coding length. Can be changed | |
1052 | + * through debug-fs. | |
1053 | + * | |
1054 | + * Programs a read on the EEPROM using ks8851 EEPROM SW access feature. | |
1055 | + * Warning: The READ feature is not supported on ks8851 revision 0. | |
1056 | + * | |
1057 | + * Rough programming model: | |
1058 | + * - on period start: set clock high and read value on bus | |
1059 | + * - on period / 2: set clock low and program value on bus | |
1060 | + * - start on period / 2 | |
1061 | + */ | |
1062 | +unsigned int ks8851_eeprom_read(struct net_device *dev, unsigned int addr) | |
1063 | +{ | |
1064 | + struct ks8851_net *ks = netdev_priv(dev); | |
1065 | + int eepcr; | |
1066 | + int ctrl = EEPROM_OP_READ; | |
1067 | + int state = EEPROM_CONTROL; | |
1068 | + int bit_count = EEPROM_OP_LEN - 1; | |
1069 | + unsigned int data = 0; | |
1070 | + int dummy; | |
1071 | + unsigned int addr_len; | |
1072 | + | |
1073 | + addr_len = (ks->eeprom_size == 128) ? 6 : 8; | |
1074 | + | |
1075 | + /* start transaction: chip select high, authorize write */ | |
1076 | + mutex_lock(&ks->lock); | |
1077 | + eepcr = EEPCR_EESA | EEPCR_EESRWA; | |
1078 | + ks8851_wrreg16(ks, KS_EEPCR, eepcr); | |
1079 | + eepcr |= EEPCR_EECS; | |
1080 | + ks8851_wrreg16(ks, KS_EEPCR, eepcr); | |
1081 | + mutex_unlock(&ks->lock); | |
1082 | + | |
1083 | + while (state != EEPROM_COMPLETE) { | |
1084 | + /* falling clock period starts... */ | |
1085 | + /* set EED_IO pin for control and address */ | |
1086 | + eepcr &= ~EEPCR_EEDO; | |
1087 | + switch (state) { | |
1088 | + case EEPROM_CONTROL: | |
1089 | + eepcr |= ((ctrl >> bit_count) & 1) << 2; | |
1090 | + if (bit_count-- <= 0) { | |
1091 | + bit_count = addr_len - 1; | |
1092 | + state = EEPROM_ADDRESS; | |
1093 | + } | |
1094 | + break; | |
1095 | + case EEPROM_ADDRESS: | |
1096 | + eepcr |= ((addr >> bit_count) & 1) << 2; | |
1097 | + bit_count--; | |
1098 | + break; | |
1099 | + case EEPROM_DATA: | |
1100 | + /* Change to receive mode */ | |
1101 | + eepcr &= ~EEPCR_EESRWA; | |
1102 | + break; | |
1103 | + } | |
1104 | + | |
1105 | + /* lower clock */ | |
1106 | + eepcr &= ~EEPCR_EESCK; | |
1107 | + | |
1108 | + mutex_lock(&ks->lock); | |
1109 | + ks8851_wrreg16(ks, KS_EEPCR, eepcr); | |
1110 | + mutex_unlock(&ks->lock); | |
1111 | + | |
1112 | + /* waitread period / 2 */ | |
1113 | + udelay(EEPROM_SK_PERIOD / 2); | |
1114 | + | |
1115 | + /* rising clock period starts... */ | |
1116 | + | |
1117 | + /* raise clock */ | |
1118 | + mutex_lock(&ks->lock); | |
1119 | + eepcr |= EEPCR_EESCK; | |
1120 | + ks8851_wrreg16(ks, KS_EEPCR, eepcr); | |
1121 | + mutex_unlock(&ks->lock); | |
1122 | + | |
1123 | + /* Manage read */ | |
1124 | + switch (state) { | |
1125 | + case EEPROM_ADDRESS: | |
1126 | + if (bit_count < 0) { | |
1127 | + bit_count = EEPROM_DATA_LEN - 1; | |
1128 | + state = EEPROM_DATA; | |
1129 | + } | |
1130 | + break; | |
1131 | + case EEPROM_DATA: | |
1132 | + mutex_lock(&ks->lock); | |
1133 | + dummy = ks8851_rdreg16(ks, KS_EEPCR); | |
1134 | + mutex_unlock(&ks->lock); | |
1135 | + data |= ((dummy >> EEPCR_EESB_OFFSET) & 1) << bit_count; | |
1136 | + if (bit_count-- <= 0) | |
1137 | + state = EEPROM_COMPLETE; | |
1138 | + break; | |
1139 | + } | |
1140 | + | |
1141 | + /* wait period / 2 */ | |
1142 | + udelay(EEPROM_SK_PERIOD / 2); | |
1143 | + } | |
1144 | + | |
1145 | + /* close transaction */ | |
1146 | + mutex_lock(&ks->lock); | |
1147 | + eepcr &= ~EEPCR_EECS; | |
1148 | + ks8851_wrreg16(ks, KS_EEPCR, eepcr); | |
1149 | + eepcr = 0; | |
1150 | + ks8851_wrreg16(ks, KS_EEPCR, eepcr); | |
1151 | + mutex_unlock(&ks->lock); | |
1152 | + | |
1153 | + return data; | |
1154 | +} | |
1155 | + | |
1156 | +/** | |
1157 | + * ks8851_eeprom_write - write a 16bits word in ks8851 companion EEPROM | |
1158 | + * @dev: The network device the PHY is on. | |
1159 | + * @op: operand (can be WRITE, EWEN, EWDS) | |
1160 | + * @addr: EEPROM address to write | |
1161 | + * @data: data to write | |
1162 | + * | |
1163 | + * eeprom_size: used to define the data coding length. Can be changed | |
1164 | + * through debug-fs. | |
1165 | + * | |
1166 | + * Programs a write on the EEPROM using ks8851 EEPROM SW access feature. | |
1167 | + * | |
1168 | + * Note that a write enable is required before writing data. | |
1169 | + * | |
1170 | + * Rough programming model: | |
1171 | + * - on period start: set clock high | |
1172 | + * - on period / 2: set clock low and program value on bus | |
1173 | + * - start on period / 2 | |
1174 | + */ | |
1175 | +void ks8851_eeprom_write(struct net_device *dev, unsigned int op, | |
1176 | + unsigned int addr, unsigned int data) | |
1177 | +{ | |
1178 | + struct ks8851_net *ks = netdev_priv(dev); | |
1179 | + int eepcr; | |
1180 | + int state = EEPROM_CONTROL; | |
1181 | + int bit_count = EEPROM_OP_LEN - 1; | |
1182 | + unsigned int addr_len; | |
1183 | + | |
1184 | + addr_len = (ks->eeprom_size == 128) ? 6 : 8; | |
1185 | + | |
1186 | + switch (op) { | |
1187 | + case EEPROM_OP_EWEN: | |
1188 | + addr = 0x30; | |
1189 | + break; | |
1190 | + case EEPROM_OP_EWDS: | |
1191 | + addr = 0; | |
1192 | + break; | |
1193 | + } | |
1194 | + | |
1195 | + /* start transaction: chip select high, authorize write */ | |
1196 | + mutex_lock(&ks->lock); | |
1197 | + eepcr = EEPCR_EESA | EEPCR_EESRWA; | |
1198 | + ks8851_wrreg16(ks, KS_EEPCR, eepcr); | |
1199 | + eepcr |= EEPCR_EECS; | |
1200 | + ks8851_wrreg16(ks, KS_EEPCR, eepcr); | |
1201 | + mutex_unlock(&ks->lock); | |
1202 | + | |
1203 | + while (state != EEPROM_COMPLETE) { | |
1204 | + /* falling clock period starts... */ | |
1205 | + /* set EED_IO pin for control and address */ | |
1206 | + eepcr &= ~EEPCR_EEDO; | |
1207 | + switch (state) { | |
1208 | + case EEPROM_CONTROL: | |
1209 | + eepcr |= ((op >> bit_count) & 1) << 2; | |
1210 | + if (bit_count-- <= 0) { | |
1211 | + bit_count = addr_len - 1; | |
1212 | + state = EEPROM_ADDRESS; | |
1213 | + } | |
1214 | + break; | |
1215 | + case EEPROM_ADDRESS: | |
1216 | + eepcr |= ((addr >> bit_count) & 1) << 2; | |
1217 | + if (bit_count-- <= 0) { | |
1218 | + if (op == EEPROM_OP_WRITE) { | |
1219 | + bit_count = EEPROM_DATA_LEN - 1; | |
1220 | + state = EEPROM_DATA; | |
1221 | + } else { | |
1222 | + state = EEPROM_COMPLETE; | |
1223 | + } | |
1224 | + } | |
1225 | + break; | |
1226 | + case EEPROM_DATA: | |
1227 | + eepcr |= ((data >> bit_count) & 1) << 2; | |
1228 | + if (bit_count-- <= 0) | |
1229 | + state = EEPROM_COMPLETE; | |
1230 | + break; | |
1231 | + } | |
1232 | + | |
1233 | + /* lower clock */ | |
1234 | + eepcr &= ~EEPCR_EESCK; | |
1235 | + | |
1236 | + mutex_lock(&ks->lock); | |
1237 | + ks8851_wrreg16(ks, KS_EEPCR, eepcr); | |
1238 | + mutex_unlock(&ks->lock); | |
1239 | + | |
1240 | + /* wait period / 2 */ | |
1241 | + udelay(EEPROM_SK_PERIOD / 2); | |
1242 | + | |
1243 | + /* rising clock period starts... */ | |
1244 | + | |
1245 | + /* raise clock */ | |
1246 | + eepcr |= EEPCR_EESCK; | |
1247 | + mutex_lock(&ks->lock); | |
1248 | + ks8851_wrreg16(ks, KS_EEPCR, eepcr); | |
1249 | + mutex_unlock(&ks->lock); | |
1250 | + | |
1251 | + /* wait period / 2 */ | |
1252 | + udelay(EEPROM_SK_PERIOD / 2); | |
1253 | + } | |
1254 | + | |
1255 | + /* close transaction */ | |
1256 | + mutex_lock(&ks->lock); | |
1257 | + eepcr &= ~EEPCR_EECS; | |
1258 | + ks8851_wrreg16(ks, KS_EEPCR, eepcr); | |
1259 | + eepcr = 0; | |
1260 | + ks8851_wrreg16(ks, KS_EEPCR, eepcr); | |
1261 | + mutex_unlock(&ks->lock); | |
1262 | + | |
1263 | +} | |
1264 | + | |
1037 | 1265 | /* ethtool support */ |
1038 | 1266 | |
1039 | 1267 | static void ks8851_get_drvinfo(struct net_device *dev, |
drivers/net/ks8851.h
... | ... | @@ -25,11 +25,23 @@ |
25 | 25 | #define OBCR_ODS_16mA (1 << 6) |
26 | 26 | |
27 | 27 | #define KS_EEPCR 0x22 |
28 | +#define EEPCR_EESRWA (1 << 5) | |
28 | 29 | #define EEPCR_EESA (1 << 4) |
29 | -#define EEPCR_EESB (1 << 3) | |
30 | +#define EEPCR_EESB_OFFSET 3 | |
31 | +#define EEPCR_EESB (1 << EEPCR_EESB_OFFSET) | |
30 | 32 | #define EEPCR_EEDO (1 << 2) |
31 | 33 | #define EEPCR_EESCK (1 << 1) |
32 | 34 | #define EEPCR_EECS (1 << 0) |
35 | + | |
36 | +#define EEPROM_OP_LEN 3 /* bits:*/ | |
37 | +#define EEPROM_OP_READ 0x06 | |
38 | +#define EEPROM_OP_EWEN 0x04 | |
39 | +#define EEPROM_OP_WRITE 0x05 | |
40 | +#define EEPROM_OP_EWDS 0x14 | |
41 | + | |
42 | +#define EEPROM_DATA_LEN 16 /* 16 bits EEPROM */ | |
43 | +#define EEPROM_WRITE_TIME 4 /* wrt ack time in ms */ | |
44 | +#define EEPROM_SK_PERIOD 400 /* in us */ | |
33 | 45 | |
34 | 46 | #define KS_MBIR 0x24 |
35 | 47 | #define MBIR_TXMBF (1 << 12) |