diff options
author | Steve Glendinning <steve.glendinning@smsc.com> | 2008-12-13 01:32:22 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-12-13 01:32:22 -0500 |
commit | 012b215ceb55aa38826f091cecfd373cc9bbb05b (patch) | |
tree | a8cdfe53fc69cc72ae40222faed9f473f8db4a97 /drivers/net/smsc9420.c | |
parent | e312674ffb5281a46a3ad06604edea6426c4eb24 (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/net/smsc9420.c')
-rw-r--r-- | drivers/net/smsc9420.c | 121 |
1 files changed, 121 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 | ||
296 | static 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 | |||
304 | static 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 | |||
336 | static 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 | |||
351 | static 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 | |||
369 | static int smsc9420_ethtool_get_eeprom_len(struct net_device *dev) | ||
370 | { | ||
371 | return SMSC9420_EEPROM_SIZE; | ||
372 | } | ||
373 | |||
374 | static 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 | |||
397 | static 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 | |||
296 | static const struct ethtool_ops smsc9420_ethtool_ops = { | 414 | static 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 */ |