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 = {
|
||||
* .oscillator_frequency = 8000000,
|
||||
* .board_specific_setup = &mcp251x_setup,
|
||||
* .model = CAN_MCP251X_MCP2510,
|
||||
* .power_enable = mcp251x_power_enable,
|
||||
* .transceiver_enable = NULL,
|
||||
* };
|
||||
*
|
||||
* static struct spi_board_info spi_board_info[] = {
|
||||
* {
|
||||
* .modalias = "mcp251x",
|
||||
* .modalias = "mcp2510",
|
||||
* // or "mcp2515" depending on your controller
|
||||
* .platform_data = &mcp251x_info,
|
||||
* .irq = IRQ_EINT13,
|
||||
* .max_speed_hz = 2*1000*1000,
|
||||
|
@ -125,6 +125,8 @@
|
|||
# define CANINTF_TX0IF 0x04
|
||||
# define CANINTF_RX1IF 0x02
|
||||
# define CANINTF_RX0IF 0x01
|
||||
# define CANINTF_ERR_TX \
|
||||
(CANINTF_ERRIF | CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)
|
||||
#define EFLG 0x2d
|
||||
# define EFLG_EWARN 0x01
|
||||
# define EFLG_RXWAR 0x02
|
||||
|
@ -222,10 +224,16 @@ static struct can_bittiming_const mcp251x_bittiming_const = {
|
|||
.brp_inc = 1,
|
||||
};
|
||||
|
||||
enum mcp251x_model {
|
||||
CAN_MCP251X_MCP2510 = 0x2510,
|
||||
CAN_MCP251X_MCP2515 = 0x2515,
|
||||
};
|
||||
|
||||
struct mcp251x_priv {
|
||||
struct can_priv can;
|
||||
struct net_device *net;
|
||||
struct spi_device *spi;
|
||||
enum mcp251x_model model;
|
||||
|
||||
struct mutex mcp_lock; /* SPI device lock */
|
||||
|
||||
|
@ -250,6 +258,16 @@ struct mcp251x_priv {
|
|||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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,
|
||||
int len, int tx_buf_idx)
|
||||
{
|
||||
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
|
||||
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
|
||||
|
||||
if (pdata->model == CAN_MCP251X_MCP2510) {
|
||||
if (mcp251x_is_2510(spi)) {
|
||||
int 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)
|
||||
{
|
||||
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;
|
||||
|
||||
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_bytes += frame->can_dlc;
|
||||
netif_rx(skb);
|
||||
netif_rx_ni(skb);
|
||||
}
|
||||
|
||||
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) {
|
||||
frame->can_id = can_id;
|
||||
frame->data[1] = data1;
|
||||
netif_rx(skb);
|
||||
netif_rx_ni(skb);
|
||||
} else {
|
||||
dev_err(&net->dev,
|
||||
"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);
|
||||
while (!priv->force_quit) {
|
||||
enum can_state new_state;
|
||||
u8 intf = mcp251x_read_reg(spi, CANINTF);
|
||||
u8 eflag;
|
||||
u8 intf, eflag;
|
||||
u8 clear_intf = 0;
|
||||
int can_id = 0, data1 = 0;
|
||||
|
||||
mcp251x_read_2regs(spi, CANINTF, &intf, &eflag);
|
||||
|
||||
/* receive buffer 0 */
|
||||
if (intf & CANINTF_RX0IF) {
|
||||
mcp251x_hw_rx(spi, 0);
|
||||
/* Free one buffer ASAP */
|
||||
mcp251x_write_bits(spi, CANINTF, intf & CANINTF_RX0IF,
|
||||
0x00);
|
||||
/*
|
||||
* Free one buffer ASAP
|
||||
* (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);
|
||||
/* 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);
|
||||
mcp251x_write_reg(spi, EFLG, 0x00);
|
||||
if (eflag)
|
||||
mcp251x_write_bits(spi, EFLG, eflag, 0x00);
|
||||
|
||||
/* Update can state */
|
||||
if (eflag & EFLG_TXBO) {
|
||||
|
@ -816,10 +861,14 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
|
|||
if (intf & CANINTF_ERRIF) {
|
||||
/* Handle overflow counters */
|
||||
if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
|
||||
if (eflag & EFLG_RX0OVR)
|
||||
if (eflag & EFLG_RX0OVR) {
|
||||
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_errors++;
|
||||
}
|
||||
can_id |= CAN_ERR_CRTL;
|
||||
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 mcp251x_priv *priv;
|
||||
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
|
||||
int model = spi_get_device_id(spi)->driver_data;
|
||||
int ret = -ENODEV;
|
||||
|
||||
if (!pdata)
|
||||
/* Platform data is required for osc freq */
|
||||
goto error_out;
|
||||
|
||||
if (model)
|
||||
pdata->model = model;
|
||||
|
||||
/* Allocate can/net device */
|
||||
net = alloc_candev(sizeof(struct mcp251x_priv), TX_ECHO_SKB_MAX);
|
||||
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.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
|
||||
CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;
|
||||
priv->model = spi_get_device_id(spi)->driver_data;
|
||||
priv->net = net;
|
||||
dev_set_drvdata(&spi->dev, priv);
|
||||
|
||||
|
@ -1120,8 +1166,7 @@ static int mcp251x_can_resume(struct spi_device *spi)
|
|||
#define mcp251x_can_resume NULL
|
||||
#endif
|
||||
|
||||
static struct spi_device_id mcp251x_id_table[] = {
|
||||
{ "mcp251x", 0 /* Use pdata.model */ },
|
||||
static const struct spi_device_id mcp251x_id_table[] = {
|
||||
{ "mcp2510", CAN_MCP251X_MCP2510 },
|
||||
{ "mcp2515", CAN_MCP251X_MCP2515 },
|
||||
{ },
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
/**
|
||||
* struct mcp251x_platform_data - MCP251X SPI CAN controller platform data
|
||||
* @oscillator_frequency: - oscillator frequency in Hz
|
||||
* @model: - actual type of chip
|
||||
* @board_specific_setup: - called before probing the chip (power,reset)
|
||||
* @transceiver_enable: - called to power on/off the transceiver
|
||||
* @power_enable: - called to power on/off the mcp *and* the
|
||||
|
@ -25,9 +24,6 @@
|
|||
|
||||
struct mcp251x_platform_data {
|
||||
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 (*transceiver_enable)(int enable);
|
||||
int (*power_enable) (int enable);
|
||||
|
|
Loading…
Reference in New Issue