aboutsummaryrefslogtreecommitdiff
path: root/drivers/spi/spi-oc-tiny.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-oc-tiny.c')
-rw-r--r--drivers/spi/spi-oc-tiny.c131
1 files changed, 35 insertions, 96 deletions
diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c
index f1bde66cea1..8998d11c723 100644
--- a/drivers/spi/spi-oc-tiny.c
+++ b/drivers/spi/spi-oc-tiny.c
@@ -15,9 +15,9 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
@@ -53,7 +53,7 @@ struct tiny_spi {
unsigned int txc, rxc;
const u8 *txp;
u8 *rxp;
- unsigned int gpio_cs_count;
+ int gpio_cs_count;
int *gpio_cs;
};
@@ -73,7 +73,7 @@ static void tiny_spi_chipselect(struct spi_device *spi, int is_active)
{
struct tiny_spi *hw = tiny_spi_to_hw(spi);
- if (hw->gpio_cs_count) {
+ if (hw->gpio_cs_count > 0) {
gpio_set_value(hw->gpio_cs[spi->chip_select],
(spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
}
@@ -128,7 +128,7 @@ static int tiny_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
unsigned int i;
if (hw->irq >= 0) {
- /* use intrrupt driven data transfer */
+ /* use interrupt driven data transfer */
hw->len = t->len;
hw->txp = t->tx_buf;
hw->rxp = t->rx_buf;
@@ -152,62 +152,22 @@ static int tiny_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
}
wait_for_completion(&hw->done);
- } else if (txp && rxp) {
- /* we need to tighten the transfer loop */
- writeb(*txp++, hw->base + TINY_SPI_TXDATA);
- if (t->len > 1) {
- writeb(*txp++, hw->base + TINY_SPI_TXDATA);
- for (i = 2; i < t->len; i++) {
- u8 rx, tx = *txp++;
- tiny_spi_wait_txr(hw);
- rx = readb(hw->base + TINY_SPI_TXDATA);
- writeb(tx, hw->base + TINY_SPI_TXDATA);
- *rxp++ = rx;
- }
- tiny_spi_wait_txr(hw);
- *rxp++ = readb(hw->base + TINY_SPI_TXDATA);
- }
- tiny_spi_wait_txe(hw);
- *rxp++ = readb(hw->base + TINY_SPI_RXDATA);
- } else if (rxp) {
- writeb(0, hw->base + TINY_SPI_TXDATA);
- if (t->len > 1) {
- writeb(0,
- hw->base + TINY_SPI_TXDATA);
- for (i = 2; i < t->len; i++) {
- u8 rx;
- tiny_spi_wait_txr(hw);
- rx = readb(hw->base + TINY_SPI_TXDATA);
- writeb(0, hw->base + TINY_SPI_TXDATA);
- *rxp++ = rx;
- }
- tiny_spi_wait_txr(hw);
- *rxp++ = readb(hw->base + TINY_SPI_TXDATA);
- }
- tiny_spi_wait_txe(hw);
- *rxp++ = readb(hw->base + TINY_SPI_RXDATA);
- } else if (txp) {
- writeb(*txp++, hw->base + TINY_SPI_TXDATA);
- if (t->len > 1) {
- writeb(*txp++, hw->base + TINY_SPI_TXDATA);
- for (i = 2; i < t->len; i++) {
- u8 tx = *txp++;
- tiny_spi_wait_txr(hw);
- writeb(tx, hw->base + TINY_SPI_TXDATA);
- }
- }
- tiny_spi_wait_txe(hw);
} else {
- writeb(0, hw->base + TINY_SPI_TXDATA);
- if (t->len > 1) {
- writeb(0, hw->base + TINY_SPI_TXDATA);
- for (i = 2; i < t->len; i++) {
+ /* we need to tighten the transfer loop */
+ writeb(txp ? *txp++ : 0, hw->base + TINY_SPI_TXDATA);
+ for (i = 1; i < t->len; i++) {
+ writeb(txp ? *txp++ : 0, hw->base + TINY_SPI_TXDATA);
+
+ if (rxp || (i != t->len - 1))
tiny_spi_wait_txr(hw);
- writeb(0, hw->base + TINY_SPI_TXDATA);
- }
+ if (rxp)
+ *rxp++ = readb(hw->base + TINY_SPI_TXDATA);
}
tiny_spi_wait_txe(hw);
+ if (rxp)
+ *rxp++ = readb(hw->base + TINY_SPI_RXDATA);
}
+
return t->len;
}
@@ -242,7 +202,7 @@ static irqreturn_t tiny_spi_irq(int irq, void *dev)
#ifdef CONFIG_OF
#include <linux/of_gpio.h>
-static int __devinit tiny_spi_of_probe(struct platform_device *pdev)
+static int tiny_spi_of_probe(struct platform_device *pdev)
{
struct tiny_spi *hw = platform_get_drvdata(pdev);
struct device_node *np = pdev->dev.of_node;
@@ -253,7 +213,7 @@ static int __devinit tiny_spi_of_probe(struct platform_device *pdev)
if (!np)
return 0;
hw->gpio_cs_count = of_gpio_count(np);
- if (hw->gpio_cs_count) {
+ if (hw->gpio_cs_count > 0) {
hw->gpio_cs = devm_kzalloc(&pdev->dev,
hw->gpio_cs_count * sizeof(unsigned int),
GFP_KERNEL);
@@ -276,15 +236,15 @@ static int __devinit tiny_spi_of_probe(struct platform_device *pdev)
return 0;
}
#else /* !CONFIG_OF */
-static int __devinit tiny_spi_of_probe(struct platform_device *pdev)
+static int tiny_spi_of_probe(struct platform_device *pdev)
{
return 0;
}
#endif /* CONFIG_OF */
-static int __devinit tiny_spi_probe(struct platform_device *pdev)
+static int tiny_spi_probe(struct platform_device *pdev)
{
- struct tiny_spi_platform_data *platp = pdev->dev.platform_data;
+ struct tiny_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
struct tiny_spi *hw;
struct spi_master *master;
struct resource *res;
@@ -305,24 +265,18 @@ static int __devinit tiny_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, hw);
/* setup the state for the bitbang driver */
- hw->bitbang.master = spi_master_get(master);
- if (!hw->bitbang.master)
- return err;
+ hw->bitbang.master = master;
hw->bitbang.setup_transfer = tiny_spi_setup_transfer;
hw->bitbang.chipselect = tiny_spi_chipselect;
hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs;
/* find and map our resources */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- goto exit_busy;
- if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
- pdev->name))
- goto exit_busy;
- hw->base = devm_ioremap_nocache(&pdev->dev, res->start,
- resource_size(res));
- if (!hw->base)
- goto exit_busy;
+ hw->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hw->base)) {
+ err = PTR_ERR(hw->base);
+ goto exit;
+ }
/* irq is optional */
hw->irq = platform_get_irq(pdev, 0);
if (hw->irq >= 0) {
@@ -336,8 +290,10 @@ static int __devinit tiny_spi_probe(struct platform_device *pdev)
if (platp) {
hw->gpio_cs_count = platp->gpio_cs_count;
hw->gpio_cs = platp->gpio_cs;
- if (platp->gpio_cs_count && !platp->gpio_cs)
- goto exit_busy;
+ if (platp->gpio_cs_count && !platp->gpio_cs) {
+ err = -EBUSY;
+ goto exit;
+ }
hw->freq = platp->freq;
hw->baudwidth = platp->baudwidth;
} else {
@@ -351,7 +307,7 @@ static int __devinit tiny_spi_probe(struct platform_device *pdev)
goto exit_gpio;
gpio_direction_output(hw->gpio_cs[i], 1);
}
- hw->bitbang.master->num_chipselect = max(1U, hw->gpio_cs_count);
+ hw->bitbang.master->num_chipselect = max(1, hw->gpio_cs_count);
/* register our spi controller */
err = spi_bitbang_start(&hw->bitbang);
@@ -364,15 +320,12 @@ static int __devinit tiny_spi_probe(struct platform_device *pdev)
exit_gpio:
while (i-- > 0)
gpio_free(hw->gpio_cs[i]);
-exit_busy:
- err = -EBUSY;
exit:
- platform_set_drvdata(pdev, NULL);
spi_master_put(master);
return err;
}
-static int __devexit tiny_spi_remove(struct platform_device *pdev)
+static int tiny_spi_remove(struct platform_device *pdev)
{
struct tiny_spi *hw = platform_get_drvdata(pdev);
struct spi_master *master = hw->bitbang.master;
@@ -381,7 +334,6 @@ static int __devexit tiny_spi_remove(struct platform_device *pdev)
spi_bitbang_stop(&hw->bitbang);
for (i = 0; i < hw->gpio_cs_count; i++)
gpio_free(hw->gpio_cs[i]);
- platform_set_drvdata(pdev, NULL);
spi_master_put(master);
return 0;
}
@@ -392,32 +344,19 @@ static const struct of_device_id tiny_spi_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, tiny_spi_match);
-#else /* CONFIG_OF */
-#define tiny_spi_match NULL
#endif /* CONFIG_OF */
static struct platform_driver tiny_spi_driver = {
.probe = tiny_spi_probe,
- .remove = __devexit_p(tiny_spi_remove),
+ .remove = tiny_spi_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.pm = NULL,
- .of_match_table = tiny_spi_match,
+ .of_match_table = of_match_ptr(tiny_spi_match),
},
};
-
-static int __init tiny_spi_init(void)
-{
- return platform_driver_register(&tiny_spi_driver);
-}
-module_init(tiny_spi_init);
-
-static void __exit tiny_spi_exit(void)
-{
- platform_driver_unregister(&tiny_spi_driver);
-}
-module_exit(tiny_spi_exit);
+module_platform_driver(tiny_spi_driver);
MODULE_DESCRIPTION("OpenCores tiny SPI driver");
MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");