diff options
Diffstat (limited to 'drivers/spi/spi-orion.c')
| -rw-r--r-- | drivers/spi/spi-orion.c | 165 |
1 files changed, 53 insertions, 112 deletions
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index b17c09cf0a0..d018a4aac3a 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -9,7 +9,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/platform_device.h> @@ -19,6 +18,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/clk.h> +#include <linux/sizes.h> #include <asm/unaligned.h> #define DRIVER_NAME "orion_spi" @@ -32,14 +32,16 @@ #define ORION_SPI_DATA_IN_REG 0x0c #define ORION_SPI_INT_CAUSE_REG 0x10 +#define ORION_SPI_MODE_CPOL (1 << 11) +#define ORION_SPI_MODE_CPHA (1 << 12) #define ORION_SPI_IF_8_16_BIT_MODE (1 << 5) #define ORION_SPI_CLK_PRESCALE_MASK 0x1F +#define ORION_SPI_MODE_MASK (ORION_SPI_MODE_CPOL | \ + ORION_SPI_MODE_CPHA) struct orion_spi { struct spi_master *master; void __iomem *base; - unsigned int max_speed; - unsigned int min_speed; struct clk *clk; }; @@ -70,23 +72,6 @@ orion_spi_clrbits(struct orion_spi *orion_spi, u32 reg, u32 mask) writel(val, reg_addr); } -static int orion_spi_set_transfer_size(struct orion_spi *orion_spi, int size) -{ - if (size == 16) { - orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG, - ORION_SPI_IF_8_16_BIT_MODE); - } else if (size == 8) { - orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG, - ORION_SPI_IF_8_16_BIT_MODE); - } else { - pr_debug("Bad bits per word value %d (only 8 or 16 are " - "allowed).\n", size); - return -EINVAL; - } - - return 0; -} - static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed) { u32 tclk_hz; @@ -123,6 +108,23 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed) return 0; } +static void +orion_spi_mode_set(struct spi_device *spi) +{ + u32 reg; + struct orion_spi *orion_spi; + + orion_spi = spi_master_get_devdata(spi->master); + + reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG)); + reg &= ~ORION_SPI_MODE_MASK; + if (spi->mode & SPI_CPOL) + reg |= ORION_SPI_MODE_CPOL; + if (spi->mode & SPI_CPHA) + reg |= ORION_SPI_MODE_CPHA; + writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG)); +} + /* * called only when no transfer is active on the bus */ @@ -142,11 +144,20 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) if ((t != NULL) && t->bits_per_word) bits_per_word = t->bits_per_word; + orion_spi_mode_set(spi); + rc = orion_spi_baudrate_set(spi, speed); if (rc) return rc; - return orion_spi_set_transfer_size(orion_spi, bits_per_word); + if (bits_per_word == 16) + orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG, + ORION_SPI_IF_8_16_BIT_MODE); + else + orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG, + ORION_SPI_IF_8_16_BIT_MODE); + + return 0; } static void orion_spi_set_cs(struct orion_spi *orion_spi, int enable) @@ -236,11 +247,9 @@ orion_spi_write_read_16bit(struct spi_device *spi, static unsigned int orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) { - struct orion_spi *orion_spi; unsigned int count; int word_len; - orion_spi = spi_master_get_devdata(spi->master); word_len = spi->bits_per_word; count = xfer->len; @@ -286,27 +295,6 @@ static int orion_spi_transfer_one_message(struct spi_master *master, goto msg_done; list_for_each_entry(t, &m->transfers, transfer_list) { - /* make sure buffer length is even when working in 16 - * bit mode*/ - if ((t->bits_per_word == 16) && (t->len & 1)) { - dev_err(&spi->dev, - "message rejected : " - "odd data length %d while in 16 bit mode\n", - t->len); - status = -EIO; - goto msg_done; - } - - if (t->speed_hz && t->speed_hz < orion_spi->min_speed) { - dev_err(&spi->dev, - "message rejected : " - "device min speed (%d Hz) exceeds " - "required transfer speed (%d Hz)\n", - orion_spi->min_speed, t->speed_hz); - status = -EIO; - goto msg_done; - } - if (par_override || t->speed_hz || t->bits_per_word) { par_override = 1; status = orion_spi_setup_transfer(spi, t); @@ -343,7 +331,7 @@ msg_done: return 0; } -static int __init orion_spi_reset(struct orion_spi *orion_spi) +static int orion_spi_reset(struct orion_spi *orion_spi) { /* Verify that the CS is deasserted */ orion_spi_set_cs(orion_spi, 0); @@ -351,29 +339,7 @@ static int __init orion_spi_reset(struct orion_spi *orion_spi) return 0; } -static int orion_spi_setup(struct spi_device *spi) -{ - struct orion_spi *orion_spi; - - orion_spi = spi_master_get_devdata(spi->master); - - if ((spi->max_speed_hz == 0) - || (spi->max_speed_hz > orion_spi->max_speed)) - spi->max_speed_hz = orion_spi->max_speed; - - if (spi->max_speed_hz < orion_spi->min_speed) { - dev_err(&spi->dev, "setup: requested speed too low %d Hz\n", - spi->max_speed_hz); - return -EINVAL; - } - - /* - * baudrate & width will be set orion_spi_setup_transfer - */ - return 0; -} - -static int __init orion_spi_probe(struct platform_device *pdev) +static int orion_spi_probe(struct platform_device *pdev) { struct spi_master *master; struct orion_spi *spi; @@ -383,7 +349,7 @@ static int __init orion_spi_probe(struct platform_device *pdev) const u32 *iprop; int size; - master = spi_alloc_master(&pdev->dev, sizeof *spi); + master = spi_alloc_master(&pdev->dev, sizeof(*spi)); if (master == NULL) { dev_dbg(&pdev->dev, "master allocation failed\n"); return -ENOMEM; @@ -399,18 +365,18 @@ static int __init orion_spi_probe(struct platform_device *pdev) } /* we support only mode 0, and no options */ - master->mode_bits = 0; + master->mode_bits = SPI_CPHA | SPI_CPOL; - master->setup = orion_spi_setup; master->transfer_one_message = orion_spi_transfer_one_message; master->num_chipselect = ORION_NUM_CHIPSELECTS; + master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); - dev_set_drvdata(&pdev->dev, master); + platform_set_drvdata(pdev, master); spi = spi_master_get_devdata(master); spi->master = master; - spi->clk = clk_get(&pdev->dev, NULL); + spi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(spi->clk)) { status = PTR_ERR(spi->clk); goto out; @@ -419,66 +385,50 @@ static int __init orion_spi_probe(struct platform_device *pdev) clk_prepare(spi->clk); clk_enable(spi->clk); tclk_hz = clk_get_rate(spi->clk); - spi->max_speed = DIV_ROUND_UP(tclk_hz, 4); - spi->min_speed = DIV_ROUND_UP(tclk_hz, 30); + master->max_speed_hz = DIV_ROUND_UP(tclk_hz, 4); + master->min_speed_hz = DIV_ROUND_UP(tclk_hz, 30); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (r == NULL) { - status = -ENODEV; - goto out_rel_clk; - } - - if (!request_mem_region(r->start, resource_size(r), - dev_name(&pdev->dev))) { - status = -EBUSY; + spi->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(spi->base)) { + status = PTR_ERR(spi->base); goto out_rel_clk; } - spi->base = ioremap(r->start, SZ_1K); if (orion_spi_reset(spi) < 0) - goto out_rel_mem; + goto out_rel_clk; master->dev.of_node = pdev->dev.of_node; - status = spi_register_master(master); + status = devm_spi_register_master(&pdev->dev, master); if (status < 0) - goto out_rel_mem; + goto out_rel_clk; return status; -out_rel_mem: - release_mem_region(r->start, resource_size(r)); out_rel_clk: clk_disable_unprepare(spi->clk); - clk_put(spi->clk); out: spi_master_put(master); return status; } -static int __exit orion_spi_remove(struct platform_device *pdev) +static int orion_spi_remove(struct platform_device *pdev) { struct spi_master *master; - struct resource *r; struct orion_spi *spi; - master = dev_get_drvdata(&pdev->dev); + master = platform_get_drvdata(pdev); spi = spi_master_get_devdata(master); clk_disable_unprepare(spi->clk); - clk_put(spi->clk); - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(r->start, resource_size(r)); - - spi_unregister_master(master); return 0; } MODULE_ALIAS("platform:" DRIVER_NAME); -static const struct of_device_id orion_spi_of_match_table[] __devinitdata = { +static const struct of_device_id orion_spi_of_match_table[] = { { .compatible = "marvell,orion-spi", }, {} }; @@ -490,20 +440,11 @@ static struct platform_driver orion_spi_driver = { .owner = THIS_MODULE, .of_match_table = of_match_ptr(orion_spi_of_match_table), }, - .remove = __exit_p(orion_spi_remove), + .probe = orion_spi_probe, + .remove = orion_spi_remove, }; -static int __init orion_spi_init(void) -{ - return platform_driver_probe(&orion_spi_driver, orion_spi_probe); -} -module_init(orion_spi_init); - -static void __exit orion_spi_exit(void) -{ - platform_driver_unregister(&orion_spi_driver); -} -module_exit(orion_spi_exit); +module_platform_driver(orion_spi_driver); MODULE_DESCRIPTION("Orion SPI driver"); MODULE_AUTHOR("Shadi Ammouri <shadi@marvell.com>"); |
