mirror of
https://github.com/torvalds/linux.git
synced 2024-11-12 07:01:57 +00:00
sfc: Use kernel I2C system and i2c-algo-bit driver
Remove our own implementation of I2C bit-banging. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
This commit is contained in:
parent
9e833be3a1
commit
37b5a60335
@ -4,6 +4,8 @@ config SFC
|
||||
select MII
|
||||
select INET_LRO
|
||||
select CRC32
|
||||
select I2C
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
This driver supports 10-gigabit Ethernet cards based on
|
||||
the Solarflare Communications Solarstorm SFC4000 controller.
|
||||
|
@ -1,5 +1,5 @@
|
||||
sfc-y += efx.o falcon.o tx.o rx.o falcon_xmac.o \
|
||||
i2c-direct.o selftest.o ethtool.o xfp_phy.o \
|
||||
selftest.o ethtool.o xfp_phy.o \
|
||||
mdio_10g.o tenxpress.o boards.o sfe4001.o
|
||||
|
||||
obj-$(CONFIG_SFC) += sfc.o
|
||||
|
@ -109,7 +109,7 @@ static struct efx_board_data board_data[] = {
|
||||
[EFX_BOARD_INVALID] =
|
||||
{NULL, NULL, dummy_init},
|
||||
[EFX_BOARD_SFE4001] =
|
||||
{"SFE4001", "10GBASE-T adapter", sfe4001_poweron},
|
||||
{"SFE4001", "10GBASE-T adapter", sfe4001_init},
|
||||
[EFX_BOARD_SFE4002] =
|
||||
{"SFE4002", "XFP adapter", sfe4002_init},
|
||||
};
|
||||
|
@ -20,8 +20,7 @@ enum efx_board_type {
|
||||
};
|
||||
|
||||
extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info);
|
||||
extern int sfe4001_poweron(struct efx_nic *efx);
|
||||
extern void sfe4001_poweroff(struct efx_nic *efx);
|
||||
extern int sfe4001_init(struct efx_nic *efx);
|
||||
/* Are we putting the PHY into flash config mode */
|
||||
extern unsigned int sfe4001_phy_flash_cfg;
|
||||
|
||||
|
@ -1815,6 +1815,7 @@ static struct efx_board efx_dummy_board_info = {
|
||||
.init = efx_nic_dummy_op_int,
|
||||
.init_leds = efx_port_dummy_op_int,
|
||||
.set_fault_led = efx_port_dummy_op_blink,
|
||||
.fini = efx_port_dummy_op_void,
|
||||
};
|
||||
|
||||
/**************************************************************************
|
||||
@ -1941,6 +1942,7 @@ static void efx_pci_remove_main(struct efx_nic *efx)
|
||||
efx_fini_port(efx);
|
||||
|
||||
/* Shutdown the board, then the NIC and board state */
|
||||
efx->board_info.fini(efx);
|
||||
falcon_fini_interrupt(efx);
|
||||
|
||||
efx_fini_napi(efx);
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include "net_driver.h"
|
||||
#include "bitfield.h"
|
||||
#include "efx.h"
|
||||
@ -36,10 +38,12 @@
|
||||
* struct falcon_nic_data - Falcon NIC state
|
||||
* @next_buffer_table: First available buffer table id
|
||||
* @pci_dev2: The secondary PCI device if present
|
||||
* @i2c_data: Operations and state for I2C bit-bashing algorithm
|
||||
*/
|
||||
struct falcon_nic_data {
|
||||
unsigned next_buffer_table;
|
||||
struct pci_dev *pci_dev2;
|
||||
struct i2c_algo_bit_data i2c_data;
|
||||
};
|
||||
|
||||
/**************************************************************************
|
||||
@ -175,39 +179,57 @@ static inline int falcon_event_present(efx_qword_t *event)
|
||||
*
|
||||
**************************************************************************
|
||||
*/
|
||||
static void falcon_setsdascl(struct efx_i2c_interface *i2c)
|
||||
static void falcon_setsda(void *data, int state)
|
||||
{
|
||||
struct efx_nic *efx = (struct efx_nic *)data;
|
||||
efx_oword_t reg;
|
||||
|
||||
falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER);
|
||||
EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, (i2c->scl ? 0 : 1));
|
||||
EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, (i2c->sda ? 0 : 1));
|
||||
falcon_write(i2c->efx, ®, GPIO_CTL_REG_KER);
|
||||
falcon_read(efx, ®, GPIO_CTL_REG_KER);
|
||||
EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, !state);
|
||||
falcon_write(efx, ®, GPIO_CTL_REG_KER);
|
||||
}
|
||||
|
||||
static int falcon_getsda(struct efx_i2c_interface *i2c)
|
||||
static void falcon_setscl(void *data, int state)
|
||||
{
|
||||
struct efx_nic *efx = (struct efx_nic *)data;
|
||||
efx_oword_t reg;
|
||||
|
||||
falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER);
|
||||
falcon_read(efx, ®, GPIO_CTL_REG_KER);
|
||||
EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, !state);
|
||||
falcon_write(efx, ®, GPIO_CTL_REG_KER);
|
||||
}
|
||||
|
||||
static int falcon_getsda(void *data)
|
||||
{
|
||||
struct efx_nic *efx = (struct efx_nic *)data;
|
||||
efx_oword_t reg;
|
||||
|
||||
falcon_read(efx, ®, GPIO_CTL_REG_KER);
|
||||
return EFX_OWORD_FIELD(reg, GPIO3_IN);
|
||||
}
|
||||
|
||||
static int falcon_getscl(struct efx_i2c_interface *i2c)
|
||||
static int falcon_getscl(void *data)
|
||||
{
|
||||
struct efx_nic *efx = (struct efx_nic *)data;
|
||||
efx_oword_t reg;
|
||||
|
||||
falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER);
|
||||
return EFX_DWORD_FIELD(reg, GPIO0_IN);
|
||||
falcon_read(efx, ®, GPIO_CTL_REG_KER);
|
||||
return EFX_OWORD_FIELD(reg, GPIO0_IN);
|
||||
}
|
||||
|
||||
static struct efx_i2c_bit_operations falcon_i2c_bit_operations = {
|
||||
.setsda = falcon_setsdascl,
|
||||
.setscl = falcon_setsdascl,
|
||||
static struct i2c_algo_bit_data falcon_i2c_bit_operations = {
|
||||
.setsda = falcon_setsda,
|
||||
.setscl = falcon_setscl,
|
||||
.getsda = falcon_getsda,
|
||||
.getscl = falcon_getscl,
|
||||
.udelay = 100,
|
||||
.mdelay = 10,
|
||||
/*
|
||||
* This is the number of system clock ticks after which
|
||||
* i2c-algo-bit gives up waiting for SCL to become high.
|
||||
* It must be at least 2 since the first tick can happen
|
||||
* immediately after it starts waiting.
|
||||
*/
|
||||
.timeout = 2,
|
||||
};
|
||||
|
||||
/**************************************************************************
|
||||
@ -2403,12 +2425,6 @@ int falcon_probe_nic(struct efx_nic *efx)
|
||||
struct falcon_nic_data *nic_data;
|
||||
int rc;
|
||||
|
||||
/* Initialise I2C interface state */
|
||||
efx->i2c.efx = efx;
|
||||
efx->i2c.op = &falcon_i2c_bit_operations;
|
||||
efx->i2c.sda = 1;
|
||||
efx->i2c.scl = 1;
|
||||
|
||||
/* Allocate storage for hardware specific data */
|
||||
nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
|
||||
efx->nic_data = nic_data;
|
||||
@ -2459,6 +2475,18 @@ int falcon_probe_nic(struct efx_nic *efx)
|
||||
if (rc)
|
||||
goto fail5;
|
||||
|
||||
/* Initialise I2C adapter */
|
||||
efx->i2c_adap.owner = THIS_MODULE;
|
||||
efx->i2c_adap.class = I2C_CLASS_HWMON;
|
||||
nic_data->i2c_data = falcon_i2c_bit_operations;
|
||||
nic_data->i2c_data.data = efx;
|
||||
efx->i2c_adap.algo_data = &nic_data->i2c_data;
|
||||
efx->i2c_adap.dev.parent = &efx->pci_dev->dev;
|
||||
strcpy(efx->i2c_adap.name, "SFC4000 GPIO");
|
||||
rc = i2c_bit_add_bus(&efx->i2c_adap);
|
||||
if (rc)
|
||||
goto fail5;
|
||||
|
||||
return 0;
|
||||
|
||||
fail5:
|
||||
@ -2633,6 +2661,10 @@ int falcon_init_nic(struct efx_nic *efx)
|
||||
void falcon_remove_nic(struct efx_nic *efx)
|
||||
{
|
||||
struct falcon_nic_data *nic_data = efx->nic_data;
|
||||
int rc;
|
||||
|
||||
rc = i2c_del_adapter(&efx->i2c_adap);
|
||||
BUG_ON(rc);
|
||||
|
||||
falcon_free_buffer(efx, &efx->irq_status);
|
||||
|
||||
|
@ -1,381 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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))
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
/****************************************************************************
|
||||
* Driver for Solarflare Solarstorm network controllers and boards
|
||||
* Copyright 2005 Fen Systems Ltd.
|
||||
* Copyright 2006 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.
|
||||
*/
|
||||
|
||||
#ifndef EFX_I2C_DIRECT_H
|
||||
#define EFX_I2C_DIRECT_H
|
||||
|
||||
#include "net_driver.h"
|
||||
|
||||
/*
|
||||
* Direct control of an I2C bus
|
||||
*/
|
||||
|
||||
struct efx_i2c_interface;
|
||||
|
||||
/**
|
||||
* struct efx_i2c_bit_operations - I2C bus direct control methods
|
||||
*
|
||||
* I2C bus direct control methods.
|
||||
*
|
||||
* @setsda: Set state of SDA line
|
||||
* @setscl: Set state of SCL line
|
||||
* @getsda: Get state of SDA line
|
||||
* @getscl: Get state of SCL line
|
||||
* @udelay: Delay between each bit operation
|
||||
* @mdelay: Delay between each byte write
|
||||
*/
|
||||
struct efx_i2c_bit_operations {
|
||||
void (*setsda) (struct efx_i2c_interface *i2c);
|
||||
void (*setscl) (struct efx_i2c_interface *i2c);
|
||||
int (*getsda) (struct efx_i2c_interface *i2c);
|
||||
int (*getscl) (struct efx_i2c_interface *i2c);
|
||||
unsigned int udelay;
|
||||
unsigned int mdelay;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct efx_i2c_interface - an I2C interface
|
||||
*
|
||||
* An I2C interface.
|
||||
*
|
||||
* @efx: Attached Efx NIC
|
||||
* @op: I2C bus control methods
|
||||
* @sda: Current output state of SDA line
|
||||
* @scl: Current output state of SCL line
|
||||
*/
|
||||
struct efx_i2c_interface {
|
||||
struct efx_nic *efx;
|
||||
struct efx_i2c_bit_operations *op;
|
||||
unsigned int sda:1;
|
||||
unsigned int scl:1;
|
||||
};
|
||||
|
||||
extern int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id);
|
||||
extern int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
|
||||
u8 device_id, u8 offset,
|
||||
u8 *data, unsigned int len);
|
||||
extern int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
|
||||
u8 device_id, u8 offset,
|
||||
const u8 *data, unsigned int len);
|
||||
extern int efx_i2c_read(struct efx_i2c_interface *i2c,
|
||||
u8 device_id, u8 offset, u8 *data, unsigned int len);
|
||||
extern int efx_i2c_write(struct efx_i2c_interface *i2c,
|
||||
u8 device_id, u8 offset,
|
||||
const u8 *data, unsigned int len);
|
||||
|
||||
extern int efx_i2c_send_bytes(struct efx_i2c_interface *i2c, u8 device_id,
|
||||
const u8 *bytes, unsigned int len);
|
||||
|
||||
extern int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
|
||||
u8 *bytes, unsigned int len);
|
||||
|
||||
|
||||
/* Versions of the API that retry on failure. */
|
||||
extern int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c,
|
||||
u8 device_id);
|
||||
|
||||
extern int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
|
||||
u8 device_id, u8 offset, u8 *data, unsigned int len);
|
||||
|
||||
extern int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
|
||||
u8 device_id, u8 offset,
|
||||
const u8 *data, unsigned int len);
|
||||
|
||||
#endif /* EFX_I2C_DIRECT_H */
|
@ -26,10 +26,10 @@
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/inet_lro.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#include "enum.h"
|
||||
#include "bitfield.h"
|
||||
#include "i2c-direct.h"
|
||||
|
||||
#define EFX_MAX_LRO_DESCRIPTORS 8
|
||||
#define EFX_MAX_LRO_AGGR MAX_SKB_FRAGS
|
||||
@ -418,7 +418,10 @@ struct efx_blinker {
|
||||
* @init_leds: Sets up board LEDs
|
||||
* @set_fault_led: Turns the fault LED on or off
|
||||
* @blink: Starts/stops blinking
|
||||
* @fini: Cleanup function
|
||||
* @blinker: used to blink LEDs in software
|
||||
* @hwmon_client: I2C client for hardware monitor
|
||||
* @ioexp_client: I2C client for power/port control
|
||||
*/
|
||||
struct efx_board {
|
||||
int type;
|
||||
@ -431,7 +434,9 @@ struct efx_board {
|
||||
int (*init_leds)(struct efx_nic *efx);
|
||||
void (*set_fault_led) (struct efx_nic *efx, int state);
|
||||
void (*blink) (struct efx_nic *efx, int start);
|
||||
void (*fini) (struct efx_nic *nic);
|
||||
struct efx_blinker blinker;
|
||||
struct i2c_client *hwmon_client, *ioexp_client;
|
||||
};
|
||||
|
||||
#define STRING_TABLE_LOOKUP(val, member) \
|
||||
@ -618,7 +623,7 @@ union efx_multicast_hash {
|
||||
* @membase: Memory BAR value
|
||||
* @biu_lock: BIU (bus interface unit) lock
|
||||
* @interrupt_mode: Interrupt mode
|
||||
* @i2c: I2C interface
|
||||
* @i2c_adap: I2C adapter
|
||||
* @board_info: Board-level information
|
||||
* @state: Device state flag. Serialised by the rtnl_lock.
|
||||
* @reset_pending: Pending reset method (normally RESET_TYPE_NONE)
|
||||
@ -686,7 +691,7 @@ struct efx_nic {
|
||||
spinlock_t biu_lock;
|
||||
enum efx_int_mode interrupt_mode;
|
||||
|
||||
struct efx_i2c_interface i2c;
|
||||
struct i2c_adapter i2c_adap;
|
||||
struct efx_board board_info;
|
||||
|
||||
enum nic_state state;
|
||||
|
@ -106,28 +106,27 @@
|
||||
|
||||
static const u8 xgphy_max_temperature = 90;
|
||||
|
||||
void sfe4001_poweroff(struct efx_nic *efx)
|
||||
static void sfe4001_poweroff(struct efx_nic *efx)
|
||||
{
|
||||
struct efx_i2c_interface *i2c = &efx->i2c;
|
||||
struct i2c_client *ioexp_client = efx->board_info.ioexp_client;
|
||||
struct i2c_client *hwmon_client = efx->board_info.hwmon_client;
|
||||
|
||||
u8 cfg, out, in;
|
||||
|
||||
EFX_INFO(efx, "%s\n", __func__);
|
||||
|
||||
/* Turn off all power rails */
|
||||
out = 0xff;
|
||||
efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
|
||||
|
||||
/* Disable port 1 outputs on IO expander */
|
||||
cfg = 0xff;
|
||||
efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
|
||||
|
||||
/* Disable port 0 outputs on IO expander */
|
||||
cfg = 0xff;
|
||||
efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
|
||||
/* Turn off all power rails and disable outputs */
|
||||
i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff);
|
||||
i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff);
|
||||
i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff);
|
||||
|
||||
/* Clear any over-temperature alert */
|
||||
efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
|
||||
i2c_smbus_read_byte_data(hwmon_client, RSL);
|
||||
}
|
||||
|
||||
static void sfe4001_fini(struct efx_nic *efx)
|
||||
{
|
||||
EFX_INFO(efx, "%s\n", __func__);
|
||||
|
||||
sfe4001_poweroff(efx);
|
||||
i2c_unregister_device(efx->board_info.ioexp_client);
|
||||
i2c_unregister_device(efx->board_info.hwmon_client);
|
||||
}
|
||||
|
||||
/* The P0_EN_3V3X line on SFE4001 boards (from A2 onward) is connected
|
||||
@ -143,14 +142,26 @@ MODULE_PARM_DESC(phy_flash_cfg,
|
||||
* be turned on before the PHY can be used.
|
||||
* Context: Process context, rtnl lock held
|
||||
*/
|
||||
int sfe4001_poweron(struct efx_nic *efx)
|
||||
int sfe4001_init(struct efx_nic *efx)
|
||||
{
|
||||
struct efx_i2c_interface *i2c = &efx->i2c;
|
||||
struct i2c_client *hwmon_client, *ioexp_client;
|
||||
unsigned int count;
|
||||
int rc;
|
||||
u8 out, in, cfg;
|
||||
u8 out;
|
||||
efx_dword_t reg;
|
||||
|
||||
hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647);
|
||||
if (!hwmon_client)
|
||||
return -EIO;
|
||||
efx->board_info.hwmon_client = hwmon_client;
|
||||
|
||||
ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539);
|
||||
if (!ioexp_client) {
|
||||
rc = -EIO;
|
||||
goto fail_hwmon;
|
||||
}
|
||||
efx->board_info.ioexp_client = ioexp_client;
|
||||
|
||||
/* 10Xpress has fixed-function LED pins, so there is no board-specific
|
||||
* blink code. */
|
||||
efx->board_info.blink = tenxpress_phy_blink;
|
||||
@ -166,44 +177,45 @@ int sfe4001_poweron(struct efx_nic *efx)
|
||||
falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC);
|
||||
udelay(10);
|
||||
|
||||
efx->board_info.fini = sfe4001_fini;
|
||||
|
||||
/* Set DSP over-temperature alert threshold */
|
||||
EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature);
|
||||
rc = efx_i2c_write(i2c, MAX6647, WLHO,
|
||||
&xgphy_max_temperature, 1);
|
||||
rc = i2c_smbus_write_byte_data(hwmon_client, WLHO,
|
||||
xgphy_max_temperature);
|
||||
if (rc)
|
||||
goto fail1;
|
||||
goto fail_ioexp;
|
||||
|
||||
/* Read it back and verify */
|
||||
rc = efx_i2c_read(i2c, MAX6647, RLHN, &in, 1);
|
||||
if (rc)
|
||||
goto fail1;
|
||||
if (in != xgphy_max_temperature) {
|
||||
rc = i2c_smbus_read_byte_data(hwmon_client, RLHN);
|
||||
if (rc < 0)
|
||||
goto fail_ioexp;
|
||||
if (rc != xgphy_max_temperature) {
|
||||
rc = -EFAULT;
|
||||
goto fail1;
|
||||
goto fail_ioexp;
|
||||
}
|
||||
|
||||
/* Clear any previous over-temperature alert */
|
||||
rc = efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
|
||||
if (rc)
|
||||
goto fail1;
|
||||
rc = i2c_smbus_read_byte_data(hwmon_client, RSL);
|
||||
if (rc < 0)
|
||||
goto fail_ioexp;
|
||||
|
||||
/* Enable port 0 and port 1 outputs on IO expander */
|
||||
cfg = 0x00;
|
||||
rc = efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
|
||||
rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00);
|
||||
if (rc)
|
||||
goto fail1;
|
||||
cfg = 0xff & ~(1 << P1_SPARE_LBN);
|
||||
rc = efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
|
||||
goto fail_ioexp;
|
||||
rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG,
|
||||
0xff & ~(1 << P1_SPARE_LBN));
|
||||
if (rc)
|
||||
goto fail2;
|
||||
goto fail_on;
|
||||
|
||||
/* Turn all power off then wait 1 sec. This ensures PHY is reset */
|
||||
out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
|
||||
(0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
|
||||
(0 << P0_EN_1V0X_LBN));
|
||||
rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
|
||||
rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
|
||||
if (rc)
|
||||
goto fail3;
|
||||
goto fail_on;
|
||||
|
||||
schedule_timeout_uninterruptible(HZ);
|
||||
count = 0;
|
||||
@ -215,26 +227,26 @@ int sfe4001_poweron(struct efx_nic *efx)
|
||||
if (sfe4001_phy_flash_cfg)
|
||||
out |= 1 << P0_EN_3V3X_LBN;
|
||||
|
||||
rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
|
||||
rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
|
||||
if (rc)
|
||||
goto fail3;
|
||||
goto fail_on;
|
||||
msleep(10);
|
||||
|
||||
/* Turn on 1V power rail */
|
||||
out &= ~(1 << P0_EN_1V0X_LBN);
|
||||
rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
|
||||
rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
|
||||
if (rc)
|
||||
goto fail3;
|
||||
goto fail_on;
|
||||
|
||||
EFX_INFO(efx, "waiting for power (attempt %d)...\n", count);
|
||||
|
||||
schedule_timeout_uninterruptible(HZ);
|
||||
|
||||
/* Check DSP is powered */
|
||||
rc = efx_i2c_read(i2c, PCA9539, P1_IN, &in, 1);
|
||||
if (rc)
|
||||
goto fail3;
|
||||
if (in & (1 << P1_AFE_PWD_LBN))
|
||||
rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN);
|
||||
if (rc < 0)
|
||||
goto fail_on;
|
||||
if (rc & (1 << P1_AFE_PWD_LBN))
|
||||
goto done;
|
||||
|
||||
/* DSP doesn't look powered in flash config mode */
|
||||
@ -244,23 +256,17 @@ int sfe4001_poweron(struct efx_nic *efx)
|
||||
|
||||
EFX_INFO(efx, "timed out waiting for power\n");
|
||||
rc = -ETIMEDOUT;
|
||||
goto fail3;
|
||||
goto fail_on;
|
||||
|
||||
done:
|
||||
EFX_INFO(efx, "PHY is powered on\n");
|
||||
return 0;
|
||||
|
||||
fail3:
|
||||
/* Turn off all power rails */
|
||||
out = 0xff;
|
||||
efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
|
||||
/* Disable port 1 outputs on IO expander */
|
||||
out = 0xff;
|
||||
efx_i2c_write(i2c, PCA9539, P1_CONFIG, &out, 1);
|
||||
fail2:
|
||||
/* Disable port 0 outputs on IO expander */
|
||||
out = 0xff;
|
||||
efx_i2c_write(i2c, PCA9539, P0_CONFIG, &out, 1);
|
||||
fail1:
|
||||
fail_on:
|
||||
sfe4001_poweroff(efx);
|
||||
fail_ioexp:
|
||||
i2c_unregister_device(ioexp_client);
|
||||
fail_hwmon:
|
||||
i2c_unregister_device(hwmon_client);
|
||||
return rc;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user