mirror of https://gitee.com/openkylin/linux.git
Merge branch 'can/mcp251x-for-net-next' of git://git.pengutronix.de/git/mkl/linux-2.6
This commit is contained in:
commit
a47d60561e
|
@ -38,14 +38,14 @@
|
||||||
* static struct mcp251x_platform_data mcp251x_info = {
|
* static struct mcp251x_platform_data mcp251x_info = {
|
||||||
* .oscillator_frequency = 8000000,
|
* .oscillator_frequency = 8000000,
|
||||||
* .board_specific_setup = &mcp251x_setup,
|
* .board_specific_setup = &mcp251x_setup,
|
||||||
* .model = CAN_MCP251X_MCP2510,
|
|
||||||
* .power_enable = mcp251x_power_enable,
|
* .power_enable = mcp251x_power_enable,
|
||||||
* .transceiver_enable = NULL,
|
* .transceiver_enable = NULL,
|
||||||
* };
|
* };
|
||||||
*
|
*
|
||||||
* static struct spi_board_info spi_board_info[] = {
|
* static struct spi_board_info spi_board_info[] = {
|
||||||
* {
|
* {
|
||||||
* .modalias = "mcp251x",
|
* .modalias = "mcp2510",
|
||||||
|
* // or "mcp2515" depending on your controller
|
||||||
* .platform_data = &mcp251x_info,
|
* .platform_data = &mcp251x_info,
|
||||||
* .irq = IRQ_EINT13,
|
* .irq = IRQ_EINT13,
|
||||||
* .max_speed_hz = 2*1000*1000,
|
* .max_speed_hz = 2*1000*1000,
|
||||||
|
@ -125,6 +125,8 @@
|
||||||
# define CANINTF_TX0IF 0x04
|
# define CANINTF_TX0IF 0x04
|
||||||
# define CANINTF_RX1IF 0x02
|
# define CANINTF_RX1IF 0x02
|
||||||
# define CANINTF_RX0IF 0x01
|
# define CANINTF_RX0IF 0x01
|
||||||
|
# define CANINTF_ERR_TX \
|
||||||
|
(CANINTF_ERRIF | CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)
|
||||||
#define EFLG 0x2d
|
#define EFLG 0x2d
|
||||||
# define EFLG_EWARN 0x01
|
# define EFLG_EWARN 0x01
|
||||||
# define EFLG_RXWAR 0x02
|
# define EFLG_RXWAR 0x02
|
||||||
|
@ -222,10 +224,16 @@ static struct can_bittiming_const mcp251x_bittiming_const = {
|
||||||
.brp_inc = 1,
|
.brp_inc = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum mcp251x_model {
|
||||||
|
CAN_MCP251X_MCP2510 = 0x2510,
|
||||||
|
CAN_MCP251X_MCP2515 = 0x2515,
|
||||||
|
};
|
||||||
|
|
||||||
struct mcp251x_priv {
|
struct mcp251x_priv {
|
||||||
struct can_priv can;
|
struct can_priv can;
|
||||||
struct net_device *net;
|
struct net_device *net;
|
||||||
struct spi_device *spi;
|
struct spi_device *spi;
|
||||||
|
enum mcp251x_model model;
|
||||||
|
|
||||||
struct mutex mcp_lock; /* SPI device lock */
|
struct mutex mcp_lock; /* SPI device lock */
|
||||||
|
|
||||||
|
@ -250,6 +258,16 @@ struct mcp251x_priv {
|
||||||
int restart_tx;
|
int restart_tx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MCP251X_IS(_model) \
|
||||||
|
static inline int mcp251x_is_##_model(struct spi_device *spi) \
|
||||||
|
{ \
|
||||||
|
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); \
|
||||||
|
return priv->model == CAN_MCP251X_MCP##_model; \
|
||||||
|
}
|
||||||
|
|
||||||
|
MCP251X_IS(2510);
|
||||||
|
MCP251X_IS(2515);
|
||||||
|
|
||||||
static void mcp251x_clean(struct net_device *net)
|
static void mcp251x_clean(struct net_device *net)
|
||||||
{
|
{
|
||||||
struct mcp251x_priv *priv = netdev_priv(net);
|
struct mcp251x_priv *priv = netdev_priv(net);
|
||||||
|
@ -319,6 +337,20 @@ static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mcp251x_read_2regs(struct spi_device *spi, uint8_t reg,
|
||||||
|
uint8_t *v1, uint8_t *v2)
|
||||||
|
{
|
||||||
|
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
|
||||||
|
|
||||||
|
priv->spi_tx_buf[0] = INSTRUCTION_READ;
|
||||||
|
priv->spi_tx_buf[1] = reg;
|
||||||
|
|
||||||
|
mcp251x_spi_trans(spi, 4);
|
||||||
|
|
||||||
|
*v1 = priv->spi_rx_buf[2];
|
||||||
|
*v2 = priv->spi_rx_buf[3];
|
||||||
|
}
|
||||||
|
|
||||||
static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
|
static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
|
||||||
{
|
{
|
||||||
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
|
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
|
||||||
|
@ -346,10 +378,9 @@ static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
|
||||||
static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,
|
static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,
|
||||||
int len, int tx_buf_idx)
|
int len, int tx_buf_idx)
|
||||||
{
|
{
|
||||||
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
|
|
||||||
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
|
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
|
||||||
|
|
||||||
if (pdata->model == CAN_MCP251X_MCP2510) {
|
if (mcp251x_is_2510(spi)) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 1; i < TXBDAT_OFF + len; i++)
|
for (i = 1; i < TXBDAT_OFF + len; i++)
|
||||||
|
@ -392,9 +423,8 @@ static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf,
|
||||||
int buf_idx)
|
int buf_idx)
|
||||||
{
|
{
|
||||||
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
|
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
|
||||||
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
|
|
||||||
|
|
||||||
if (pdata->model == CAN_MCP251X_MCP2510) {
|
if (mcp251x_is_2510(spi)) {
|
||||||
int i, len;
|
int i, len;
|
||||||
|
|
||||||
for (i = 1; i < RXBDAT_OFF; i++)
|
for (i = 1; i < RXBDAT_OFF; i++)
|
||||||
|
@ -451,7 +481,7 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
|
||||||
|
|
||||||
priv->net->stats.rx_packets++;
|
priv->net->stats.rx_packets++;
|
||||||
priv->net->stats.rx_bytes += frame->can_dlc;
|
priv->net->stats.rx_bytes += frame->can_dlc;
|
||||||
netif_rx(skb);
|
netif_rx_ni(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mcp251x_hw_sleep(struct spi_device *spi)
|
static void mcp251x_hw_sleep(struct spi_device *spi)
|
||||||
|
@ -676,7 +706,7 @@ static void mcp251x_error_skb(struct net_device *net, int can_id, int data1)
|
||||||
if (skb) {
|
if (skb) {
|
||||||
frame->can_id = can_id;
|
frame->can_id = can_id;
|
||||||
frame->data[1] = data1;
|
frame->data[1] = data1;
|
||||||
netif_rx(skb);
|
netif_rx_ni(skb);
|
||||||
} else {
|
} else {
|
||||||
dev_err(&net->dev,
|
dev_err(&net->dev,
|
||||||
"cannot allocate error skb\n");
|
"cannot allocate error skb\n");
|
||||||
|
@ -754,24 +784,39 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
|
||||||
mutex_lock(&priv->mcp_lock);
|
mutex_lock(&priv->mcp_lock);
|
||||||
while (!priv->force_quit) {
|
while (!priv->force_quit) {
|
||||||
enum can_state new_state;
|
enum can_state new_state;
|
||||||
u8 intf = mcp251x_read_reg(spi, CANINTF);
|
u8 intf, eflag;
|
||||||
u8 eflag;
|
u8 clear_intf = 0;
|
||||||
int can_id = 0, data1 = 0;
|
int can_id = 0, data1 = 0;
|
||||||
|
|
||||||
|
mcp251x_read_2regs(spi, CANINTF, &intf, &eflag);
|
||||||
|
|
||||||
|
/* receive buffer 0 */
|
||||||
if (intf & CANINTF_RX0IF) {
|
if (intf & CANINTF_RX0IF) {
|
||||||
mcp251x_hw_rx(spi, 0);
|
mcp251x_hw_rx(spi, 0);
|
||||||
/* Free one buffer ASAP */
|
/*
|
||||||
mcp251x_write_bits(spi, CANINTF, intf & CANINTF_RX0IF,
|
* Free one buffer ASAP
|
||||||
0x00);
|
* (The MCP2515 does this automatically.)
|
||||||
|
*/
|
||||||
|
if (mcp251x_is_2510(spi))
|
||||||
|
mcp251x_write_bits(spi, CANINTF, CANINTF_RX0IF, 0x00);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intf & CANINTF_RX1IF)
|
/* receive buffer 1 */
|
||||||
|
if (intf & CANINTF_RX1IF) {
|
||||||
mcp251x_hw_rx(spi, 1);
|
mcp251x_hw_rx(spi, 1);
|
||||||
|
/* the MCP2515 does this automatically */
|
||||||
|
if (mcp251x_is_2510(spi))
|
||||||
|
clear_intf |= CANINTF_RX1IF;
|
||||||
|
}
|
||||||
|
|
||||||
mcp251x_write_bits(spi, CANINTF, intf, 0x00);
|
/* any error or tx interrupt we need to clear? */
|
||||||
|
if (intf & CANINTF_ERR_TX)
|
||||||
|
clear_intf |= intf & CANINTF_ERR_TX;
|
||||||
|
if (clear_intf)
|
||||||
|
mcp251x_write_bits(spi, CANINTF, clear_intf, 0x00);
|
||||||
|
|
||||||
eflag = mcp251x_read_reg(spi, EFLG);
|
if (eflag)
|
||||||
mcp251x_write_reg(spi, EFLG, 0x00);
|
mcp251x_write_bits(spi, EFLG, eflag, 0x00);
|
||||||
|
|
||||||
/* Update can state */
|
/* Update can state */
|
||||||
if (eflag & EFLG_TXBO) {
|
if (eflag & EFLG_TXBO) {
|
||||||
|
@ -816,10 +861,14 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
|
||||||
if (intf & CANINTF_ERRIF) {
|
if (intf & CANINTF_ERRIF) {
|
||||||
/* Handle overflow counters */
|
/* Handle overflow counters */
|
||||||
if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
|
if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
|
||||||
if (eflag & EFLG_RX0OVR)
|
if (eflag & EFLG_RX0OVR) {
|
||||||
net->stats.rx_over_errors++;
|
net->stats.rx_over_errors++;
|
||||||
if (eflag & EFLG_RX1OVR)
|
net->stats.rx_errors++;
|
||||||
|
}
|
||||||
|
if (eflag & EFLG_RX1OVR) {
|
||||||
net->stats.rx_over_errors++;
|
net->stats.rx_over_errors++;
|
||||||
|
net->stats.rx_errors++;
|
||||||
|
}
|
||||||
can_id |= CAN_ERR_CRTL;
|
can_id |= CAN_ERR_CRTL;
|
||||||
data1 |= CAN_ERR_CRTL_RX_OVERFLOW;
|
data1 |= CAN_ERR_CRTL_RX_OVERFLOW;
|
||||||
}
|
}
|
||||||
|
@ -921,16 +970,12 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
|
||||||
struct net_device *net;
|
struct net_device *net;
|
||||||
struct mcp251x_priv *priv;
|
struct mcp251x_priv *priv;
|
||||||
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
|
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
|
||||||
int model = spi_get_device_id(spi)->driver_data;
|
|
||||||
int ret = -ENODEV;
|
int ret = -ENODEV;
|
||||||
|
|
||||||
if (!pdata)
|
if (!pdata)
|
||||||
/* Platform data is required for osc freq */
|
/* Platform data is required for osc freq */
|
||||||
goto error_out;
|
goto error_out;
|
||||||
|
|
||||||
if (model)
|
|
||||||
pdata->model = model;
|
|
||||||
|
|
||||||
/* Allocate can/net device */
|
/* Allocate can/net device */
|
||||||
net = alloc_candev(sizeof(struct mcp251x_priv), TX_ECHO_SKB_MAX);
|
net = alloc_candev(sizeof(struct mcp251x_priv), TX_ECHO_SKB_MAX);
|
||||||
if (!net) {
|
if (!net) {
|
||||||
|
@ -947,6 +992,7 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
|
||||||
priv->can.clock.freq = pdata->oscillator_frequency / 2;
|
priv->can.clock.freq = pdata->oscillator_frequency / 2;
|
||||||
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
|
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
|
||||||
CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;
|
CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;
|
||||||
|
priv->model = spi_get_device_id(spi)->driver_data;
|
||||||
priv->net = net;
|
priv->net = net;
|
||||||
dev_set_drvdata(&spi->dev, priv);
|
dev_set_drvdata(&spi->dev, priv);
|
||||||
|
|
||||||
|
@ -1120,8 +1166,7 @@ static int mcp251x_can_resume(struct spi_device *spi)
|
||||||
#define mcp251x_can_resume NULL
|
#define mcp251x_can_resume NULL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct spi_device_id mcp251x_id_table[] = {
|
static const struct spi_device_id mcp251x_id_table[] = {
|
||||||
{ "mcp251x", 0 /* Use pdata.model */ },
|
|
||||||
{ "mcp2510", CAN_MCP251X_MCP2510 },
|
{ "mcp2510", CAN_MCP251X_MCP2510 },
|
||||||
{ "mcp2515", CAN_MCP251X_MCP2515 },
|
{ "mcp2515", CAN_MCP251X_MCP2515 },
|
||||||
{ },
|
{ },
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
/**
|
/**
|
||||||
* struct mcp251x_platform_data - MCP251X SPI CAN controller platform data
|
* struct mcp251x_platform_data - MCP251X SPI CAN controller platform data
|
||||||
* @oscillator_frequency: - oscillator frequency in Hz
|
* @oscillator_frequency: - oscillator frequency in Hz
|
||||||
* @model: - actual type of chip
|
|
||||||
* @board_specific_setup: - called before probing the chip (power,reset)
|
* @board_specific_setup: - called before probing the chip (power,reset)
|
||||||
* @transceiver_enable: - called to power on/off the transceiver
|
* @transceiver_enable: - called to power on/off the transceiver
|
||||||
* @power_enable: - called to power on/off the mcp *and* the
|
* @power_enable: - called to power on/off the mcp *and* the
|
||||||
|
@ -25,9 +24,6 @@
|
||||||
|
|
||||||
struct mcp251x_platform_data {
|
struct mcp251x_platform_data {
|
||||||
unsigned long oscillator_frequency;
|
unsigned long oscillator_frequency;
|
||||||
int model;
|
|
||||||
#define CAN_MCP251X_MCP2510 0x2510
|
|
||||||
#define CAN_MCP251X_MCP2515 0x2515
|
|
||||||
int (*board_specific_setup)(struct spi_device *spi);
|
int (*board_specific_setup)(struct spi_device *spi);
|
||||||
int (*transceiver_enable)(int enable);
|
int (*transceiver_enable)(int enable);
|
||||||
int (*power_enable) (int enable);
|
int (*power_enable) (int enable);
|
||||||
|
|
Loading…
Reference in New Issue