aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSteve Glendinning <steve.glendinning@smsc.com>2008-12-13 01:32:22 -0500
committerDavid S. Miller <davem@davemloft.net>2008-12-13 01:32:22 -0500
commit012b215ceb55aa38826f091cecfd373cc9bbb05b (patch)
treea8cdfe53fc69cc72ae40222faed9f473f8db4a97 /drivers
parente312674ffb5281a46a3ad06604edea6426c4eb24 (diff)
smsc9420: add ethtool eeprom support
Signed-off-by: Steve Glendinning <steve.glendinning@smsc.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/smsc9420.c121
-rw-r--r--drivers/net/smsc9420.h3
2 files changed, 124 insertions, 0 deletions
diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c
index 80dab8bea76c..2a8e9b71de92 100644
--- a/drivers/net/smsc9420.c
+++ b/drivers/net/smsc9420.c
@@ -293,6 +293,124 @@ static int smsc9420_ethtool_nway_reset(struct net_device *netdev)
293 return phy_start_aneg(pd->phy_dev); 293 return phy_start_aneg(pd->phy_dev);
294} 294}
295 295
296static void smsc9420_eeprom_enable_access(struct smsc9420_pdata *pd)
297{
298 unsigned int temp = smsc9420_reg_read(pd, GPIO_CFG);
299 temp &= ~GPIO_CFG_EEPR_EN_;
300 smsc9420_reg_write(pd, GPIO_CFG, temp);
301 msleep(1);
302}
303
304static int smsc9420_eeprom_send_cmd(struct smsc9420_pdata *pd, u32 op)
305{
306 int timeout = 100;
307 u32 e2cmd;
308
309 smsc_dbg(HW, "op 0x%08x", op);
310 if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) {
311 smsc_warn(HW, "Busy at start");
312 return -EBUSY;
313 }
314
315 e2cmd = op | E2P_CMD_EPC_BUSY_;
316 smsc9420_reg_write(pd, E2P_CMD, e2cmd);
317
318 do {
319 msleep(1);
320 e2cmd = smsc9420_reg_read(pd, E2P_CMD);
321 } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (timeout--));
322
323 if (!timeout) {
324 smsc_info(HW, "TIMED OUT");
325 return -EAGAIN;
326 }
327
328 if (e2cmd & E2P_CMD_EPC_TIMEOUT_) {
329 smsc_info(HW, "Error occured during eeprom operation");
330 return -EINVAL;
331 }
332
333 return 0;
334}
335
336static int smsc9420_eeprom_read_location(struct smsc9420_pdata *pd,
337 u8 address, u8 *data)
338{
339 u32 op = E2P_CMD_EPC_CMD_READ_ | address;
340 int ret;
341
342 smsc_dbg(HW, "address 0x%x", address);
343 ret = smsc9420_eeprom_send_cmd(pd, op);
344
345 if (!ret)
346 data[address] = smsc9420_reg_read(pd, E2P_DATA);
347
348 return ret;
349}
350
351static int smsc9420_eeprom_write_location(struct smsc9420_pdata *pd,
352 u8 address, u8 data)
353{
354 u32 op = E2P_CMD_EPC_CMD_ERASE_ | address;
355 int ret;
356
357 smsc_dbg(HW, "address 0x%x, data 0x%x", address, data);
358 ret = smsc9420_eeprom_send_cmd(pd, op);
359
360 if (!ret) {
361 op = E2P_CMD_EPC_CMD_WRITE_ | address;
362 smsc9420_reg_write(pd, E2P_DATA, (u32)data);
363 ret = smsc9420_eeprom_send_cmd(pd, op);
364 }
365
366 return ret;
367}
368
369static int smsc9420_ethtool_get_eeprom_len(struct net_device *dev)
370{
371 return SMSC9420_EEPROM_SIZE;
372}
373
374static int smsc9420_ethtool_get_eeprom(struct net_device *dev,
375 struct ethtool_eeprom *eeprom, u8 *data)
376{
377 struct smsc9420_pdata *pd = netdev_priv(dev);
378 u8 eeprom_data[SMSC9420_EEPROM_SIZE];
379 int len, i;
380
381 smsc9420_eeprom_enable_access(pd);
382
383 len = min(eeprom->len, SMSC9420_EEPROM_SIZE);
384 for (i = 0; i < len; i++) {
385 int ret = smsc9420_eeprom_read_location(pd, i, eeprom_data);
386 if (ret < 0) {
387 eeprom->len = 0;
388 return ret;
389 }
390 }
391
392 memcpy(data, &eeprom_data[eeprom->offset], len);
393 eeprom->len = len;
394 return 0;
395}
396
397static int smsc9420_ethtool_set_eeprom(struct net_device *dev,
398 struct ethtool_eeprom *eeprom, u8 *data)
399{
400 struct smsc9420_pdata *pd = netdev_priv(dev);
401 int ret;
402
403 smsc9420_eeprom_enable_access(pd);
404 smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWEN_);
405 ret = smsc9420_eeprom_write_location(pd, eeprom->offset, *data);
406 smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWDS_);
407
408 /* Single byte write, according to man page */
409 eeprom->len = 1;
410
411 return ret;
412}
413
296static const struct ethtool_ops smsc9420_ethtool_ops = { 414static const struct ethtool_ops smsc9420_ethtool_ops = {
297 .get_settings = smsc9420_ethtool_get_settings, 415 .get_settings = smsc9420_ethtool_get_settings,
298 .set_settings = smsc9420_ethtool_set_settings, 416 .set_settings = smsc9420_ethtool_set_settings,
@@ -301,6 +419,9 @@ static const struct ethtool_ops smsc9420_ethtool_ops = {
301 .set_msglevel = smsc9420_ethtool_set_msglevel, 419 .set_msglevel = smsc9420_ethtool_set_msglevel,
302 .nway_reset = smsc9420_ethtool_nway_reset, 420 .nway_reset = smsc9420_ethtool_nway_reset,
303 .get_link = ethtool_op_get_link, 421 .get_link = ethtool_op_get_link,
422 .get_eeprom_len = smsc9420_ethtool_get_eeprom_len,
423 .get_eeprom = smsc9420_ethtool_get_eeprom,
424 .set_eeprom = smsc9420_ethtool_set_eeprom,
304}; 425};
305 426
306/* Sets the device MAC address to dev_addr */ 427/* Sets the device MAC address to dev_addr */
diff --git a/drivers/net/smsc9420.h b/drivers/net/smsc9420.h
index afda2d249eb6..80c426dc4325 100644
--- a/drivers/net/smsc9420.h
+++ b/drivers/net/smsc9420.h
@@ -43,6 +43,8 @@
43 43
44#define LAN_REGISTER_EXTENT (0x400) 44#define LAN_REGISTER_EXTENT (0x400)
45 45
46#define SMSC9420_EEPROM_SIZE ((u32)11)
47
46#define FLOW_CTRL_TX (1) 48#define FLOW_CTRL_TX (1)
47#define FLOW_CTRL_RX (2) 49#define FLOW_CTRL_RX (2)
48 50
@@ -238,6 +240,7 @@
238#define GPIO_CFG_LED_3_ (0x40000000) 240#define GPIO_CFG_LED_3_ (0x40000000)
239#define GPIO_CFG_LED_2_ (0x20000000) 241#define GPIO_CFG_LED_2_ (0x20000000)
240#define GPIO_CFG_LED_1_ (0x10000000) 242#define GPIO_CFG_LED_1_ (0x10000000)
243#define GPIO_CFG_EEPR_EN_ (0x00700000)
241 244
242#define GPT_CFG (0xD4) 245#define GPT_CFG (0xD4)
243#define GPT_CFG_TIMER_EN_ (0x20000000) 246#define GPT_CFG_TIMER_EN_ (0x20000000)