New driver "sfc" for Solarstorm SFC4000 controller.
The driver supports the 10Xpress PHY and XFP modules on our reference designs SFE4001 and SFE4002 and the SMC models SMC10GPCIe-XFP and SMC10GPCIe-10BT. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
This commit is contained in:
parent
358c12953b
commit
8ceee660aa
36 changed files with 12887 additions and 0 deletions
381
drivers/net/sfc/i2c-direct.c
Normal file
381
drivers/net/sfc/i2c-direct.c
Normal file
|
@ -0,0 +1,381 @@
|
|||
/****************************************************************************
|
||||
* Driver for Solarflare Solarstorm network controllers and boards
|
||||
* Copyright 2005 Fen Systems Ltd.
|
||||
* Copyright 2006-2008 Solarflare Communications Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation, incorporated herein by reference.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include "net_driver.h"
|
||||
#include "i2c-direct.h"
|
||||
|
||||
/*
|
||||
* I2C data (SDA) and clock (SCL) line read/writes with appropriate
|
||||
* delays.
|
||||
*/
|
||||
|
||||
static inline void setsda(struct efx_i2c_interface *i2c, int state)
|
||||
{
|
||||
udelay(i2c->op->udelay);
|
||||
i2c->sda = state;
|
||||
i2c->op->setsda(i2c);
|
||||
udelay(i2c->op->udelay);
|
||||
}
|
||||
|
||||
static inline void setscl(struct efx_i2c_interface *i2c, int state)
|
||||
{
|
||||
udelay(i2c->op->udelay);
|
||||
i2c->scl = state;
|
||||
i2c->op->setscl(i2c);
|
||||
udelay(i2c->op->udelay);
|
||||
}
|
||||
|
||||
static inline int getsda(struct efx_i2c_interface *i2c)
|
||||
{
|
||||
int sda;
|
||||
|
||||
udelay(i2c->op->udelay);
|
||||
sda = i2c->op->getsda(i2c);
|
||||
udelay(i2c->op->udelay);
|
||||
return sda;
|
||||
}
|
||||
|
||||
static inline int getscl(struct efx_i2c_interface *i2c)
|
||||
{
|
||||
int scl;
|
||||
|
||||
udelay(i2c->op->udelay);
|
||||
scl = i2c->op->getscl(i2c);
|
||||
udelay(i2c->op->udelay);
|
||||
return scl;
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C low-level protocol operations
|
||||
*
|
||||
*/
|
||||
|
||||
static inline void i2c_release(struct efx_i2c_interface *i2c)
|
||||
{
|
||||
EFX_WARN_ON_PARANOID(!i2c->scl);
|
||||
EFX_WARN_ON_PARANOID(!i2c->sda);
|
||||
/* Devices may time out if operations do not end */
|
||||
setscl(i2c, 1);
|
||||
setsda(i2c, 1);
|
||||
EFX_BUG_ON_PARANOID(getsda(i2c) != 1);
|
||||
EFX_BUG_ON_PARANOID(getscl(i2c) != 1);
|
||||
}
|
||||
|
||||
static inline void i2c_start(struct efx_i2c_interface *i2c)
|
||||
{
|
||||
/* We may be restarting immediately after a {send,recv}_bit,
|
||||
* so SCL will not necessarily already be high.
|
||||
*/
|
||||
EFX_WARN_ON_PARANOID(!i2c->sda);
|
||||
setscl(i2c, 1);
|
||||
setsda(i2c, 0);
|
||||
setscl(i2c, 0);
|
||||
setsda(i2c, 1);
|
||||
}
|
||||
|
||||
static inline void i2c_send_bit(struct efx_i2c_interface *i2c, int bit)
|
||||
{
|
||||
EFX_WARN_ON_PARANOID(i2c->scl != 0);
|
||||
setsda(i2c, bit);
|
||||
setscl(i2c, 1);
|
||||
setscl(i2c, 0);
|
||||
setsda(i2c, 1);
|
||||
}
|
||||
|
||||
static inline int i2c_recv_bit(struct efx_i2c_interface *i2c)
|
||||
{
|
||||
int bit;
|
||||
|
||||
EFX_WARN_ON_PARANOID(i2c->scl != 0);
|
||||
EFX_WARN_ON_PARANOID(!i2c->sda);
|
||||
setscl(i2c, 1);
|
||||
bit = getsda(i2c);
|
||||
setscl(i2c, 0);
|
||||
return bit;
|
||||
}
|
||||
|
||||
static inline void i2c_stop(struct efx_i2c_interface *i2c)
|
||||
{
|
||||
EFX_WARN_ON_PARANOID(i2c->scl != 0);
|
||||
setsda(i2c, 0);
|
||||
setscl(i2c, 1);
|
||||
setsda(i2c, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C mid-level protocol operations
|
||||
*
|
||||
*/
|
||||
|
||||
/* Sends a byte via the I2C bus and checks for an acknowledgement from
|
||||
* the slave device.
|
||||
*/
|
||||
static int i2c_send_byte(struct efx_i2c_interface *i2c, u8 byte)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Send byte */
|
||||
for (i = 0; i < 8; i++) {
|
||||
i2c_send_bit(i2c, !!(byte & 0x80));
|
||||
byte <<= 1;
|
||||
}
|
||||
|
||||
/* Check for acknowledgement from slave */
|
||||
return (i2c_recv_bit(i2c) == 0 ? 0 : -EIO);
|
||||
}
|
||||
|
||||
/* Receives a byte via the I2C bus and sends ACK/NACK to the slave device. */
|
||||
static u8 i2c_recv_byte(struct efx_i2c_interface *i2c, int ack)
|
||||
{
|
||||
u8 value = 0;
|
||||
int i;
|
||||
|
||||
/* Receive byte */
|
||||
for (i = 0; i < 8; i++)
|
||||
value = (value << 1) | i2c_recv_bit(i2c);
|
||||
|
||||
/* Send ACK/NACK */
|
||||
i2c_send_bit(i2c, (ack ? 0 : 1));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Calculate command byte for a read operation */
|
||||
static inline u8 i2c_read_cmd(u8 device_id)
|
||||
{
|
||||
return ((device_id << 1) | 1);
|
||||
}
|
||||
|
||||
/* Calculate command byte for a write operation */
|
||||
static inline u8 i2c_write_cmd(u8 device_id)
|
||||
{
|
||||
return ((device_id << 1) | 0);
|
||||
}
|
||||
|
||||
int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* If someone is driving the bus low we just give up. */
|
||||
if (getsda(i2c) == 0 || getscl(i2c) == 0) {
|
||||
EFX_ERR(i2c->efx, "%s someone is holding the I2C bus low."
|
||||
" Giving up.\n", __func__);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* Pretend to initiate a device write */
|
||||
i2c_start(i2c);
|
||||
rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
i2c_stop(i2c);
|
||||
i2c_release(i2c);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* This performs a fast read of one or more consecutive bytes from an
|
||||
* I2C device. Not all devices support consecutive reads of more than
|
||||
* one byte; for these devices use efx_i2c_read() instead.
|
||||
*/
|
||||
int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
|
||||
u8 device_id, u8 offset, u8 *data, unsigned int len)
|
||||
{
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
|
||||
EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
|
||||
EFX_WARN_ON_PARANOID(data == NULL);
|
||||
EFX_WARN_ON_PARANOID(len < 1);
|
||||
|
||||
/* Select device and starting offset */
|
||||
i2c_start(i2c);
|
||||
rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
|
||||
if (rc)
|
||||
goto out;
|
||||
rc = i2c_send_byte(i2c, offset);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/* Read data from device */
|
||||
i2c_start(i2c);
|
||||
rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
|
||||
if (rc)
|
||||
goto out;
|
||||
for (i = 0; i < (len - 1); i++)
|
||||
/* Read and acknowledge all but the last byte */
|
||||
data[i] = i2c_recv_byte(i2c, 1);
|
||||
/* Read last byte with no acknowledgement */
|
||||
data[i] = i2c_recv_byte(i2c, 0);
|
||||
|
||||
out:
|
||||
i2c_stop(i2c);
|
||||
i2c_release(i2c);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* This performs a fast write of one or more consecutive bytes to an
|
||||
* I2C device. Not all devices support consecutive writes of more
|
||||
* than one byte; for these devices use efx_i2c_write() instead.
|
||||
*/
|
||||
int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
|
||||
u8 device_id, u8 offset,
|
||||
const u8 *data, unsigned int len)
|
||||
{
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
|
||||
EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
|
||||
EFX_WARN_ON_PARANOID(len < 1);
|
||||
|
||||
/* Select device and starting offset */
|
||||
i2c_start(i2c);
|
||||
rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
|
||||
if (rc)
|
||||
goto out;
|
||||
rc = i2c_send_byte(i2c, offset);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/* Write data to device */
|
||||
for (i = 0; i < len; i++) {
|
||||
rc = i2c_send_byte(i2c, data[i]);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
i2c_stop(i2c);
|
||||
i2c_release(i2c);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* I2C byte-by-byte read */
|
||||
int efx_i2c_read(struct efx_i2c_interface *i2c,
|
||||
u8 device_id, u8 offset, u8 *data, unsigned int len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* i2c_fast_read with length 1 is a single byte read */
|
||||
for (; len > 0; offset++, data++, len--) {
|
||||
rc = efx_i2c_fast_read(i2c, device_id, offset, data, 1);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* I2C byte-by-byte write */
|
||||
int efx_i2c_write(struct efx_i2c_interface *i2c,
|
||||
u8 device_id, u8 offset, const u8 *data, unsigned int len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* i2c_fast_write with length 1 is a single byte write */
|
||||
for (; len > 0; offset++, data++, len--) {
|
||||
rc = efx_i2c_fast_write(i2c, device_id, offset, data, 1);
|
||||
if (rc)
|
||||
return rc;
|
||||
mdelay(i2c->op->mdelay);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* This is just a slightly neater wrapper round efx_i2c_fast_write
|
||||
* in the case where the target doesn't take an offset
|
||||
*/
|
||||
int efx_i2c_send_bytes(struct efx_i2c_interface *i2c,
|
||||
u8 device_id, const u8 *data, unsigned int len)
|
||||
{
|
||||
return efx_i2c_fast_write(i2c, device_id, data[0], data + 1, len - 1);
|
||||
}
|
||||
|
||||
/* I2C receiving of bytes - does not send an offset byte */
|
||||
int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
|
||||
u8 *bytes, unsigned int len)
|
||||
{
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
|
||||
EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
|
||||
EFX_WARN_ON_PARANOID(len < 1);
|
||||
|
||||
/* Select device */
|
||||
i2c_start(i2c);
|
||||
|
||||
/* Read data from device */
|
||||
rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < (len - 1); i++)
|
||||
/* Read and acknowledge all but the last byte */
|
||||
bytes[i] = i2c_recv_byte(i2c, 1);
|
||||
/* Read last byte with no acknowledgement */
|
||||
bytes[i] = i2c_recv_byte(i2c, 0);
|
||||
|
||||
out:
|
||||
i2c_stop(i2c);
|
||||
i2c_release(i2c);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* SMBus and some I2C devices will time out if the I2C clock is
|
||||
* held low for too long. This is most likely to happen in virtualised
|
||||
* systems (when the entire domain is descheduled) but could in
|
||||
* principle happen due to preemption on any busy system (and given the
|
||||
* potential length of an I2C operation turning preemption off is not
|
||||
* a sensible option). The following functions deal with the failure by
|
||||
* retrying up to a fixed number of times.
|
||||
*/
|
||||
|
||||
#define I2C_MAX_RETRIES (10)
|
||||
|
||||
/* The timeout problem will result in -EIO. If the wrapped function
|
||||
* returns any other error, pass this up and do not retry. */
|
||||
#define RETRY_WRAPPER(_f) \
|
||||
int retries = I2C_MAX_RETRIES; \
|
||||
int rc; \
|
||||
while (retries) { \
|
||||
rc = _f; \
|
||||
if (rc != -EIO) \
|
||||
return rc; \
|
||||
retries--; \
|
||||
} \
|
||||
return rc; \
|
||||
|
||||
int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c, u8 device_id)
|
||||
{
|
||||
RETRY_WRAPPER(efx_i2c_check_presence(i2c, device_id))
|
||||
}
|
||||
|
||||
int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
|
||||
u8 device_id, u8 offset, u8 *data, unsigned int len)
|
||||
{
|
||||
RETRY_WRAPPER(efx_i2c_read(i2c, device_id, offset, data, len))
|
||||
}
|
||||
|
||||
int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
|
||||
u8 device_id, u8 offset, const u8 *data, unsigned int len)
|
||||
{
|
||||
RETRY_WRAPPER(efx_i2c_write(i2c, device_id, offset, data, len))
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue