Merge branch 'broonie/spi-next' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/misc.git

Minor features and bug fixes for PXA, OMAP and GPIO deivce drivers and a
cosmetic change to the bitbang driver.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
This commit is contained in:
Grant Likely 2013-02-05 12:30:13 +00:00
Родитель 766ed70447 d560040f7d
Коммит f305a0a8d7
12 изменённых файлов: 148 добавлений и 376 удалений

Просмотреть файл

@ -7178,6 +7178,7 @@ F: drivers/clk/spear/
SPI SUBSYSTEM SPI SUBSYSTEM
M: Grant Likely <grant.likely@secretlab.ca> M: Grant Likely <grant.likely@secretlab.ca>
M: Mark Brown <broonie@opensource.wolfsonmicro.com>
L: spi-devel-general@lists.sourceforge.net L: spi-devel-general@lists.sourceforge.net
Q: http://patchwork.kernel.org/project/spi-devel-general/list/ Q: http://patchwork.kernel.org/project/spi-devel-general/list/
T: git git://git.secretlab.ca/git/linux-2.6.git T: git git://git.secretlab.ca/git/linux-2.6.git

Просмотреть файл

@ -299,7 +299,7 @@ config SPI_PPC4xx
config SPI_PXA2XX config SPI_PXA2XX
tristate "PXA2xx SSP SPI master" tristate "PXA2xx SSP SPI master"
depends on (ARCH_PXA || (X86_32 && PCI)) && EXPERIMENTAL depends on ARCH_PXA || PCI
select PXA_SSP if ARCH_PXA select PXA_SSP if ARCH_PXA
help help
This enables using a PXA2xx or Sodaville SSP port as a SPI master This enables using a PXA2xx or Sodaville SSP port as a SPI master
@ -307,7 +307,7 @@ config SPI_PXA2XX
additional documentation can be found a Documentation/spi/pxa2xx. additional documentation can be found a Documentation/spi/pxa2xx.
config SPI_PXA2XX_PCI config SPI_PXA2XX_PCI
def_bool SPI_PXA2XX && X86_32 && PCI def_tristate SPI_PXA2XX && PCI
config SPI_RSPI config SPI_RSPI
tristate "Renesas RSPI controller" tristate "Renesas RSPI controller"

Просмотреть файл

@ -427,40 +427,41 @@ EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
*/ */
int spi_bitbang_start(struct spi_bitbang *bitbang) int spi_bitbang_start(struct spi_bitbang *bitbang)
{ {
int status; struct spi_master *master = bitbang->master;
int status;
if (!bitbang->master || !bitbang->chipselect) if (!master || !bitbang->chipselect)
return -EINVAL; return -EINVAL;
INIT_WORK(&bitbang->work, bitbang_work); INIT_WORK(&bitbang->work, bitbang_work);
spin_lock_init(&bitbang->lock); spin_lock_init(&bitbang->lock);
INIT_LIST_HEAD(&bitbang->queue); INIT_LIST_HEAD(&bitbang->queue);
if (!bitbang->master->mode_bits) if (!master->mode_bits)
bitbang->master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags; master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
if (!bitbang->master->transfer) if (!master->transfer)
bitbang->master->transfer = spi_bitbang_transfer; master->transfer = spi_bitbang_transfer;
if (!bitbang->txrx_bufs) { if (!bitbang->txrx_bufs) {
bitbang->use_dma = 0; bitbang->use_dma = 0;
bitbang->txrx_bufs = spi_bitbang_bufs; bitbang->txrx_bufs = spi_bitbang_bufs;
if (!bitbang->master->setup) { if (!master->setup) {
if (!bitbang->setup_transfer) if (!bitbang->setup_transfer)
bitbang->setup_transfer = bitbang->setup_transfer =
spi_bitbang_setup_transfer; spi_bitbang_setup_transfer;
bitbang->master->setup = spi_bitbang_setup; master->setup = spi_bitbang_setup;
bitbang->master->cleanup = spi_bitbang_cleanup; master->cleanup = spi_bitbang_cleanup;
} }
} else if (!bitbang->master->setup) } else if (!master->setup)
return -EINVAL; return -EINVAL;
if (bitbang->master->transfer == spi_bitbang_transfer && if (master->transfer == spi_bitbang_transfer &&
!bitbang->setup_transfer) !bitbang->setup_transfer)
return -EINVAL; return -EINVAL;
/* this task is the only thing to touch the SPI bits */ /* this task is the only thing to touch the SPI bits */
bitbang->busy = 0; bitbang->busy = 0;
bitbang->workqueue = create_singlethread_workqueue( bitbang->workqueue = create_singlethread_workqueue(
dev_name(bitbang->master->dev.parent)); dev_name(master->dev.parent));
if (bitbang->workqueue == NULL) { if (bitbang->workqueue == NULL) {
status = -EBUSY; status = -EBUSY;
goto err1; goto err1;
@ -469,7 +470,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
/* driver may get busy before register() returns, especially /* driver may get busy before register() returns, especially
* if someone registered boardinfo for devices * if someone registered boardinfo for devices
*/ */
status = spi_register_master(bitbang->master); status = spi_register_master(master);
if (status < 0) if (status < 0)
goto err2; goto err2;

Просмотреть файл

@ -365,9 +365,26 @@ static int spi_gpio_probe_dt(struct platform_device *pdev)
if (!pdata) if (!pdata)
return -ENOMEM; return -ENOMEM;
pdata->sck = of_get_named_gpio(np, "gpio-sck", 0); ret = of_get_named_gpio(np, "gpio-sck", 0);
pdata->miso = of_get_named_gpio(np, "gpio-miso", 0); if (ret < 0) {
pdata->mosi = of_get_named_gpio(np, "gpio-mosi", 0); dev_err(&pdev->dev, "gpio-sck property not found\n");
goto error_free;
}
pdata->sck = ret;
ret = of_get_named_gpio(np, "gpio-miso", 0);
if (ret < 0) {
dev_info(&pdev->dev, "gpio-miso property not found, switching to no-rx mode\n");
pdata->miso = SPI_GPIO_NO_MISO;
} else
pdata->miso = ret;
ret = of_get_named_gpio(np, "gpio-mosi", 0);
if (ret < 0) {
dev_info(&pdev->dev, "gpio-mosi property not found, switching to no-tx mode\n");
pdata->mosi = SPI_GPIO_NO_MOSI;
} else
pdata->mosi = ret;
ret = of_property_read_u32(np, "num-chipselects", &tmp); ret = of_property_read_u32(np, "num-chipselects", &tmp);
if (ret < 0) { if (ret < 0) {

Просмотреть файл

@ -927,6 +927,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
struct spi_device *spi; struct spi_device *spi;
struct spi_transfer *t = NULL; struct spi_transfer *t = NULL;
struct spi_master *master;
int cs_active = 0; int cs_active = 0;
struct omap2_mcspi_cs *cs; struct omap2_mcspi_cs *cs;
struct omap2_mcspi_device_config *cd; struct omap2_mcspi_device_config *cd;
@ -935,6 +936,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
u32 chconf; u32 chconf;
spi = m->spi; spi = m->spi;
master = spi->master;
cs = spi->controller_state; cs = spi->controller_state;
cd = spi->controller_data; cd = spi->controller_data;
@ -952,6 +954,14 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
if (!t->speed_hz && !t->bits_per_word) if (!t->speed_hz && !t->bits_per_word)
par_override = 0; par_override = 0;
} }
if (cd && cd->cs_per_word) {
chconf = mcspi->ctx.modulctrl;
chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
mcspi->ctx.modulctrl =
mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
}
if (!cs_active) { if (!cs_active) {
omap2_mcspi_force_cs(spi, 1); omap2_mcspi_force_cs(spi, 1);
@ -1013,6 +1023,14 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
if (cs_active) if (cs_active)
omap2_mcspi_force_cs(spi, 0); omap2_mcspi_force_cs(spi, 0);
if (cd && cd->cs_per_word) {
chconf = mcspi->ctx.modulctrl;
chconf |= OMAP2_MCSPI_MODULCTRL_SINGLE;
mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
mcspi->ctx.modulctrl =
mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
}
omap2_mcspi_set_enable(spi, 0); omap2_mcspi_set_enable(spi, 0);
m->status = status; m->status = status;
@ -1020,7 +1038,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
} }
static int omap2_mcspi_transfer_one_message(struct spi_master *master, static int omap2_mcspi_transfer_one_message(struct spi_master *master,
struct spi_message *m) struct spi_message *m)
{ {
struct omap2_mcspi *mcspi; struct omap2_mcspi *mcspi;
struct spi_transfer *t; struct spi_transfer *t;
@ -1041,7 +1059,7 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
|| (len && !(rx_buf || tx_buf)) || (len && !(rx_buf || tx_buf))
|| (t->bits_per_word && || (t->bits_per_word &&
( t->bits_per_word < 4 ( t->bits_per_word < 4
|| t->bits_per_word > 32))) { || t->bits_per_word > 32))) {
dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n", dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
t->speed_hz, t->speed_hz,
len, len,
@ -1052,8 +1070,8 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
} }
if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) { if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) {
dev_dbg(mcspi->dev, "speed_hz %d below minimum %d Hz\n", dev_dbg(mcspi->dev, "speed_hz %d below minimum %d Hz\n",
t->speed_hz, t->speed_hz,
OMAP2_MCSPI_MAX_FREQ >> 15); OMAP2_MCSPI_MAX_FREQ >> 15);
return -EINVAL; return -EINVAL;
} }
@ -1099,7 +1117,7 @@ static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
return ret; return ret;
mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE,
OMAP2_MCSPI_WAKEUPENABLE_WKEN); OMAP2_MCSPI_WAKEUPENABLE_WKEN);
ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN; ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
omap2_mcspi_set_master_mode(master); omap2_mcspi_set_master_mode(master);
@ -1228,7 +1246,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
sprintf(dma_ch_name, "rx%d", i); sprintf(dma_ch_name, "rx%d", i);
dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
dma_ch_name); dma_ch_name);
if (!dma_res) { if (!dma_res) {
dev_dbg(&pdev->dev, "cannot get DMA RX channel\n"); dev_dbg(&pdev->dev, "cannot get DMA RX channel\n");
status = -ENODEV; status = -ENODEV;
@ -1238,7 +1256,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start; mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start;
sprintf(dma_ch_name, "tx%d", i); sprintf(dma_ch_name, "tx%d", i);
dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
dma_ch_name); dma_ch_name);
if (!dma_res) { if (!dma_res) {
dev_dbg(&pdev->dev, "cannot get DMA TX channel\n"); dev_dbg(&pdev->dev, "cannot get DMA TX channel\n");
status = -ENODEV; status = -ENODEV;
@ -1254,7 +1272,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
pinctrl = devm_pinctrl_get_select_default(&pdev->dev); pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl)) if (IS_ERR(pinctrl))
dev_warn(&pdev->dev, dev_warn(&pdev->dev,
"pins are not configured from the driver\n"); "pins are not configured from the driver\n");
pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);

Просмотреть файл

@ -8,147 +8,58 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/spi/pxa2xx_spi.h> #include <linux/spi/pxa2xx_spi.h>
struct ce4100_info {
struct ssp_device ssp;
struct platform_device *spi_pdev;
};
static DEFINE_MUTEX(ssp_lock);
static LIST_HEAD(ssp_list);
struct ssp_device *pxa_ssp_request(int port, const char *label)
{
struct ssp_device *ssp = NULL;
mutex_lock(&ssp_lock);
list_for_each_entry(ssp, &ssp_list, node) {
if (ssp->port_id == port && ssp->use_count == 0) {
ssp->use_count++;
ssp->label = label;
break;
}
}
mutex_unlock(&ssp_lock);
if (&ssp->node == &ssp_list)
return NULL;
return ssp;
}
EXPORT_SYMBOL_GPL(pxa_ssp_request);
void pxa_ssp_free(struct ssp_device *ssp)
{
mutex_lock(&ssp_lock);
if (ssp->use_count) {
ssp->use_count--;
ssp->label = NULL;
} else
dev_err(&ssp->pdev->dev, "device already free\n");
mutex_unlock(&ssp_lock);
}
EXPORT_SYMBOL_GPL(pxa_ssp_free);
static int ce4100_spi_probe(struct pci_dev *dev, static int ce4100_spi_probe(struct pci_dev *dev,
const struct pci_device_id *ent) const struct pci_device_id *ent)
{ {
struct platform_device_info pi;
int ret; int ret;
resource_size_t phys_beg;
resource_size_t phys_len;
struct ce4100_info *spi_info;
struct platform_device *pdev; struct platform_device *pdev;
struct pxa2xx_spi_master spi_pdata; struct pxa2xx_spi_master spi_pdata;
struct ssp_device *ssp; struct ssp_device *ssp;
ret = pci_enable_device(dev); ret = pcim_enable_device(dev);
if (ret) if (ret)
return ret; return ret;
phys_beg = pci_resource_start(dev, 0); ret = pcim_iomap_regions(dev, 1 << 0, "PXA2xx SPI");
phys_len = pci_resource_len(dev, 0); if (!ret)
if (!request_mem_region(phys_beg, phys_len,
"CE4100 SPI")) {
dev_err(&dev->dev, "Can't request register space.\n");
ret = -EBUSY;
return ret; return ret;
}
pdev = platform_device_alloc("pxa2xx-spi", dev->devfn);
spi_info = kzalloc(sizeof(*spi_info), GFP_KERNEL);
if (!pdev || !spi_info ) {
ret = -ENOMEM;
goto err_nomem;
}
memset(&spi_pdata, 0, sizeof(spi_pdata)); memset(&spi_pdata, 0, sizeof(spi_pdata));
spi_pdata.num_chipselect = dev->devfn; spi_pdata.num_chipselect = dev->devfn;
ret = platform_device_add_data(pdev, &spi_pdata, sizeof(spi_pdata)); ssp = &spi_pdata.ssp;
if (ret)
goto err_nomem;
pdev->dev.parent = &dev->dev;
pdev->dev.of_node = dev->dev.of_node;
ssp = &spi_info->ssp;
ssp->phys_base = pci_resource_start(dev, 0); ssp->phys_base = pci_resource_start(dev, 0);
ssp->mmio_base = ioremap(phys_beg, phys_len); ssp->mmio_base = pcim_iomap_table(dev)[0];
if (!ssp->mmio_base) { if (!ssp->mmio_base) {
dev_err(&pdev->dev, "failed to ioremap() registers\n"); dev_err(&dev->dev, "failed to ioremap() registers\n");
ret = -EIO; return -EIO;
goto err_nomem;
} }
ssp->irq = dev->irq; ssp->irq = dev->irq;
ssp->port_id = pdev->id; ssp->port_id = dev->devfn;
ssp->type = PXA25x_SSP; ssp->type = PXA25x_SSP;
mutex_lock(&ssp_lock); memset(&pi, 0, sizeof(pi));
list_add(&ssp->node, &ssp_list); pi.parent = &dev->dev;
mutex_unlock(&ssp_lock); pi.name = "pxa2xx-spi";
pi.id = ssp->port_id;
pi.data = &spi_pdata;
pi.size_data = sizeof(spi_pdata);
pci_set_drvdata(dev, spi_info); pdev = platform_device_register_full(&pi);
if (!pdev)
return -ENOMEM;
ret = platform_device_add(pdev); pci_set_drvdata(dev, pdev);
if (ret)
goto err_dev_add;
return ret; return 0;
err_dev_add:
pci_set_drvdata(dev, NULL);
mutex_lock(&ssp_lock);
list_del(&ssp->node);
mutex_unlock(&ssp_lock);
iounmap(ssp->mmio_base);
err_nomem:
release_mem_region(phys_beg, phys_len);
platform_device_put(pdev);
kfree(spi_info);
return ret;
} }
static void ce4100_spi_remove(struct pci_dev *dev) static void ce4100_spi_remove(struct pci_dev *dev)
{ {
struct ce4100_info *spi_info; struct platform_device *pdev = pci_get_drvdata(dev);
struct ssp_device *ssp;
spi_info = pci_get_drvdata(dev); platform_device_unregister(pdev);
ssp = &spi_info->ssp;
platform_device_unregister(spi_info->spi_pdev);
iounmap(ssp->mmio_base);
release_mem_region(pci_resource_start(dev, 0),
pci_resource_len(dev, 0));
mutex_lock(&ssp_lock);
list_del(&ssp->node);
mutex_unlock(&ssp_lock);
pci_set_drvdata(dev, NULL);
pci_disable_device(dev);
kfree(spi_info);
} }
static DEFINE_PCI_DEVICE_TABLE(ce4100_spi_devices) = { static DEFINE_PCI_DEVICE_TABLE(ce4100_spi_devices) = {

Просмотреть файл

@ -30,6 +30,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/clk.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
@ -47,7 +48,7 @@ MODULE_ALIAS("platform:pxa2xx-spi");
#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR) #define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
#define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK) #define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK)
#define IS_DMA_ALIGNED(x) ((((u32)(x)) & 0x07) == 0) #define IS_DMA_ALIGNED(x) IS_ALIGNED((unsigned long)(x), DMA_ALIGNMENT)
#define MAX_DMA_LEN 8191 #define MAX_DMA_LEN 8191
#define DMA_ALIGNMENT 8 #define DMA_ALIGNMENT 8
@ -85,9 +86,6 @@ DEFINE_SSP_REG(SSPSP, 0x2c)
#define DONE_STATE ((void*)2) #define DONE_STATE ((void*)2)
#define ERROR_STATE ((void*)-1) #define ERROR_STATE ((void*)-1)
#define QUEUE_RUNNING 0
#define QUEUE_STOPPED 1
struct driver_data { struct driver_data {
/* Driver model hookup */ /* Driver model hookup */
struct platform_device *pdev; struct platform_device *pdev;
@ -117,13 +115,8 @@ struct driver_data {
u32 clear_sr; u32 clear_sr;
u32 mask_sr; u32 mask_sr;
/* Driver message queue */ /* Maximun clock rate */
struct workqueue_struct *workqueue; unsigned long max_clk_rate;
struct work_struct pump_messages;
spinlock_t lock;
struct list_head queue;
int busy;
int run;
/* Message Transfer pump */ /* Message Transfer pump */
struct tasklet_struct pump_transfers; struct tasklet_struct pump_transfers;
@ -173,8 +166,6 @@ struct chip_data {
void (*cs_control)(u32 command); void (*cs_control)(u32 command);
}; };
static void pump_messages(struct work_struct *work);
static void cs_assert(struct driver_data *drv_data) static void cs_assert(struct driver_data *drv_data)
{ {
struct chip_data *chip = drv_data->cur_chip; struct chip_data *chip = drv_data->cur_chip;
@ -444,15 +435,11 @@ static void unmap_dma_buffers(struct driver_data *drv_data)
static void giveback(struct driver_data *drv_data) static void giveback(struct driver_data *drv_data)
{ {
struct spi_transfer* last_transfer; struct spi_transfer* last_transfer;
unsigned long flags;
struct spi_message *msg; struct spi_message *msg;
spin_lock_irqsave(&drv_data->lock, flags);
msg = drv_data->cur_msg; msg = drv_data->cur_msg;
drv_data->cur_msg = NULL; drv_data->cur_msg = NULL;
drv_data->cur_transfer = NULL; drv_data->cur_transfer = NULL;
queue_work(drv_data->workqueue, &drv_data->pump_messages);
spin_unlock_irqrestore(&drv_data->lock, flags);
last_transfer = list_entry(msg->transfers.prev, last_transfer = list_entry(msg->transfers.prev,
struct spi_transfer, struct spi_transfer,
@ -481,13 +468,7 @@ static void giveback(struct driver_data *drv_data)
*/ */
/* get a pointer to the next message, if any */ /* get a pointer to the next message, if any */
spin_lock_irqsave(&drv_data->lock, flags); next_msg = spi_get_next_queued_message(drv_data->master);
if (list_empty(&drv_data->queue))
next_msg = NULL;
else
next_msg = list_entry(drv_data->queue.next,
struct spi_message, queue);
spin_unlock_irqrestore(&drv_data->lock, flags);
/* see if the next and current messages point /* see if the next and current messages point
* to the same chip * to the same chip
@ -498,10 +479,7 @@ static void giveback(struct driver_data *drv_data)
cs_deassert(drv_data); cs_deassert(drv_data);
} }
msg->state = NULL; spi_finalize_current_message(drv_data->master);
if (msg->complete)
msg->complete(msg->context);
drv_data->cur_chip = NULL; drv_data->cur_chip = NULL;
} }
@ -917,9 +895,12 @@ static int set_dma_burst_and_threshold(struct chip_data *chip,
return retval; return retval;
} }
static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate) static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
{ {
unsigned long ssp_clk = clk_get_rate(ssp->clk); unsigned long ssp_clk = drv_data->max_clk_rate;
const struct ssp_device *ssp = drv_data->ssp;
rate = min_t(int, ssp_clk, rate);
if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP) if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8; return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
@ -934,7 +915,6 @@ static void pump_transfers(unsigned long data)
struct spi_transfer *transfer = NULL; struct spi_transfer *transfer = NULL;
struct spi_transfer *previous = NULL; struct spi_transfer *previous = NULL;
struct chip_data *chip = NULL; struct chip_data *chip = NULL;
struct ssp_device *ssp = drv_data->ssp;
void __iomem *reg = drv_data->ioaddr; void __iomem *reg = drv_data->ioaddr;
u32 clk_div = 0; u32 clk_div = 0;
u8 bits = 0; u8 bits = 0;
@ -1031,7 +1011,7 @@ static void pump_transfers(unsigned long data)
if (transfer->bits_per_word) if (transfer->bits_per_word)
bits = transfer->bits_per_word; bits = transfer->bits_per_word;
clk_div = ssp_get_clk_div(ssp, speed); clk_div = ssp_get_clk_div(drv_data, speed);
if (bits <= 8) { if (bits <= 8) {
drv_data->n_bytes = 1; drv_data->n_bytes = 1;
@ -1176,31 +1156,12 @@ static void pump_transfers(unsigned long data)
write_SSCR1(cr1, reg); write_SSCR1(cr1, reg);
} }
static void pump_messages(struct work_struct *work) static int pxa2xx_spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{ {
struct driver_data *drv_data = struct driver_data *drv_data = spi_master_get_devdata(master);
container_of(work, struct driver_data, pump_messages);
unsigned long flags;
/* Lock queue and check for queue work */
spin_lock_irqsave(&drv_data->lock, flags);
if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
drv_data->busy = 0;
spin_unlock_irqrestore(&drv_data->lock, flags);
return;
}
/* Make sure we are not already running a message */
if (drv_data->cur_msg) {
spin_unlock_irqrestore(&drv_data->lock, flags);
return;
}
/* Extract head of queue */
drv_data->cur_msg = list_entry(drv_data->queue.next,
struct spi_message, queue);
list_del_init(&drv_data->cur_msg->queue);
drv_data->cur_msg = msg;
/* Initial message state*/ /* Initial message state*/
drv_data->cur_msg->state = START_STATE; drv_data->cur_msg->state = START_STATE;
drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next, drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
@ -1213,34 +1174,6 @@ static void pump_messages(struct work_struct *work)
/* Mark as busy and launch transfers */ /* Mark as busy and launch transfers */
tasklet_schedule(&drv_data->pump_transfers); tasklet_schedule(&drv_data->pump_transfers);
drv_data->busy = 1;
spin_unlock_irqrestore(&drv_data->lock, flags);
}
static int transfer(struct spi_device *spi, struct spi_message *msg)
{
struct driver_data *drv_data = spi_master_get_devdata(spi->master);
unsigned long flags;
spin_lock_irqsave(&drv_data->lock, flags);
if (drv_data->run == QUEUE_STOPPED) {
spin_unlock_irqrestore(&drv_data->lock, flags);
return -ESHUTDOWN;
}
msg->actual_length = 0;
msg->status = -EINPROGRESS;
msg->state = START_STATE;
list_add_tail(&msg->queue, &drv_data->queue);
if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
queue_work(drv_data->workqueue, &drv_data->pump_messages);
spin_unlock_irqrestore(&drv_data->lock, flags);
return 0; return 0;
} }
@ -1287,7 +1220,6 @@ static int setup(struct spi_device *spi)
struct pxa2xx_spi_chip *chip_info = NULL; struct pxa2xx_spi_chip *chip_info = NULL;
struct chip_data *chip; struct chip_data *chip;
struct driver_data *drv_data = spi_master_get_devdata(spi->master); struct driver_data *drv_data = spi_master_get_devdata(spi->master);
struct ssp_device *ssp = drv_data->ssp;
unsigned int clk_div; unsigned int clk_div;
uint tx_thres = TX_THRESH_DFLT; uint tx_thres = TX_THRESH_DFLT;
uint rx_thres = RX_THRESH_DFLT; uint rx_thres = RX_THRESH_DFLT;
@ -1369,7 +1301,7 @@ static int setup(struct spi_device *spi)
} }
} }
clk_div = ssp_get_clk_div(ssp, spi->max_speed_hz); clk_div = ssp_get_clk_div(drv_data, spi->max_speed_hz);
chip->speed_hz = spi->max_speed_hz; chip->speed_hz = spi->max_speed_hz;
chip->cr0 = clk_div chip->cr0 = clk_div
@ -1385,12 +1317,12 @@ static int setup(struct spi_device *spi)
/* NOTE: PXA25x_SSP _could_ use external clocking ... */ /* NOTE: PXA25x_SSP _could_ use external clocking ... */
if (!pxa25x_ssp_comp(drv_data)) if (!pxa25x_ssp_comp(drv_data))
dev_dbg(&spi->dev, "%ld Hz actual, %s\n", dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
clk_get_rate(ssp->clk) drv_data->max_clk_rate
/ (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)), / (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)),
chip->enable_dma ? "DMA" : "PIO"); chip->enable_dma ? "DMA" : "PIO");
else else
dev_dbg(&spi->dev, "%ld Hz actual, %s\n", dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
clk_get_rate(ssp->clk) / 2 drv_data->max_clk_rate / 2
/ (1 + ((chip->cr0 & SSCR0_SCR(0x0ff)) >> 8)), / (1 + ((chip->cr0 & SSCR0_SCR(0x0ff)) >> 8)),
chip->enable_dma ? "DMA" : "PIO"); chip->enable_dma ? "DMA" : "PIO");
@ -1438,94 +1370,6 @@ static void cleanup(struct spi_device *spi)
kfree(chip); kfree(chip);
} }
static int init_queue(struct driver_data *drv_data)
{
INIT_LIST_HEAD(&drv_data->queue);
spin_lock_init(&drv_data->lock);
drv_data->run = QUEUE_STOPPED;
drv_data->busy = 0;
tasklet_init(&drv_data->pump_transfers,
pump_transfers, (unsigned long)drv_data);
INIT_WORK(&drv_data->pump_messages, pump_messages);
drv_data->workqueue = create_singlethread_workqueue(
dev_name(drv_data->master->dev.parent));
if (drv_data->workqueue == NULL)
return -EBUSY;
return 0;
}
static int start_queue(struct driver_data *drv_data)
{
unsigned long flags;
spin_lock_irqsave(&drv_data->lock, flags);
if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
spin_unlock_irqrestore(&drv_data->lock, flags);
return -EBUSY;
}
drv_data->run = QUEUE_RUNNING;
drv_data->cur_msg = NULL;
drv_data->cur_transfer = NULL;
drv_data->cur_chip = NULL;
spin_unlock_irqrestore(&drv_data->lock, flags);
queue_work(drv_data->workqueue, &drv_data->pump_messages);
return 0;
}
static int stop_queue(struct driver_data *drv_data)
{
unsigned long flags;
unsigned limit = 500;
int status = 0;
spin_lock_irqsave(&drv_data->lock, flags);
/* This is a bit lame, but is optimized for the common execution path.
* A wait_queue on the drv_data->busy could be used, but then the common
* execution path (pump_messages) would be required to call wake_up or
* friends on every SPI message. Do this instead */
drv_data->run = QUEUE_STOPPED;
while ((!list_empty(&drv_data->queue) || drv_data->busy) && limit--) {
spin_unlock_irqrestore(&drv_data->lock, flags);
msleep(10);
spin_lock_irqsave(&drv_data->lock, flags);
}
if (!list_empty(&drv_data->queue) || drv_data->busy)
status = -EBUSY;
spin_unlock_irqrestore(&drv_data->lock, flags);
return status;
}
static int destroy_queue(struct driver_data *drv_data)
{
int status;
status = stop_queue(drv_data);
/* we are unloading the module or failing to load (only two calls
* to this routine), and neither call can handle a return value.
* However, destroy_workqueue calls flush_workqueue, and that will
* block until all work is done. If the reason that stop_queue
* timed out is that the work will never finish, then it does no
* good to call destroy_workqueue, so return anyway. */
if (status != 0)
return status;
destroy_workqueue(drv_data->workqueue);
return 0;
}
static int pxa2xx_spi_probe(struct platform_device *pdev) static int pxa2xx_spi_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
@ -1535,11 +1379,18 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
struct ssp_device *ssp; struct ssp_device *ssp;
int status; int status;
platform_info = dev->platform_data; platform_info = dev_get_platdata(dev);
if (!platform_info) {
dev_err(&pdev->dev, "missing platform data\n");
return -ENODEV;
}
ssp = pxa_ssp_request(pdev->id, pdev->name); ssp = pxa_ssp_request(pdev->id, pdev->name);
if (ssp == NULL) { if (!ssp)
dev_err(&pdev->dev, "failed to request SSP%d\n", pdev->id); ssp = &platform_info->ssp;
if (!ssp->mmio_base) {
dev_err(&pdev->dev, "failed to get ssp\n");
return -ENODEV; return -ENODEV;
} }
@ -1561,16 +1412,15 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */ /* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->bus_num = pdev->id; master->bus_num = ssp->port_id;
master->num_chipselect = platform_info->num_chipselect; master->num_chipselect = platform_info->num_chipselect;
master->dma_alignment = DMA_ALIGNMENT; master->dma_alignment = DMA_ALIGNMENT;
master->cleanup = cleanup; master->cleanup = cleanup;
master->setup = setup; master->setup = setup;
master->transfer = transfer; master->transfer_one_message = pxa2xx_spi_transfer_one_message;
drv_data->ssp_type = ssp->type; drv_data->ssp_type = ssp->type;
drv_data->null_dma_buf = (u32 *)ALIGN((u32)(drv_data + drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT);
sizeof(struct driver_data)), 8);
drv_data->ioaddr = ssp->mmio_base; drv_data->ioaddr = ssp->mmio_base;
drv_data->ssdr_physical = ssp->phys_base + SSDR; drv_data->ssdr_physical = ssp->phys_base + SSDR;
@ -1625,7 +1475,9 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
} }
/* Enable SOC clock */ /* Enable SOC clock */
clk_enable(ssp->clk); clk_prepare_enable(ssp->clk);
drv_data->max_clk_rate = clk_get_rate(ssp->clk);
/* Load default SSP configuration */ /* Load default SSP configuration */
write_SSCR0(0, drv_data->ioaddr); write_SSCR0(0, drv_data->ioaddr);
@ -1640,33 +1492,21 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
write_SSTO(0, drv_data->ioaddr); write_SSTO(0, drv_data->ioaddr);
write_SSPSP(0, drv_data->ioaddr); write_SSPSP(0, drv_data->ioaddr);
/* Initial and start queue */ tasklet_init(&drv_data->pump_transfers, pump_transfers,
status = init_queue(drv_data); (unsigned long)drv_data);
if (status != 0) {
dev_err(&pdev->dev, "problem initializing queue\n");
goto out_error_clock_enabled;
}
status = start_queue(drv_data);
if (status != 0) {
dev_err(&pdev->dev, "problem starting queue\n");
goto out_error_clock_enabled;
}
/* Register with the SPI framework */ /* Register with the SPI framework */
platform_set_drvdata(pdev, drv_data); platform_set_drvdata(pdev, drv_data);
status = spi_register_master(master); status = spi_register_master(master);
if (status != 0) { if (status != 0) {
dev_err(&pdev->dev, "problem registering spi master\n"); dev_err(&pdev->dev, "problem registering spi master\n");
goto out_error_queue_alloc; goto out_error_clock_enabled;
} }
return status; return status;
out_error_queue_alloc:
destroy_queue(drv_data);
out_error_clock_enabled: out_error_clock_enabled:
clk_disable(ssp->clk); clk_disable_unprepare(ssp->clk);
out_error_dma_alloc: out_error_dma_alloc:
if (drv_data->tx_channel != -1) if (drv_data->tx_channel != -1)
@ -1687,29 +1527,14 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
{ {
struct driver_data *drv_data = platform_get_drvdata(pdev); struct driver_data *drv_data = platform_get_drvdata(pdev);
struct ssp_device *ssp; struct ssp_device *ssp;
int status = 0;
if (!drv_data) if (!drv_data)
return 0; return 0;
ssp = drv_data->ssp; ssp = drv_data->ssp;
/* Remove the queue */
status = destroy_queue(drv_data);
if (status != 0)
/* the kernel does not check the return status of this
* this routine (mod->exit, within the kernel). Therefore
* nothing is gained by returning from here, the module is
* going away regardless, and we should not leave any more
* resources allocated than necessary. We cannot free the
* message memory in drv_data->queue, but we can release the
* resources below. I think the kernel should honor -EBUSY
* returns but... */
dev_err(&pdev->dev, "pxa2xx_spi_remove: workqueue will not "
"complete, message memory not freed\n");
/* Disable the SSP at the peripheral and SOC level */ /* Disable the SSP at the peripheral and SOC level */
write_SSCR0(0, drv_data->ioaddr); write_SSCR0(0, drv_data->ioaddr);
clk_disable(ssp->clk); clk_disable_unprepare(ssp->clk);
/* Release DMA */ /* Release DMA */
if (drv_data->master_info->enable_dma) { if (drv_data->master_info->enable_dma) {
@ -1749,11 +1574,11 @@ static int pxa2xx_spi_suspend(struct device *dev)
struct ssp_device *ssp = drv_data->ssp; struct ssp_device *ssp = drv_data->ssp;
int status = 0; int status = 0;
status = stop_queue(drv_data); status = spi_master_suspend(drv_data->master);
if (status != 0) if (status != 0)
return status; return status;
write_SSCR0(0, drv_data->ioaddr); write_SSCR0(0, drv_data->ioaddr);
clk_disable(ssp->clk); clk_disable_unprepare(ssp->clk);
return 0; return 0;
} }
@ -1772,10 +1597,10 @@ static int pxa2xx_spi_resume(struct device *dev)
DRCMR_MAPVLD | drv_data->tx_channel; DRCMR_MAPVLD | drv_data->tx_channel;
/* Enable the SSP clock */ /* Enable the SSP clock */
clk_enable(ssp->clk); clk_prepare_enable(ssp->clk);
/* Start the queue running */ /* Start the queue running */
status = start_queue(drv_data); status = spi_master_resume(drv_data->master);
if (status != 0) { if (status != 0) {
dev_err(dev, "problem starting queue (%d)\n", status); dev_err(dev, "problem starting queue (%d)\n", status);
return status; return status;

Просмотреть файл

@ -957,6 +957,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
if (spi->max_speed_hz >= speed) { if (spi->max_speed_hz >= speed) {
spi->max_speed_hz = speed; spi->max_speed_hz = speed;
} else { } else {
dev_err(&spi->dev, "Can't set %dHz transfer speed\n",
spi->max_speed_hz);
err = -EINVAL; err = -EINVAL;
goto setup_exit; goto setup_exit;
} }

Просмотреть файл

@ -22,6 +22,9 @@ struct omap2_mcspi_dev_attr {
struct omap2_mcspi_device_config { struct omap2_mcspi_device_config {
unsigned turbo_mode:1; unsigned turbo_mode:1;
/* toggle chip select after every word */
unsigned cs_per_word:1;
}; };
#endif #endif

Просмотреть файл

@ -206,6 +206,15 @@ static inline u32 pxa_ssp_read_reg(struct ssp_device *dev, u32 reg)
return __raw_readl(dev->mmio_base + reg); return __raw_readl(dev->mmio_base + reg);
} }
#ifdef CONFIG_ARCH_PXA
struct ssp_device *pxa_ssp_request(int port, const char *label); struct ssp_device *pxa_ssp_request(int port, const char *label);
void pxa_ssp_free(struct ssp_device *); void pxa_ssp_free(struct ssp_device *);
#else
static inline struct ssp_device *pxa_ssp_request(int port, const char *label)
{
return NULL;
}
static inline void pxa_ssp_free(struct ssp_device *ssp) {}
#endif
#endif #endif

Просмотреть файл

@ -28,6 +28,9 @@ struct pxa2xx_spi_master {
u32 clock_enable; u32 clock_enable;
u16 num_chipselect; u16 num_chipselect;
u8 enable_dma; u8 enable_dma;
/* For non-PXA arches */
struct ssp_device ssp;
}; };
/* spi_board_info.controller_data for SPI slave devices, /* spi_board_info.controller_data for SPI slave devices,
@ -130,23 +133,5 @@ static inline void pxa_free_dma(int dma_ch)
{ {
} }
/*
* The CE4100 does not have the clk framework implemented and SPI clock can
* not be switched on/off or the divider changed.
*/
static inline void clk_disable(struct clk *clk)
{
}
static inline int clk_enable(struct clk *clk)
{
return 0;
}
static inline unsigned long clk_get_rate(struct clk *clk)
{
return 3686400;
}
#endif #endif
#endif #endif

Просмотреть файл

@ -62,8 +62,8 @@
*/ */
struct spi_gpio_platform_data { struct spi_gpio_platform_data {
unsigned sck; unsigned sck;
unsigned mosi; unsigned long mosi;
unsigned miso; unsigned long miso;
u16 num_chipselect; u16 num_chipselect;
}; };