diff options
author | Sebastien Jan <s-jan@ti.com> | 2010-05-05 04:45:53 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-05-06 00:27:44 -0400 |
commit | a4bdfff74464f86d7e3b8feaf42d18960adc5514 (patch) | |
tree | 4dcde38694ca796b1a3d04a0044948397b497f6c /drivers/net | |
parent | 7d9974666e0dc2cbbeac80fa4d550df0bbea6fad (diff) |
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>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ks8851.c | 228 | ||||
-rw-r--r-- | drivers/net/ks8851.h | 14 |
2 files changed, 241 insertions, 1 deletions
diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c index 623171f37d99..3dba57b72ef8 100644 --- a/drivers/net/ks8851.c +++ b/drivers/net/ks8851.c | |||
@@ -1034,6 +1034,234 @@ static const struct net_device_ops ks8851_netdev_ops = { | |||
1034 | .ndo_validate_addr = eth_validate_addr, | 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 | /* ethtool support */ | 1265 | /* ethtool support */ |
1038 | 1266 | ||
1039 | static void ks8851_get_drvinfo(struct net_device *dev, | 1267 | static void ks8851_get_drvinfo(struct net_device *dev, |
diff --git a/drivers/net/ks8851.h b/drivers/net/ks8851.h index f52c312cc356..537fb06e5932 100644 --- a/drivers/net/ks8851.h +++ b/drivers/net/ks8851.h | |||
@@ -25,12 +25,24 @@ | |||
25 | #define OBCR_ODS_16mA (1 << 6) | 25 | #define OBCR_ODS_16mA (1 << 6) |
26 | 26 | ||
27 | #define KS_EEPCR 0x22 | 27 | #define KS_EEPCR 0x22 |
28 | #define EEPCR_EESRWA (1 << 5) | ||
28 | #define EEPCR_EESA (1 << 4) | 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 | #define EEPCR_EEDO (1 << 2) | 32 | #define EEPCR_EEDO (1 << 2) |
31 | #define EEPCR_EESCK (1 << 1) | 33 | #define EEPCR_EESCK (1 << 1) |
32 | #define EEPCR_EECS (1 << 0) | 34 | #define EEPCR_EECS (1 << 0) |
33 | 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 */ | ||
45 | |||
34 | #define KS_MBIR 0x24 | 46 | #define KS_MBIR 0x24 |
35 | #define MBIR_TXMBF (1 << 12) | 47 | #define MBIR_TXMBF (1 << 12) |
36 | #define MBIR_TXMBFA (1 << 11) | 48 | #define MBIR_TXMBFA (1 << 11) |