X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/546b5ed544503182a9b3e981bc11feebd6042b21..613a88e6a5a1b15309e72975a92747325e19d0c1:/target/linux/ar71xx/files/drivers/spi/ar71xx_spi.c diff --git a/target/linux/ar71xx/files/drivers/spi/ar71xx_spi.c b/target/linux/ar71xx/files/drivers/spi/ar71xx_spi.c index 98de435fd..f548cde6d 100644 --- a/target/linux/ar71xx/files/drivers/spi/ar71xx_spi.c +++ b/target/linux/ar71xx/files/drivers/spi/ar71xx_spi.c @@ -1,7 +1,7 @@ /* * Atheros AR71xx SPI Controller driver * - * Copyright (C) 2008 Gabor Juhos + * Copyright (C) 2008-2009 Gabor Juhos * Copyright (C) 2008 Imre Kaloz * * This program is free software; you can redistribute it and/or modify @@ -25,17 +25,17 @@ #include #define DRV_DESC "Atheros AR71xx SPI Controller driver" -#define DRV_VERSION "0.2.2" +#define DRV_VERSION "0.2.4" #define DRV_NAME "ar71xx-spi" #undef PER_BIT_READ struct ar71xx_spi { - struct spi_bitbang bitbang; + struct spi_bitbang bitbang; u32 ioc_base; u32 reg_ctrl; - void __iomem *base; + void __iomem *base; struct platform_device *pdev; u32 (*get_ioc_base)(u8 chip_select, int cs_high, @@ -80,10 +80,7 @@ static void ar71xx_spi_chipselect(struct spi_device *spi, int value) ioc_base = sp->get_ioc_base(spi->chip_select, (spi->mode & SPI_CS_HIGH) != 0, AR71XX_SPI_CS_INACTIVE); - __raw_writel(ioc_base, base + SPI_REG_IOC); - __raw_writel(sp->reg_ctrl, base + SPI_REG_CTRL); - __raw_writel(0, base + SPI_REG_FS); break; case BITBANG_CS_ACTIVE: @@ -91,15 +88,59 @@ static void ar71xx_spi_chipselect(struct spi_device *spi, int value) (spi->mode & SPI_CS_HIGH) != 0, AR71XX_SPI_CS_ACTIVE); - __raw_writel(SPI_FS_GPIO, base + SPI_REG_FS); - /* TODO: setup speed */ - __raw_writel(0x43, base + SPI_REG_CTRL); __raw_writel(ioc_base, base + SPI_REG_IOC); sp->ioc_base = ioc_base; break; } } +static void ar71xx_spi_setup_regs(struct spi_device *spi) +{ + struct ar71xx_spi *sp = spidev_to_sp(spi); + + /* enable GPIO mode */ + ar71xx_spi_wr(sp, SPI_REG_FS, SPI_FS_GPIO); + + /* save CTRL register */ + sp->reg_ctrl = ar71xx_spi_rr(sp, SPI_REG_CTRL); + + /* TODO: setup speed? */ + ar71xx_spi_wr(sp, SPI_REG_CTRL, 0x43); +} + +static void ar71xx_spi_restore_regs(struct spi_device *spi) +{ + struct ar71xx_spi *sp = spidev_to_sp(spi); + + /* restore CTRL register */ + ar71xx_spi_wr(sp, SPI_REG_CTRL, sp->reg_ctrl); + /* disable GPIO mode */ + ar71xx_spi_wr(sp, SPI_REG_FS, 0); +} + +static int ar71xx_spi_setup(struct spi_device *spi) +{ + int status; + + if (spi->bits_per_word > 32) + return -EINVAL; + + if (!spi->controller_state) + ar71xx_spi_setup_regs(spi); + + status = spi_bitbang_setup(spi); + if (status && !spi->controller_state) + ar71xx_spi_restore_regs(spi); + + return status; +} + +static void ar71xx_spi_cleanup(struct spi_device *spi) +{ + ar71xx_spi_restore_regs(spi); + spi_bitbang_cleanup(spi); +} + static u32 ar71xx_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits) { @@ -157,9 +198,13 @@ static int ar71xx_spi_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; + master->setup = ar71xx_spi_setup; + master->cleanup = ar71xx_spi_cleanup; + sp->bitbang.master = spi_master_get(master); sp->bitbang.chipselect = ar71xx_spi_chipselect; sp->bitbang.txrx_word[SPI_MODE_0] = ar71xx_spi_txrx_mode0; + sp->bitbang.setup_transfer = spi_bitbang_setup_transfer; sp->get_ioc_base = ar71xx_spi_get_ioc_base; if (pdata) { @@ -184,8 +229,6 @@ static int ar71xx_spi_probe(struct platform_device *pdev) goto err1; } - sp->reg_ctrl = ar71xx_spi_rr(sp, SPI_REG_IOC); - ret = spi_bitbang_start(&sp->bitbang); if (!ret) return 0;