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