ks8851 MAC and eeprom updates
Subsystems (3)
cover ks8851 MAC and eeprom updates
I pulled this patch series off the netdev list[1] when the eeprom reading didn't work for my ks8851 and I wanted the mac address to be read out at boot. It all seems to work well, so I'm posting it here again, slightly cleaned up and simplified, for inclusion.
Overall it reduces the lines of code and properly supports eeprom reading; two things the previous implementation doesn't do.
This is based off of linux-next-20111025.
Thanks to Ben Dooks for doing the heavy lifting.
[1] http://article.gmane.org/gmane.linux.network/159708
Ben Dooks (4):
eeprom_93cx6: Add data direction control.
eeprom_93cx6: Add write support
KSZ8851-SNL: Add support for EEPROM MAC address
KSZ8851-SNL: Add ethtool support for EEPROM via eeprom_93cx6
Tristram Ha (1):
KSZ8851-SNL: Fix MAC address change problem
drivers/misc/eeprom/eeprom_93cx6.c | 88 ++++++ drivers/net/ethernet/micrel/Kconfig | 2 + drivers/net/ethernet/micrel/ks8851.c | 513 ++++++++++++---------------------- drivers/net/ethernet/micrel/ks8851.h | 15 +- include/linux/eeprom_93cx6.h | 8 + 5 files changed, 278 insertions(+), 348 deletions(-)
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 1/5 eeprom_93cx6: Add data direction control.
From: Ben Dooks <[email protected]>
Some devices need to know if the data is to be output or read, so add a data direction into the eeprom structure to tell the driver whether the data line should be driven.
The user in this case is the Micrel KS8851 which has a direction control for the EEPROM data line and thus needs to know whether to drive it (writing) or to tristate it for receiving.
--- drivers/misc/eeprom/eeprom_93cx6.c | 3 +++ include/linux/eeprom_93cx6.h | 2 ++ 2 files changed, 5 insertions(+), 0 deletions(-)
drivers/misc/eeprom/eeprom_93cx6.c +3 -0
@@ -63,6 +63,7 @@ static void eeprom_93cx6_startup(struct eeprom_93cx6 *eeprom) eeprom->reg_data_out =0 ; eeprom->reg_data_clock =0 ; eeprom->reg_chip_select =1 ; + eeprom->drive_data =1 ; eeprom->register_write (eeprom);/*
@@ -101,6 +102,7 @@ static void eeprom_93cx6_write_bits(struct eeprom_93cx6 *eeprom,*/ eeprom->reg_data_in =0 ; eeprom->reg_data_out =0 ; + eeprom->drive_data =1 ;/* * Start writing all bits.
@@ -140,6 +142,7 @@ static void eeprom_93cx6_read_bits(struct eeprom_93cx6 *eeprom,*/ eeprom->reg_data_in =0 ; eeprom->reg_data_out =0 ; + eeprom->drive_data =0 ;/* * Start reading all bits.
include/linux/eeprom_93cx6.h +2 -0
@@ -46,6 +46,7 @@* @register_write(struct eeprom_93cx6 *eeprom): handler to * write to the eeprom register by using all reg_* fields. * @width: eeprom width, should be one of the PCI_EEPROM_WIDTH_* defines +* @drive_data: Set if we're driving the data line. * @reg_data_in: register field to indicate data input * @reg_data_out: register field to indicate data output * @reg_data_clock: register field to set the data clock
@@ -62,6 +63,7 @@ struct eeprom_93cx6 {int width; +char drive_data;char reg_data_in;char reg_data_out;char reg_data_clock;
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 2/5 eeprom_93cx6: Add write support
In reply to Stephen BoydFrom: Ben Dooks <[email protected]>
Add support for writing data to EEPROM.
--- drivers/misc/eeprom/eeprom_93cx6.c | 85 ++++++++++++++++++++++++++++++++++++ include/linux/eeprom_93cx6.h | 6 +++ 2 files changed, 91 insertions(+), 0 deletions(-)
drivers/misc/eeprom/eeprom_93cx6.c +85 -0
@@ -234,3 +234,88 @@ void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom, const u8 word, }EXPORT_SYMBOL_GPL (eeprom_93cx6_multiread); +/** +* eeprom_93cx6_wren - set the write enable state +* @eeprom: Pointer to eeprom structure +* @enable: true to enable writes, otherwise disable writes +* +* Set the EEPROM write enable state to either allow or deny +* writes depending on the @enable value. +*/ +void eeprom_93cx6_wren (struct eeprom_93cx6 *eeprom,bool enable) +{ +u16 command; + +/* start the command */ +eeprom_93cx6_startup (eeprom); + +/* create command to enable/disable */ + + command = enable ?PCI_EEPROM_EWEN_OPCODE :PCI_EEPROM_EWDS_OPCODE ; + command <<= (eeprom->width -2 ); + +eeprom_93cx6_write_bits (eeprom, command, +PCI_EEPROM_WIDTH_OPCODE + eeprom->width); + +eeprom_93cx6_cleanup (eeprom); +} +EXPORT_SYMBOL_GPL (eeprom_93cx6_wren); + +/** +* eeprom_93cx6_write - write data to the EEPROM +* @eeprom: Pointer to eeprom structure +* @addr: Address to write data to. +* @data: The data to write to address @addr. +* +* Write the @data to the specified @addr in the EEPROM and +* waiting for the device to finish writing. +* +* Note, since we do not expect large number of write operations +* we delay in between parts of the operation to avoid using excessive +* amounts of CPU time busy waiting. +*/ +void eeprom_93cx6_write (struct eeprom_93cx6 *eeprom,u8 addr,u16 data) +{ +int timeout =100 ; +u16 command; + +/* start the command */ +eeprom_93cx6_startup (eeprom); + + command =PCI_EEPROM_WRITE_OPCODE << eeprom->width; + command |= addr; + +/* send write command */ +eeprom_93cx6_write_bits (eeprom, command, +PCI_EEPROM_WIDTH_OPCODE + eeprom->width); + +/* send data */ +eeprom_93cx6_write_bits (eeprom, data,16 ); + +/* get ready to check for busy */ + eeprom->drive_data =0 ; + eeprom->reg_chip_select =1 ; + eeprom->register_write (eeprom); + +/* wait at-least 250ns to get DO to be the busy signal */ +usleep_range (1000 ,2000 ); + +/* wait for DO to go high to signify finish */ + +while (true) { + eeprom->register_read (eeprom); + +if (eeprom->reg_data_out) +break ; + +usleep_range (1000 ,2000 ); + +if (--timeout <=0 ) { +printk (KERN_ERR "%s: timeout\n" , __func__); +break ; + } + } + +eeprom_93cx6_cleanup (eeprom); +} +EXPORT_SYMBOL_GPL (eeprom_93cx6_write);
include/linux/eeprom_93cx6.h +6 -0
@@ -33,6 +33,7 @@#define PCI_EEPROM_WIDTH_93C86 8#define PCI_EEPROM_WIDTH_OPCODE 3#define PCI_EEPROM_WRITE_OPCODE 0x05 +#define PCI_EEPROM_ERASE_OPCODE 0x07#define PCI_EEPROM_READ_OPCODE 0x06#define PCI_EEPROM_EWDS_OPCODE 0x10#define PCI_EEPROM_EWEN_OPCODE 0x13
@@ -74,3 +75,8 @@ extern void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom, const u8 word, u16 *data);extern void eeprom_93cx6_multiread (struct eeprom_93cx6 *eeprom,const u8 word,__le16 *data,const u16 words); + +extern void eeprom_93cx6_wren (struct eeprom_93cx6 *eeprom,bool enable); + +extern void eeprom_93cx6_write (struct eeprom_93cx6 *eeprom, +u8 addr,u16 data);
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 3/5 KSZ8851-SNL: Add support for EEPROM MAC address
In reply to Stephen BoydFrom: Ben Dooks <[email protected]>
Add support for reading the MAC address from the system registers if there is an EEPROM present. This involves caching the KS_CCR register for later use (will also be useful for ETHTOOL support) and adding a print to say that there is an EEPROM present.
--- drivers/net/ethernet/micrel/ks8851.c | 41 ++++++++++++++++++++++++++++----- 1 files changed, 34 insertions(+), 7 deletions(-)
drivers/net/ethernet/micrel/ks8851.c +34 -7
@@ -367,21 +367,47 @@ static int ks8851_write_mac_addr(struct net_device *dev) }/** +* ks8851_read_mac_addr - read mac address from device registers +* @dev: The network device +* +* Update our copy of the KS8851 MAC address from the registers of @dev. +*/ +static void ks8851_read_mac_addr (struct net_device *dev) +{ +struct ks8851_net *ks =netdev_priv (dev); +int i; + +mutex_lock (&ks->lock); + +for (i =0 ; i <ETH_ALEN ; i++) + dev->dev_addr[i] =ks8851_rdreg8 (ks,KS_MAR (i)); + +mutex_unlock (&ks->lock); +} + +/** * ks8851_init_mac - initialise the mac address * @ks: The device structure * * Get or create the initial mac address for the device and then set that -* into the station address register. Currently we assume that the device -* does not have a valid mac address in it, and so we use random_ether_addr() +* into the station address register. If there is an EEPROM present, then +* we try that. If no valid mac address is found we use random_ether_addr() * to create a new one. -* -* In future, the driver should check to see if the device has an EEPROM -* attached and whether that has a valid ethernet address in it. */ static void ks8851_init_mac (struct ks8851_net *ks) {struct net_device *dev = ks->netdev; +/* first, try reading what we've got already */ +if (ks->rc_ccr &CCR_EEPROM ) { +ks8851_read_mac_addr (dev); +if (is_valid_ether_addr (dev->dev_addr)) +return ; + +netdev_err (ks->netdev,"invalid mac address read %pM\n" , + dev->dev_addr); + } +random_ether_addr (dev->dev_addr);ks8851_write_mac_addr (dev); }
@@ -1674,9 +1700,10 @@ static int __devinit ks8851_probe(struct spi_device *spi) goto err_netdev; } -netdev_info (ndev,"revision %d, MAC %pM, IRQ %d\n" , +netdev_info (ndev,"revision %d, MAC %pM, IRQ %d, %s EEPROM\n" ,CIDER_REV_GET (ks8851_rdreg16 (ks,KS_CIDER )), - ndev->dev_addr, ndev->irq); + ndev->dev_addr, ndev->irq, + ks->rc_ccr &CCR_EEPROM ?"has" :"no" );return 0 ;
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 4/5 KSZ8851-SNL: Fix MAC address change problem
In reply to Stephen BoydFrom: Tristram Ha <[email protected]>
When device is off it is under power saving mode. Changing the MAC address in that situation will result in the device not communicating as the first write to the MAC address register is not executed.
--- drivers/net/ethernet/micrel/ks8851.c | 47 +++++++++++++++++++-------------- drivers/net/ethernet/micrel/ks8851.h | 2 +- 2 files changed, 28 insertions(+), 21 deletions(-)
drivers/net/ethernet/micrel/ks8851.c +27 -20
@@ -343,6 +343,26 @@ static void ks8851_soft_reset(struct ks8851_net *ks, unsigned op) }/** +* ks8851_set_powermode - set power mode of the device +* @ks: The device state +* @pwrmode: The power mode value to write to KS_PMECR. +* +* Change the power mode of the chip. +*/ +static void ks8851_set_powermode (struct ks8851_net *ks,unsigned pwrmode) +{ +unsigned pmecr; + +netif_dbg (ks, hw, ks->netdev,"setting power mode %d\n" , pwrmode); + + pmecr =ks8851_rdreg16 (ks,KS_PMECR ); + pmecr &= ~PMECR_PM_MASK ; + pmecr |= pwrmode; + +ks8851_wrreg16 (ks,KS_PMECR , pmecr); +} + +/** * ks8851_write_mac_addr - write mac address to device registers * @dev: The network device *
@@ -358,8 +378,15 @@ static int ks8851_write_mac_addr(struct net_device *dev)mutex_lock (&ks->lock); +/* +* Wake up chip in case it was powered off when stopped; otherwise, +* the first write to the MAC address does not take effect. +*/ +ks8851_set_powermode (ks,PMECR_PM_NORMAL );for (i =0 ; i <ETH_ALEN ; i++)ks8851_wrreg8 (ks,KS_MAR (i), dev->dev_addr[i]); +if (!netif_running (dev)) +ks8851_set_powermode (ks,PMECR_PM_SOFTDOWN );mutex_unlock (&ks->lock);
@@ -765,26 +792,6 @@ static void ks8851_tx_work(struct work_struct *work) }/** -* ks8851_set_powermode - set power mode of the device -* @ks: The device state -* @pwrmode: The power mode value to write to KS_PMECR. -* -* Change the power mode of the chip. -*/ -static void ks8851_set_powermode (struct ks8851_net *ks,unsigned pwrmode) -{ -unsigned pmecr; - -netif_dbg (ks, hw, ks->netdev,"setting power mode %d\n" , pwrmode); - - pmecr =ks8851_rdreg16 (ks,KS_PMECR ); - pmecr &= ~PMECR_PM_MASK ; - pmecr |= pwrmode; - -ks8851_wrreg16 (ks,KS_PMECR , pmecr); -} - -/** * ks8851_net_open - open network device * @dev: The network device being opened. *
drivers/net/ethernet/micrel/ks8851.h +1 -1
@@ -16,7 +16,7 @@#define CCR_32PIN (1 << 0)/* MAC address registers */ -#define KS_MAR (_m) 0x15 - (_m) +#define KS_MAR (_m) (0x15 - (_m))#define KS_MARL 0x10#define KS_MARM 0x12#define KS_MARH 0x14
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 5/5 KSZ8851-SNL: Add ethtool support for EEPROM via eeprom_93cx6
In reply to Stephen BoydFrom: Ben Dooks <[email protected]>
Add ethtool EEPROM read/write support using the eeprom_93cx6 library instead of open-coding the functions.
Depends on eeprom_93cx6 driver getting EEPROM write support.
--- drivers/net/ethernet/micrel/Kconfig | 2 + drivers/net/ethernet/micrel/ks8851.c | 425 ++++++++++------------------------ drivers/net/ethernet/micrel/ks8851.h | 13 +- 3 files changed, 120 insertions(+), 320 deletions(-)
drivers/net/ethernet/micrel/Kconfig +2 -0
@@ -42,6 +42,8 @@ config KS8851 select NET_CORE select MII select CRC32 + select MISC_DEVICES + select EEPROM_93CX6 ---help--- SPI driver for Micrel KS8851 SPI attached network chip.
drivers/net/ethernet/micrel/ks8851.c +117 -308
490 lines not on this page · raw message
drivers/net/ethernet/micrel/ks8851.h +1 -12
@@ -27,22 +27,11 @@#define KS_EEPCR 0x22#define EEPCR_EESRWA (1 << 5)#define EEPCR_EESA (1 << 4) -#define EEPCR_EESB_OFFSET 3 -#define EEPCR_EESB (1 << EEPCR_EESB_OFFSET) +#define EEPCR_EESB (1 << 3)#define EEPCR_EEDO (1 << 2)#define EEPCR_EESCK (1 << 1)#define EEPCR_EECS (1 << 0) -#define EEPROM_OP_LEN 3/* bits:*/ -#define EEPROM_OP_READ 0x06 -#define EEPROM_OP_EWEN 0x04 -#define EEPROM_OP_WRITE 0x05 -#define EEPROM_OP_EWDS 0x14 - -#define EEPROM_DATA_LEN 16/* 16 bits EEPROM */ -#define EEPROM_WRITE_TIME 4/* wrt ack time in ms */ -#define EEPROM_SK_PERIOD 400/* in us */ -#define KS_MBIR 0x24#define MBIR_TXMBF (1 << 12)#define MBIR_TXMBFA (1 << 11)
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
David Miller
maintainerFrom: Stephen Boyd <[email protected]>
Date: Mon, 21 Nov 2011 10:57:55 -0800
Quoted 5 lines
I pulled this patch series off the netdev list[1] when the eeprom reading didn't work for my ks8851 and I wanted the mac address to be read out at boot. It all seems to work well, so I'm posting it here again, slightly cleaned up and simplified, for inclusion.
Quoted 8 lines
Overall it reduces the lines of code and properly supports eeprom reading; two things the previous implementation doesn't do.
This is based off of linux-next-20111025.
Thanks to Ben Dooks for doing the heavy lifting.
I guess I'll apply this series to net-next, I hope the eeprom layer maintainers don't mind.
Thanks.