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>
This commit is contained in:
parent
7d9974666e
commit
a4bdfff744
|
@ -1034,6 +1034,234 @@ static const struct net_device_ops ks8851_netdev_ops = {
|
|||
.ndo_validate_addr = eth_validate_addr,
|
||||
};
|
||||
|
||||
/* Companion eeprom access */
|
||||
|
||||
enum { /* EEPROM programming states */
|
||||
EEPROM_CONTROL,
|
||||
EEPROM_ADDRESS,
|
||||
EEPROM_DATA,
|
||||
EEPROM_COMPLETE
|
||||
};
|
||||
|
||||
/**
|
||||
* ks8851_eeprom_read - read a 16bits word in ks8851 companion EEPROM
|
||||
* @dev: The network device the PHY is on.
|
||||
* @addr: EEPROM address to read
|
||||
*
|
||||
* eeprom_size: used to define the data coding length. Can be changed
|
||||
* through debug-fs.
|
||||
*
|
||||
* Programs a read on the EEPROM using ks8851 EEPROM SW access feature.
|
||||
* Warning: The READ feature is not supported on ks8851 revision 0.
|
||||
*
|
||||
* Rough programming model:
|
||||
* - on period start: set clock high and read value on bus
|
||||
* - on period / 2: set clock low and program value on bus
|
||||
* - start on period / 2
|
||||
*/
|
||||
unsigned int ks8851_eeprom_read(struct net_device *dev, unsigned int addr)
|
||||
{
|
||||
struct ks8851_net *ks = netdev_priv(dev);
|
||||
int eepcr;
|
||||
int ctrl = EEPROM_OP_READ;
|
||||
int state = EEPROM_CONTROL;
|
||||
int bit_count = EEPROM_OP_LEN - 1;
|
||||
unsigned int data = 0;
|
||||
int dummy;
|
||||
unsigned int addr_len;
|
||||
|
||||
addr_len = (ks->eeprom_size == 128) ? 6 : 8;
|
||||
|
||||
/* start transaction: chip select high, authorize write */
|
||||
mutex_lock(&ks->lock);
|
||||
eepcr = EEPCR_EESA | EEPCR_EESRWA;
|
||||
ks8851_wrreg16(ks, KS_EEPCR, eepcr);
|
||||
eepcr |= EEPCR_EECS;
|
||||
ks8851_wrreg16(ks, KS_EEPCR, eepcr);
|
||||
mutex_unlock(&ks->lock);
|
||||
|
||||
while (state != EEPROM_COMPLETE) {
|
||||
/* falling clock period starts... */
|
||||
/* set EED_IO pin for control and address */
|
||||
eepcr &= ~EEPCR_EEDO;
|
||||
switch (state) {
|
||||
case EEPROM_CONTROL:
|
||||
eepcr |= ((ctrl >> bit_count) & 1) << 2;
|
||||
if (bit_count-- <= 0) {
|
||||
bit_count = addr_len - 1;
|
||||
state = EEPROM_ADDRESS;
|
||||
}
|
||||
break;
|
||||
case EEPROM_ADDRESS:
|
||||
eepcr |= ((addr >> bit_count) & 1) << 2;
|
||||
bit_count--;
|
||||
break;
|
||||
case EEPROM_DATA:
|
||||
/* Change to receive mode */
|
||||
eepcr &= ~EEPCR_EESRWA;
|
||||
break;
|
||||
}
|
||||
|
||||
/* lower clock */
|
||||
eepcr &= ~EEPCR_EESCK;
|
||||
|
||||
mutex_lock(&ks->lock);
|
||||
ks8851_wrreg16(ks, KS_EEPCR, eepcr);
|
||||
mutex_unlock(&ks->lock);
|
||||
|
||||
/* waitread period / 2 */
|
||||
udelay(EEPROM_SK_PERIOD / 2);
|
||||
|
||||
/* rising clock period starts... */
|
||||
|
||||
/* raise clock */
|
||||
mutex_lock(&ks->lock);
|
||||
eepcr |= EEPCR_EESCK;
|
||||
ks8851_wrreg16(ks, KS_EEPCR, eepcr);
|
||||
mutex_unlock(&ks->lock);
|
||||
|
||||
/* Manage read */
|
||||
switch (state) {
|
||||
case EEPROM_ADDRESS:
|
||||
if (bit_count < 0) {
|
||||
bit_count = EEPROM_DATA_LEN - 1;
|
||||
state = EEPROM_DATA;
|
||||
}
|
||||
break;
|
||||
case EEPROM_DATA:
|
||||
mutex_lock(&ks->lock);
|
||||
dummy = ks8851_rdreg16(ks, KS_EEPCR);
|
||||
mutex_unlock(&ks->lock);
|
||||
data |= ((dummy >> EEPCR_EESB_OFFSET) & 1) << bit_count;
|
||||
if (bit_count-- <= 0)
|
||||
state = EEPROM_COMPLETE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* wait period / 2 */
|
||||
udelay(EEPROM_SK_PERIOD / 2);
|
||||
}
|
||||
|
||||
/* close transaction */
|
||||
mutex_lock(&ks->lock);
|
||||
eepcr &= ~EEPCR_EECS;
|
||||
ks8851_wrreg16(ks, KS_EEPCR, eepcr);
|
||||
eepcr = 0;
|
||||
ks8851_wrreg16(ks, KS_EEPCR, eepcr);
|
||||
mutex_unlock(&ks->lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* ks8851_eeprom_write - write a 16bits word in ks8851 companion EEPROM
|
||||
* @dev: The network device the PHY is on.
|
||||
* @op: operand (can be WRITE, EWEN, EWDS)
|
||||
* @addr: EEPROM address to write
|
||||
* @data: data to write
|
||||
*
|
||||
* eeprom_size: used to define the data coding length. Can be changed
|
||||
* through debug-fs.
|
||||
*
|
||||
* Programs a write on the EEPROM using ks8851 EEPROM SW access feature.
|
||||
*
|
||||
* Note that a write enable is required before writing data.
|
||||
*
|
||||
* Rough programming model:
|
||||
* - on period start: set clock high
|
||||
* - on period / 2: set clock low and program value on bus
|
||||
* - start on period / 2
|
||||
*/
|
||||
void ks8851_eeprom_write(struct net_device *dev, unsigned int op,
|
||||
unsigned int addr, unsigned int data)
|
||||
{
|
||||
struct ks8851_net *ks = netdev_priv(dev);
|
||||
int eepcr;
|
||||
int state = EEPROM_CONTROL;
|
||||
int bit_count = EEPROM_OP_LEN - 1;
|
||||
unsigned int addr_len;
|
||||
|
||||
addr_len = (ks->eeprom_size == 128) ? 6 : 8;
|
||||
|
||||
switch (op) {
|
||||
case EEPROM_OP_EWEN:
|
||||
addr = 0x30;
|
||||
break;
|
||||
case EEPROM_OP_EWDS:
|
||||
addr = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* start transaction: chip select high, authorize write */
|
||||
mutex_lock(&ks->lock);
|
||||
eepcr = EEPCR_EESA | EEPCR_EESRWA;
|
||||
ks8851_wrreg16(ks, KS_EEPCR, eepcr);
|
||||
eepcr |= EEPCR_EECS;
|
||||
ks8851_wrreg16(ks, KS_EEPCR, eepcr);
|
||||
mutex_unlock(&ks->lock);
|
||||
|
||||
while (state != EEPROM_COMPLETE) {
|
||||
/* falling clock period starts... */
|
||||
/* set EED_IO pin for control and address */
|
||||
eepcr &= ~EEPCR_EEDO;
|
||||
switch (state) {
|
||||
case EEPROM_CONTROL:
|
||||
eepcr |= ((op >> bit_count) & 1) << 2;
|
||||
if (bit_count-- <= 0) {
|
||||
bit_count = addr_len - 1;
|
||||
state = EEPROM_ADDRESS;
|
||||
}
|
||||
break;
|
||||
case EEPROM_ADDRESS:
|
||||
eepcr |= ((addr >> bit_count) & 1) << 2;
|
||||
if (bit_count-- <= 0) {
|
||||
if (op == EEPROM_OP_WRITE) {
|
||||
bit_count = EEPROM_DATA_LEN - 1;
|
||||
state = EEPROM_DATA;
|
||||
} else {
|
||||
state = EEPROM_COMPLETE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EEPROM_DATA:
|
||||
eepcr |= ((data >> bit_count) & 1) << 2;
|
||||
if (bit_count-- <= 0)
|
||||
state = EEPROM_COMPLETE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* lower clock */
|
||||
eepcr &= ~EEPCR_EESCK;
|
||||
|
||||
mutex_lock(&ks->lock);
|
||||
ks8851_wrreg16(ks, KS_EEPCR, eepcr);
|
||||
mutex_unlock(&ks->lock);
|
||||
|
||||
/* wait period / 2 */
|
||||
udelay(EEPROM_SK_PERIOD / 2);
|
||||
|
||||
/* rising clock period starts... */
|
||||
|
||||
/* raise clock */
|
||||
eepcr |= EEPCR_EESCK;
|
||||
mutex_lock(&ks->lock);
|
||||
ks8851_wrreg16(ks, KS_EEPCR, eepcr);
|
||||
mutex_unlock(&ks->lock);
|
||||
|
||||
/* wait period / 2 */
|
||||
udelay(EEPROM_SK_PERIOD / 2);
|
||||
}
|
||||
|
||||
/* close transaction */
|
||||
mutex_lock(&ks->lock);
|
||||
eepcr &= ~EEPCR_EECS;
|
||||
ks8851_wrreg16(ks, KS_EEPCR, eepcr);
|
||||
eepcr = 0;
|
||||
ks8851_wrreg16(ks, KS_EEPCR, eepcr);
|
||||
mutex_unlock(&ks->lock);
|
||||
|
||||
}
|
||||
|
||||
/* ethtool support */
|
||||
|
||||
static void ks8851_get_drvinfo(struct net_device *dev,
|
||||
|
|
|
@ -25,12 +25,24 @@
|
|||
#define OBCR_ODS_16mA (1 << 6)
|
||||
|
||||
#define KS_EEPCR 0x22
|
||||
#define EEPCR_EESRWA (1 << 5)
|
||||
#define EEPCR_EESA (1 << 4)
|
||||
#define EEPCR_EESB (1 << 3)
|
||||
#define EEPCR_EESB_OFFSET 3
|
||||
#define EEPCR_EESB (1 << EEPCR_EESB_OFFSET)
|
||||
#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)
|
||||
|
|
Loading…
Reference in New Issue