spi-nuc900.c revision ca632f556697d45d67ed5cada7cedf3ddfe0db4b
1/* 2 * Copyright (c) 2009 Nuvoton technology. 3 * Wan ZongShun <mcuos.com@gmail.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 */ 10 11#include <linux/init.h> 12#include <linux/spinlock.h> 13#include <linux/workqueue.h> 14#include <linux/interrupt.h> 15#include <linux/delay.h> 16#include <linux/errno.h> 17#include <linux/err.h> 18#include <linux/clk.h> 19#include <linux/device.h> 20#include <linux/platform_device.h> 21#include <linux/gpio.h> 22#include <linux/io.h> 23#include <linux/slab.h> 24 25#include <linux/spi/spi.h> 26#include <linux/spi/spi_bitbang.h> 27 28#include <mach/nuc900_spi.h> 29 30/* usi registers offset */ 31#define USI_CNT 0x00 32#define USI_DIV 0x04 33#define USI_SSR 0x08 34#define USI_RX0 0x10 35#define USI_TX0 0x10 36 37/* usi register bit */ 38#define ENINT (0x01 << 17) 39#define ENFLG (0x01 << 16) 40#define TXNUM (0x03 << 8) 41#define TXNEG (0x01 << 2) 42#define RXNEG (0x01 << 1) 43#define LSB (0x01 << 10) 44#define SELECTLEV (0x01 << 2) 45#define SELECTPOL (0x01 << 31) 46#define SELECTSLAVE 0x01 47#define GOBUSY 0x01 48 49struct nuc900_spi { 50 struct spi_bitbang bitbang; 51 struct completion done; 52 void __iomem *regs; 53 int irq; 54 int len; 55 int count; 56 const unsigned char *tx; 57 unsigned char *rx; 58 struct clk *clk; 59 struct resource *ioarea; 60 struct spi_master *master; 61 struct spi_device *curdev; 62 struct device *dev; 63 struct nuc900_spi_info *pdata; 64 spinlock_t lock; 65 struct resource *res; 66}; 67 68static inline struct nuc900_spi *to_hw(struct spi_device *sdev) 69{ 70 return spi_master_get_devdata(sdev->master); 71} 72 73static void nuc900_slave_select(struct spi_device *spi, unsigned int ssr) 74{ 75 struct nuc900_spi *hw = to_hw(spi); 76 unsigned int val; 77 unsigned int cs = spi->mode & SPI_CS_HIGH ? 1 : 0; 78 unsigned int cpol = spi->mode & SPI_CPOL ? 1 : 0; 79 unsigned long flags; 80 81 spin_lock_irqsave(&hw->lock, flags); 82 83 val = __raw_readl(hw->regs + USI_SSR); 84 85 if (!cs) 86 val &= ~SELECTLEV; 87 else 88 val |= SELECTLEV; 89 90 if (!ssr) 91 val &= ~SELECTSLAVE; 92 else 93 val |= SELECTSLAVE; 94 95 __raw_writel(val, hw->regs + USI_SSR); 96 97 val = __raw_readl(hw->regs + USI_CNT); 98 99 if (!cpol) 100 val &= ~SELECTPOL; 101 else 102 val |= SELECTPOL; 103 104 __raw_writel(val, hw->regs + USI_CNT); 105 106 spin_unlock_irqrestore(&hw->lock, flags); 107} 108 109static void nuc900_spi_chipsel(struct spi_device *spi, int value) 110{ 111 switch (value) { 112 case BITBANG_CS_INACTIVE: 113 nuc900_slave_select(spi, 0); 114 break; 115 116 case BITBANG_CS_ACTIVE: 117 nuc900_slave_select(spi, 1); 118 break; 119 } 120} 121 122static void nuc900_spi_setup_txnum(struct nuc900_spi *hw, 123 unsigned int txnum) 124{ 125 unsigned int val; 126 unsigned long flags; 127 128 spin_lock_irqsave(&hw->lock, flags); 129 130 val = __raw_readl(hw->regs + USI_CNT); 131 132 if (!txnum) 133 val &= ~TXNUM; 134 else 135 val |= txnum << 0x08; 136 137 __raw_writel(val, hw->regs + USI_CNT); 138 139 spin_unlock_irqrestore(&hw->lock, flags); 140 141} 142 143static void nuc900_spi_setup_txbitlen(struct nuc900_spi *hw, 144 unsigned int txbitlen) 145{ 146 unsigned int val; 147 unsigned long flags; 148 149 spin_lock_irqsave(&hw->lock, flags); 150 151 val = __raw_readl(hw->regs + USI_CNT); 152 153 val |= (txbitlen << 0x03); 154 155 __raw_writel(val, hw->regs + USI_CNT); 156 157 spin_unlock_irqrestore(&hw->lock, flags); 158} 159 160static void nuc900_spi_gobusy(struct nuc900_spi *hw) 161{ 162 unsigned int val; 163 unsigned long flags; 164 165 spin_lock_irqsave(&hw->lock, flags); 166 167 val = __raw_readl(hw->regs + USI_CNT); 168 169 val |= GOBUSY; 170 171 __raw_writel(val, hw->regs + USI_CNT); 172 173 spin_unlock_irqrestore(&hw->lock, flags); 174} 175 176static int nuc900_spi_setupxfer(struct spi_device *spi, 177 struct spi_transfer *t) 178{ 179 return 0; 180} 181 182static int nuc900_spi_setup(struct spi_device *spi) 183{ 184 return 0; 185} 186 187static inline unsigned int hw_txbyte(struct nuc900_spi *hw, int count) 188{ 189 return hw->tx ? hw->tx[count] : 0; 190} 191 192static int nuc900_spi_txrx(struct spi_device *spi, struct spi_transfer *t) 193{ 194 struct nuc900_spi *hw = to_hw(spi); 195 196 hw->tx = t->tx_buf; 197 hw->rx = t->rx_buf; 198 hw->len = t->len; 199 hw->count = 0; 200 201 __raw_writel(hw_txbyte(hw, 0x0), hw->regs + USI_TX0); 202 203 nuc900_spi_gobusy(hw); 204 205 wait_for_completion(&hw->done); 206 207 return hw->count; 208} 209 210static irqreturn_t nuc900_spi_irq(int irq, void *dev) 211{ 212 struct nuc900_spi *hw = dev; 213 unsigned int status; 214 unsigned int count = hw->count; 215 216 status = __raw_readl(hw->regs + USI_CNT); 217 __raw_writel(status, hw->regs + USI_CNT); 218 219 if (status & ENFLG) { 220 hw->count++; 221 222 if (hw->rx) 223 hw->rx[count] = __raw_readl(hw->regs + USI_RX0); 224 count++; 225 226 if (count < hw->len) { 227 __raw_writel(hw_txbyte(hw, count), hw->regs + USI_TX0); 228 nuc900_spi_gobusy(hw); 229 } else { 230 complete(&hw->done); 231 } 232 233 return IRQ_HANDLED; 234 } 235 236 complete(&hw->done); 237 return IRQ_HANDLED; 238} 239 240static void nuc900_tx_edge(struct nuc900_spi *hw, unsigned int edge) 241{ 242 unsigned int val; 243 unsigned long flags; 244 245 spin_lock_irqsave(&hw->lock, flags); 246 247 val = __raw_readl(hw->regs + USI_CNT); 248 249 if (edge) 250 val |= TXNEG; 251 else 252 val &= ~TXNEG; 253 __raw_writel(val, hw->regs + USI_CNT); 254 255 spin_unlock_irqrestore(&hw->lock, flags); 256} 257 258static void nuc900_rx_edge(struct nuc900_spi *hw, unsigned int edge) 259{ 260 unsigned int val; 261 unsigned long flags; 262 263 spin_lock_irqsave(&hw->lock, flags); 264 265 val = __raw_readl(hw->regs + USI_CNT); 266 267 if (edge) 268 val |= RXNEG; 269 else 270 val &= ~RXNEG; 271 __raw_writel(val, hw->regs + USI_CNT); 272 273 spin_unlock_irqrestore(&hw->lock, flags); 274} 275 276static void nuc900_send_first(struct nuc900_spi *hw, unsigned int lsb) 277{ 278 unsigned int val; 279 unsigned long flags; 280 281 spin_lock_irqsave(&hw->lock, flags); 282 283 val = __raw_readl(hw->regs + USI_CNT); 284 285 if (lsb) 286 val |= LSB; 287 else 288 val &= ~LSB; 289 __raw_writel(val, hw->regs + USI_CNT); 290 291 spin_unlock_irqrestore(&hw->lock, flags); 292} 293 294static void nuc900_set_sleep(struct nuc900_spi *hw, unsigned int sleep) 295{ 296 unsigned int val; 297 unsigned long flags; 298 299 spin_lock_irqsave(&hw->lock, flags); 300 301 val = __raw_readl(hw->regs + USI_CNT); 302 303 if (sleep) 304 val |= (sleep << 12); 305 else 306 val &= ~(0x0f << 12); 307 __raw_writel(val, hw->regs + USI_CNT); 308 309 spin_unlock_irqrestore(&hw->lock, flags); 310} 311 312static void nuc900_enable_int(struct nuc900_spi *hw) 313{ 314 unsigned int val; 315 unsigned long flags; 316 317 spin_lock_irqsave(&hw->lock, flags); 318 319 val = __raw_readl(hw->regs + USI_CNT); 320 321 val |= ENINT; 322 323 __raw_writel(val, hw->regs + USI_CNT); 324 325 spin_unlock_irqrestore(&hw->lock, flags); 326} 327 328static void nuc900_set_divider(struct nuc900_spi *hw) 329{ 330 __raw_writel(hw->pdata->divider, hw->regs + USI_DIV); 331} 332 333static void nuc900_init_spi(struct nuc900_spi *hw) 334{ 335 clk_enable(hw->clk); 336 spin_lock_init(&hw->lock); 337 338 nuc900_tx_edge(hw, hw->pdata->txneg); 339 nuc900_rx_edge(hw, hw->pdata->rxneg); 340 nuc900_send_first(hw, hw->pdata->lsb); 341 nuc900_set_sleep(hw, hw->pdata->sleep); 342 nuc900_spi_setup_txbitlen(hw, hw->pdata->txbitlen); 343 nuc900_spi_setup_txnum(hw, hw->pdata->txnum); 344 nuc900_set_divider(hw); 345 nuc900_enable_int(hw); 346} 347 348static int __devinit nuc900_spi_probe(struct platform_device *pdev) 349{ 350 struct nuc900_spi *hw; 351 struct spi_master *master; 352 int err = 0; 353 354 master = spi_alloc_master(&pdev->dev, sizeof(struct nuc900_spi)); 355 if (master == NULL) { 356 dev_err(&pdev->dev, "No memory for spi_master\n"); 357 err = -ENOMEM; 358 goto err_nomem; 359 } 360 361 hw = spi_master_get_devdata(master); 362 memset(hw, 0, sizeof(struct nuc900_spi)); 363 364 hw->master = spi_master_get(master); 365 hw->pdata = pdev->dev.platform_data; 366 hw->dev = &pdev->dev; 367 368 if (hw->pdata == NULL) { 369 dev_err(&pdev->dev, "No platform data supplied\n"); 370 err = -ENOENT; 371 goto err_pdata; 372 } 373 374 platform_set_drvdata(pdev, hw); 375 init_completion(&hw->done); 376 377 master->mode_bits = SPI_MODE_0; 378 master->num_chipselect = hw->pdata->num_cs; 379 master->bus_num = hw->pdata->bus_num; 380 hw->bitbang.master = hw->master; 381 hw->bitbang.setup_transfer = nuc900_spi_setupxfer; 382 hw->bitbang.chipselect = nuc900_spi_chipsel; 383 hw->bitbang.txrx_bufs = nuc900_spi_txrx; 384 hw->bitbang.master->setup = nuc900_spi_setup; 385 386 hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 387 if (hw->res == NULL) { 388 dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); 389 err = -ENOENT; 390 goto err_pdata; 391 } 392 393 hw->ioarea = request_mem_region(hw->res->start, 394 resource_size(hw->res), pdev->name); 395 396 if (hw->ioarea == NULL) { 397 dev_err(&pdev->dev, "Cannot reserve region\n"); 398 err = -ENXIO; 399 goto err_pdata; 400 } 401 402 hw->regs = ioremap(hw->res->start, resource_size(hw->res)); 403 if (hw->regs == NULL) { 404 dev_err(&pdev->dev, "Cannot map IO\n"); 405 err = -ENXIO; 406 goto err_iomap; 407 } 408 409 hw->irq = platform_get_irq(pdev, 0); 410 if (hw->irq < 0) { 411 dev_err(&pdev->dev, "No IRQ specified\n"); 412 err = -ENOENT; 413 goto err_irq; 414 } 415 416 err = request_irq(hw->irq, nuc900_spi_irq, 0, pdev->name, hw); 417 if (err) { 418 dev_err(&pdev->dev, "Cannot claim IRQ\n"); 419 goto err_irq; 420 } 421 422 hw->clk = clk_get(&pdev->dev, "spi"); 423 if (IS_ERR(hw->clk)) { 424 dev_err(&pdev->dev, "No clock for device\n"); 425 err = PTR_ERR(hw->clk); 426 goto err_clk; 427 } 428 429 mfp_set_groupg(&pdev->dev); 430 nuc900_init_spi(hw); 431 432 err = spi_bitbang_start(&hw->bitbang); 433 if (err) { 434 dev_err(&pdev->dev, "Failed to register SPI master\n"); 435 goto err_register; 436 } 437 438 return 0; 439 440err_register: 441 clk_disable(hw->clk); 442 clk_put(hw->clk); 443err_clk: 444 free_irq(hw->irq, hw); 445err_irq: 446 iounmap(hw->regs); 447err_iomap: 448 release_mem_region(hw->res->start, resource_size(hw->res)); 449 kfree(hw->ioarea); 450err_pdata: 451 spi_master_put(hw->master); 452 453err_nomem: 454 return err; 455} 456 457static int __devexit nuc900_spi_remove(struct platform_device *dev) 458{ 459 struct nuc900_spi *hw = platform_get_drvdata(dev); 460 461 free_irq(hw->irq, hw); 462 463 platform_set_drvdata(dev, NULL); 464 465 spi_bitbang_stop(&hw->bitbang); 466 467 clk_disable(hw->clk); 468 clk_put(hw->clk); 469 470 iounmap(hw->regs); 471 472 release_mem_region(hw->res->start, resource_size(hw->res)); 473 kfree(hw->ioarea); 474 475 spi_master_put(hw->master); 476 return 0; 477} 478 479static struct platform_driver nuc900_spi_driver = { 480 .probe = nuc900_spi_probe, 481 .remove = __devexit_p(nuc900_spi_remove), 482 .driver = { 483 .name = "nuc900-spi", 484 .owner = THIS_MODULE, 485 }, 486}; 487 488static int __init nuc900_spi_init(void) 489{ 490 return platform_driver_register(&nuc900_spi_driver); 491} 492 493static void __exit nuc900_spi_exit(void) 494{ 495 platform_driver_unregister(&nuc900_spi_driver); 496} 497 498module_init(nuc900_spi_init); 499module_exit(nuc900_spi_exit); 500 501MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); 502MODULE_DESCRIPTION("nuc900 spi driver!"); 503MODULE_LICENSE("GPL"); 504MODULE_ALIAS("platform:nuc900-spi"); 505