Merge branch 'for-davem' of git://gitorious.org/linux-can/linux-can-next
Marc Kleine-Budde says: ==================== this pull-request for net-next consists of a series by Alexander Shiyan, he cleans up the mcp251x driver. As the first patch touches arch/arm/mach-pxa, it's acked by Haojian Zhuang. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
d94a0147dc
|
@ -73,9 +73,6 @@ static struct pxa2xx_spi_chip mcp251x_chip_info4 = {
|
||||||
|
|
||||||
static struct mcp251x_platform_data mcp251x_info = {
|
static struct mcp251x_platform_data mcp251x_info = {
|
||||||
.oscillator_frequency = 16E6,
|
.oscillator_frequency = 16E6,
|
||||||
.board_specific_setup = NULL,
|
|
||||||
.power_enable = NULL,
|
|
||||||
.transceiver_enable = NULL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct spi_board_info mcp251x_board_info[] = {
|
static struct spi_board_info mcp251x_board_info[] = {
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
#include <linux/i2c/pca953x.h>
|
#include <linux/i2c/pca953x.h>
|
||||||
#include <linux/apm-emulation.h>
|
#include <linux/apm-emulation.h>
|
||||||
#include <linux/can/platform/mcp251x.h>
|
#include <linux/can/platform/mcp251x.h>
|
||||||
|
#include <linux/regulator/fixed.h>
|
||||||
|
#include <linux/regulator/machine.h>
|
||||||
|
|
||||||
#include <asm/mach-types.h>
|
#include <asm/mach-types.h>
|
||||||
#include <asm/suspend.h>
|
#include <asm/suspend.h>
|
||||||
|
@ -391,33 +393,34 @@ static struct pxa2xx_spi_master pxa2xx_spi_ssp3_master_info = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* CAN bus on SPI */
|
/* CAN bus on SPI */
|
||||||
static int zeus_mcp2515_setup(struct spi_device *sdev)
|
static struct regulator_consumer_supply can_regulator_consumer =
|
||||||
{
|
REGULATOR_SUPPLY("vdd", "spi3.0");
|
||||||
int err;
|
|
||||||
|
|
||||||
err = gpio_request(ZEUS_CAN_SHDN_GPIO, "CAN shutdown");
|
static struct regulator_init_data can_regulator_init_data = {
|
||||||
if (err)
|
.constraints = {
|
||||||
return err;
|
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
|
||||||
|
},
|
||||||
|
.consumer_supplies = &can_regulator_consumer,
|
||||||
|
.num_consumer_supplies = 1,
|
||||||
|
};
|
||||||
|
|
||||||
err = gpio_direction_output(ZEUS_CAN_SHDN_GPIO, 1);
|
static struct fixed_voltage_config can_regulator_pdata = {
|
||||||
if (err) {
|
.supply_name = "CAN_SHDN",
|
||||||
gpio_free(ZEUS_CAN_SHDN_GPIO);
|
.microvolts = 3300000,
|
||||||
return err;
|
.gpio = ZEUS_CAN_SHDN_GPIO,
|
||||||
}
|
.init_data = &can_regulator_init_data,
|
||||||
|
};
|
||||||
|
|
||||||
return 0;
|
static struct platform_device can_regulator_device = {
|
||||||
}
|
.name = "reg-fixed-volage",
|
||||||
|
.id = -1,
|
||||||
static int zeus_mcp2515_transceiver_enable(int enable)
|
.dev = {
|
||||||
{
|
.platform_data = &can_regulator_pdata,
|
||||||
gpio_set_value(ZEUS_CAN_SHDN_GPIO, !enable);
|
},
|
||||||
return 0;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static struct mcp251x_platform_data zeus_mcp2515_pdata = {
|
static struct mcp251x_platform_data zeus_mcp2515_pdata = {
|
||||||
.oscillator_frequency = 16*1000*1000,
|
.oscillator_frequency = 16*1000*1000,
|
||||||
.board_specific_setup = zeus_mcp2515_setup,
|
|
||||||
.power_enable = zeus_mcp2515_transceiver_enable,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct spi_board_info zeus_spi_board_info[] = {
|
static struct spi_board_info zeus_spi_board_info[] = {
|
||||||
|
@ -516,6 +519,7 @@ static struct platform_device *zeus_devices[] __initdata = {
|
||||||
&zeus_leds_device,
|
&zeus_leds_device,
|
||||||
&zeus_pcmcia_device,
|
&zeus_pcmcia_device,
|
||||||
&zeus_max6369_device,
|
&zeus_max6369_device,
|
||||||
|
&can_regulator_device,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* AC'97 */
|
/* AC'97 */
|
||||||
|
|
|
@ -37,9 +37,6 @@
|
||||||
*
|
*
|
||||||
* 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,
|
|
||||||
* .power_enable = mcp251x_power_enable,
|
|
||||||
* .transceiver_enable = NULL,
|
|
||||||
* };
|
* };
|
||||||
*
|
*
|
||||||
* static struct spi_board_info spi_board_info[] = {
|
* static struct spi_board_info spi_board_info[] = {
|
||||||
|
@ -76,6 +73,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
|
|
||||||
/* SPI interface instruction set */
|
/* SPI interface instruction set */
|
||||||
#define INSTRUCTION_WRITE 0x02
|
#define INSTRUCTION_WRITE 0x02
|
||||||
|
@ -264,6 +262,8 @@ struct mcp251x_priv {
|
||||||
#define AFTER_SUSPEND_POWER 4
|
#define AFTER_SUSPEND_POWER 4
|
||||||
#define AFTER_SUSPEND_RESTART 8
|
#define AFTER_SUSPEND_RESTART 8
|
||||||
int restart_tx;
|
int restart_tx;
|
||||||
|
struct regulator *power;
|
||||||
|
struct regulator *transceiver;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MCP251X_IS(_model) \
|
#define MCP251X_IS(_model) \
|
||||||
|
@ -667,16 +667,25 @@ static int mcp251x_hw_probe(struct spi_device *spi)
|
||||||
return (st1 == 0x80 && st2 == 0x07) ? 1 : 0;
|
return (st1 == 0x80 && st2 == 0x07) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mcp251x_power_enable(struct regulator *reg, int enable)
|
||||||
|
{
|
||||||
|
if (IS_ERR(reg))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
return regulator_enable(reg);
|
||||||
|
else
|
||||||
|
return regulator_disable(reg);
|
||||||
|
}
|
||||||
|
|
||||||
static void mcp251x_open_clean(struct net_device *net)
|
static void mcp251x_open_clean(struct net_device *net)
|
||||||
{
|
{
|
||||||
struct mcp251x_priv *priv = netdev_priv(net);
|
struct mcp251x_priv *priv = netdev_priv(net);
|
||||||
struct spi_device *spi = priv->spi;
|
struct spi_device *spi = priv->spi;
|
||||||
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
|
|
||||||
|
|
||||||
free_irq(spi->irq, priv);
|
free_irq(spi->irq, priv);
|
||||||
mcp251x_hw_sleep(spi);
|
mcp251x_hw_sleep(spi);
|
||||||
if (pdata->transceiver_enable)
|
mcp251x_power_enable(priv->transceiver, 0);
|
||||||
pdata->transceiver_enable(0);
|
|
||||||
close_candev(net);
|
close_candev(net);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -684,7 +693,6 @@ static int mcp251x_stop(struct net_device *net)
|
||||||
{
|
{
|
||||||
struct mcp251x_priv *priv = netdev_priv(net);
|
struct mcp251x_priv *priv = netdev_priv(net);
|
||||||
struct spi_device *spi = priv->spi;
|
struct spi_device *spi = priv->spi;
|
||||||
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
|
|
||||||
|
|
||||||
close_candev(net);
|
close_candev(net);
|
||||||
|
|
||||||
|
@ -704,8 +712,7 @@ static int mcp251x_stop(struct net_device *net)
|
||||||
|
|
||||||
mcp251x_hw_sleep(spi);
|
mcp251x_hw_sleep(spi);
|
||||||
|
|
||||||
if (pdata->transceiver_enable)
|
mcp251x_power_enable(priv->transceiver, 0);
|
||||||
pdata->transceiver_enable(0);
|
|
||||||
|
|
||||||
priv->can.state = CAN_STATE_STOPPED;
|
priv->can.state = CAN_STATE_STOPPED;
|
||||||
|
|
||||||
|
@ -928,8 +935,7 @@ static int mcp251x_open(struct net_device *net)
|
||||||
{
|
{
|
||||||
struct mcp251x_priv *priv = netdev_priv(net);
|
struct mcp251x_priv *priv = netdev_priv(net);
|
||||||
struct spi_device *spi = priv->spi;
|
struct spi_device *spi = priv->spi;
|
||||||
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
|
unsigned long flags = IRQF_ONESHOT | IRQF_TRIGGER_FALLING;
|
||||||
unsigned long flags;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = open_candev(net);
|
ret = open_candev(net);
|
||||||
|
@ -939,25 +945,17 @@ static int mcp251x_open(struct net_device *net)
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&priv->mcp_lock);
|
mutex_lock(&priv->mcp_lock);
|
||||||
if (pdata->transceiver_enable)
|
mcp251x_power_enable(priv->transceiver, 1);
|
||||||
pdata->transceiver_enable(1);
|
|
||||||
|
|
||||||
priv->force_quit = 0;
|
priv->force_quit = 0;
|
||||||
priv->tx_skb = NULL;
|
priv->tx_skb = NULL;
|
||||||
priv->tx_len = 0;
|
priv->tx_len = 0;
|
||||||
|
|
||||||
flags = IRQF_ONESHOT;
|
|
||||||
if (pdata->irq_flags)
|
|
||||||
flags |= pdata->irq_flags;
|
|
||||||
else
|
|
||||||
flags |= IRQF_TRIGGER_FALLING;
|
|
||||||
|
|
||||||
ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,
|
ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,
|
||||||
flags, DEVICE_NAME, priv);
|
flags, DEVICE_NAME, priv);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
|
dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
|
||||||
if (pdata->transceiver_enable)
|
mcp251x_power_enable(priv->transceiver, 0);
|
||||||
pdata->transceiver_enable(0);
|
|
||||||
close_candev(net);
|
close_candev(net);
|
||||||
goto open_unlock;
|
goto open_unlock;
|
||||||
}
|
}
|
||||||
|
@ -1026,6 +1024,19 @@ static int mcp251x_can_probe(struct spi_device *spi)
|
||||||
CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;
|
CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;
|
||||||
priv->model = spi_get_device_id(spi)->driver_data;
|
priv->model = spi_get_device_id(spi)->driver_data;
|
||||||
priv->net = net;
|
priv->net = net;
|
||||||
|
|
||||||
|
priv->power = devm_regulator_get(&spi->dev, "vdd");
|
||||||
|
priv->transceiver = devm_regulator_get(&spi->dev, "xceiver");
|
||||||
|
if ((PTR_ERR(priv->power) == -EPROBE_DEFER) ||
|
||||||
|
(PTR_ERR(priv->transceiver) == -EPROBE_DEFER)) {
|
||||||
|
ret = -EPROBE_DEFER;
|
||||||
|
goto error_power;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mcp251x_power_enable(priv->power, 1);
|
||||||
|
if (ret)
|
||||||
|
goto error_power;
|
||||||
|
|
||||||
spi_set_drvdata(spi, priv);
|
spi_set_drvdata(spi, priv);
|
||||||
|
|
||||||
priv->spi = spi;
|
priv->spi = spi;
|
||||||
|
@ -1068,30 +1079,24 @@ static int mcp251x_can_probe(struct spi_device *spi)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdata->power_enable)
|
|
||||||
pdata->power_enable(1);
|
|
||||||
|
|
||||||
/* Call out to platform specific setup */
|
|
||||||
if (pdata->board_specific_setup)
|
|
||||||
pdata->board_specific_setup(spi);
|
|
||||||
|
|
||||||
SET_NETDEV_DEV(net, &spi->dev);
|
SET_NETDEV_DEV(net, &spi->dev);
|
||||||
|
|
||||||
/* Configure the SPI bus */
|
/* Configure the SPI bus */
|
||||||
spi->mode = SPI_MODE_0;
|
spi->mode = spi->mode ? : SPI_MODE_0;
|
||||||
|
if (mcp251x_is_2510(spi))
|
||||||
|
spi->max_speed_hz = spi->max_speed_hz ? : 5 * 1000 * 1000;
|
||||||
|
else
|
||||||
|
spi->max_speed_hz = spi->max_speed_hz ? : 10 * 1000 * 1000;
|
||||||
spi->bits_per_word = 8;
|
spi->bits_per_word = 8;
|
||||||
spi_setup(spi);
|
spi_setup(spi);
|
||||||
|
|
||||||
/* Here is OK to not lock the MCP, no one knows about it yet */
|
/* Here is OK to not lock the MCP, no one knows about it yet */
|
||||||
if (!mcp251x_hw_probe(spi)) {
|
if (!mcp251x_hw_probe(spi)) {
|
||||||
dev_info(&spi->dev, "Probe failed\n");
|
ret = -ENODEV;
|
||||||
goto error_probe;
|
goto error_probe;
|
||||||
}
|
}
|
||||||
mcp251x_hw_sleep(spi);
|
mcp251x_hw_sleep(spi);
|
||||||
|
|
||||||
if (pdata->transceiver_enable)
|
|
||||||
pdata->transceiver_enable(0);
|
|
||||||
|
|
||||||
ret = register_candev(net);
|
ret = register_candev(net);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto error_probe;
|
goto error_probe;
|
||||||
|
@ -1109,13 +1114,13 @@ error_rx_buf:
|
||||||
if (!mcp251x_enable_dma)
|
if (!mcp251x_enable_dma)
|
||||||
kfree(priv->spi_tx_buf);
|
kfree(priv->spi_tx_buf);
|
||||||
error_tx_buf:
|
error_tx_buf:
|
||||||
free_candev(net);
|
|
||||||
if (mcp251x_enable_dma)
|
if (mcp251x_enable_dma)
|
||||||
dma_free_coherent(&spi->dev, PAGE_SIZE,
|
dma_free_coherent(&spi->dev, PAGE_SIZE,
|
||||||
priv->spi_tx_buf, priv->spi_tx_dma);
|
priv->spi_tx_buf, priv->spi_tx_dma);
|
||||||
|
mcp251x_power_enable(priv->power, 0);
|
||||||
|
error_power:
|
||||||
|
free_candev(net);
|
||||||
error_alloc:
|
error_alloc:
|
||||||
if (pdata->power_enable)
|
|
||||||
pdata->power_enable(0);
|
|
||||||
dev_err(&spi->dev, "probe failed\n");
|
dev_err(&spi->dev, "probe failed\n");
|
||||||
error_out:
|
error_out:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1123,12 +1128,10 @@ error_out:
|
||||||
|
|
||||||
static int mcp251x_can_remove(struct spi_device *spi)
|
static int mcp251x_can_remove(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
|
|
||||||
struct mcp251x_priv *priv = spi_get_drvdata(spi);
|
struct mcp251x_priv *priv = spi_get_drvdata(spi);
|
||||||
struct net_device *net = priv->net;
|
struct net_device *net = priv->net;
|
||||||
|
|
||||||
unregister_candev(net);
|
unregister_candev(net);
|
||||||
free_candev(net);
|
|
||||||
|
|
||||||
if (mcp251x_enable_dma) {
|
if (mcp251x_enable_dma) {
|
||||||
dma_free_coherent(&spi->dev, PAGE_SIZE,
|
dma_free_coherent(&spi->dev, PAGE_SIZE,
|
||||||
|
@ -1138,8 +1141,9 @@ static int mcp251x_can_remove(struct spi_device *spi)
|
||||||
kfree(priv->spi_rx_buf);
|
kfree(priv->spi_rx_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdata->power_enable)
|
mcp251x_power_enable(priv->power, 0);
|
||||||
pdata->power_enable(0);
|
|
||||||
|
free_candev(net);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1149,7 +1153,6 @@ static int mcp251x_can_remove(struct spi_device *spi)
|
||||||
static int mcp251x_can_suspend(struct device *dev)
|
static int mcp251x_can_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct spi_device *spi = to_spi_device(dev);
|
struct spi_device *spi = to_spi_device(dev);
|
||||||
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
|
|
||||||
struct mcp251x_priv *priv = spi_get_drvdata(spi);
|
struct mcp251x_priv *priv = spi_get_drvdata(spi);
|
||||||
struct net_device *net = priv->net;
|
struct net_device *net = priv->net;
|
||||||
|
|
||||||
|
@ -1163,15 +1166,14 @@ static int mcp251x_can_suspend(struct device *dev)
|
||||||
netif_device_detach(net);
|
netif_device_detach(net);
|
||||||
|
|
||||||
mcp251x_hw_sleep(spi);
|
mcp251x_hw_sleep(spi);
|
||||||
if (pdata->transceiver_enable)
|
mcp251x_power_enable(priv->transceiver, 0);
|
||||||
pdata->transceiver_enable(0);
|
|
||||||
priv->after_suspend = AFTER_SUSPEND_UP;
|
priv->after_suspend = AFTER_SUSPEND_UP;
|
||||||
} else {
|
} else {
|
||||||
priv->after_suspend = AFTER_SUSPEND_DOWN;
|
priv->after_suspend = AFTER_SUSPEND_DOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdata->power_enable) {
|
if (!IS_ERR(priv->power)) {
|
||||||
pdata->power_enable(0);
|
regulator_disable(priv->power);
|
||||||
priv->after_suspend |= AFTER_SUSPEND_POWER;
|
priv->after_suspend |= AFTER_SUSPEND_POWER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1181,16 +1183,14 @@ static int mcp251x_can_suspend(struct device *dev)
|
||||||
static int mcp251x_can_resume(struct device *dev)
|
static int mcp251x_can_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct spi_device *spi = to_spi_device(dev);
|
struct spi_device *spi = to_spi_device(dev);
|
||||||
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
|
|
||||||
struct mcp251x_priv *priv = spi_get_drvdata(spi);
|
struct mcp251x_priv *priv = spi_get_drvdata(spi);
|
||||||
|
|
||||||
if (priv->after_suspend & AFTER_SUSPEND_POWER) {
|
if (priv->after_suspend & AFTER_SUSPEND_POWER) {
|
||||||
pdata->power_enable(1);
|
mcp251x_power_enable(priv->power, 1);
|
||||||
queue_work(priv->wq, &priv->restart_work);
|
queue_work(priv->wq, &priv->restart_work);
|
||||||
} else {
|
} else {
|
||||||
if (priv->after_suspend & AFTER_SUSPEND_UP) {
|
if (priv->after_suspend & AFTER_SUSPEND_UP) {
|
||||||
if (pdata->transceiver_enable)
|
mcp251x_power_enable(priv->transceiver, 1);
|
||||||
pdata->transceiver_enable(1);
|
|
||||||
queue_work(priv->wq, &priv->restart_work);
|
queue_work(priv->wq, &priv->restart_work);
|
||||||
} else {
|
} else {
|
||||||
priv->after_suspend = 0;
|
priv->after_suspend = 0;
|
||||||
|
|
|
@ -9,26 +9,13 @@
|
||||||
|
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* 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
|
||||||
* @irq_flags: - IRQF configuration flags
|
|
||||||
* @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
|
|
||||||
* transceiver
|
|
||||||
*
|
|
||||||
* Please note that you should define power_enable or transceiver_enable or
|
|
||||||
* none of them. Defining both of them is no use.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct mcp251x_platform_data {
|
struct mcp251x_platform_data {
|
||||||
unsigned long oscillator_frequency;
|
unsigned long oscillator_frequency;
|
||||||
unsigned long irq_flags;
|
|
||||||
int (*board_specific_setup)(struct spi_device *spi);
|
|
||||||
int (*transceiver_enable)(int enable);
|
|
||||||
int (*power_enable) (int enable);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __CAN_PLATFORM_MCP251X_H__ */
|
#endif /* __CAN_PLATFORM_MCP251X_H__ */
|
||||||
|
|
Loading…
Reference in a new issue