aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/spi/spi-ath79.c44
1 files changed, 43 insertions, 1 deletions
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index 9a5d7791c5fb..e02528244451 100644
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -24,17 +24,24 @@
24#include <linux/spi/spi_bitbang.h> 24#include <linux/spi/spi_bitbang.h>
25#include <linux/bitops.h> 25#include <linux/bitops.h>
26#include <linux/gpio.h> 26#include <linux/gpio.h>
27#include <linux/clk.h>
28#include <linux/err.h>
27 29
28#include <asm/mach-ath79/ar71xx_regs.h> 30#include <asm/mach-ath79/ar71xx_regs.h>
29#include <asm/mach-ath79/ath79_spi_platform.h> 31#include <asm/mach-ath79/ath79_spi_platform.h>
30 32
31#define DRV_NAME "ath79-spi" 33#define DRV_NAME "ath79-spi"
32 34
35#define ATH79_SPI_RRW_DELAY_FACTOR 12000
36#define MHZ (1000 * 1000)
37
33struct ath79_spi { 38struct ath79_spi {
34 struct spi_bitbang bitbang; 39 struct spi_bitbang bitbang;
35 u32 ioc_base; 40 u32 ioc_base;
36 u32 reg_ctrl; 41 u32 reg_ctrl;
37 void __iomem *base; 42 void __iomem *base;
43 struct clk *clk;
44 unsigned rrw_delay;
38}; 45};
39 46
40static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg) 47static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg)
@@ -52,6 +59,12 @@ static inline struct ath79_spi *ath79_spidev_to_sp(struct spi_device *spi)
52 return spi_master_get_devdata(spi->master); 59 return spi_master_get_devdata(spi->master);
53} 60}
54 61
62static inline void ath79_spi_delay(struct ath79_spi *sp, unsigned nsecs)
63{
64 if (nsecs > sp->rrw_delay)
65 ndelay(nsecs - sp->rrw_delay);
66}
67
55static void ath79_spi_chipselect(struct spi_device *spi, int is_active) 68static void ath79_spi_chipselect(struct spi_device *spi, int is_active)
56{ 69{
57 struct ath79_spi *sp = ath79_spidev_to_sp(spi); 70 struct ath79_spi *sp = ath79_spidev_to_sp(spi);
@@ -184,7 +197,9 @@ static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs,
184 197
185 /* setup MSB (to slave) on trailing edge */ 198 /* setup MSB (to slave) on trailing edge */
186 ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out); 199 ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out);
200 ath79_spi_delay(sp, nsecs);
187 ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out | AR71XX_SPI_IOC_CLK); 201 ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out | AR71XX_SPI_IOC_CLK);
202 ath79_spi_delay(sp, nsecs);
188 203
189 word <<= 1; 204 word <<= 1;
190 } 205 }
@@ -198,6 +213,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
198 struct ath79_spi *sp; 213 struct ath79_spi *sp;
199 struct ath79_spi_platform_data *pdata; 214 struct ath79_spi_platform_data *pdata;
200 struct resource *r; 215 struct resource *r;
216 unsigned long rate;
201 int ret; 217 int ret;
202 218
203 master = spi_alloc_master(&pdev->dev, sizeof(*sp)); 219 master = spi_alloc_master(&pdev->dev, sizeof(*sp));
@@ -236,12 +252,36 @@ static int ath79_spi_probe(struct platform_device *pdev)
236 goto err_put_master; 252 goto err_put_master;
237 } 253 }
238 254
255 sp->clk = clk_get(&pdev->dev, "ahb");
256 if (IS_ERR(sp->clk)) {
257 ret = PTR_ERR(sp->clk);
258 goto err_unmap;
259 }
260
261 ret = clk_enable(sp->clk);
262 if (ret)
263 goto err_clk_put;
264
265 rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
266 if (!rate) {
267 ret = -EINVAL;
268 goto err_clk_disable;
269 }
270
271 sp->rrw_delay = ATH79_SPI_RRW_DELAY_FACTOR / rate;
272 dev_dbg(&pdev->dev, "register read/write delay is %u nsecs\n",
273 sp->rrw_delay);
274
239 ret = spi_bitbang_start(&sp->bitbang); 275 ret = spi_bitbang_start(&sp->bitbang);
240 if (ret) 276 if (ret)
241 goto err_unmap; 277 goto err_clk_disable;
242 278
243 return 0; 279 return 0;
244 280
281err_clk_disable:
282 clk_disable(sp->clk);
283err_clk_put:
284 clk_put(sp->clk);
245err_unmap: 285err_unmap:
246 iounmap(sp->base); 286 iounmap(sp->base);
247err_put_master: 287err_put_master:
@@ -256,6 +296,8 @@ static int ath79_spi_remove(struct platform_device *pdev)
256 struct ath79_spi *sp = platform_get_drvdata(pdev); 296 struct ath79_spi *sp = platform_get_drvdata(pdev);
257 297
258 spi_bitbang_stop(&sp->bitbang); 298 spi_bitbang_stop(&sp->bitbang);
299 clk_disable(sp->clk);
300 clk_put(sp->clk);
259 iounmap(sp->base); 301 iounmap(sp->base);
260 platform_set_drvdata(pdev, NULL); 302 platform_set_drvdata(pdev, NULL);
261 spi_master_put(sp->bitbang.master); 303 spi_master_put(sp->bitbang.master);