Skip to content
Snippets Groups Projects
spi-atmel.c 28.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	ret = request_irq(irq, atmel_spi_interrupt, 0,
    
    	if (ret)
    		goto out_unmap_regs;
    
    	/* Initialize the hardware */
    	clk_enable(clk);
    	spi_writel(as, CR, SPI_BIT(SWRST));
    
    	spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
    
    	if (as->caps.has_wdrbt) {
    		spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS)
    				| SPI_BIT(MSTR));
    	} else {
    		spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
    	}
    
    	spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
    	spi_writel(as, CR, SPI_BIT(SPIEN));
    
    	/* go! */
    	dev_info(&pdev->dev, "Atmel SPI Controller at 0x%08lx (irq %d)\n",
    			(unsigned long)regs->start, irq);
    
    	ret = spi_register_master(master);
    	if (ret)
    		goto out_reset_hw;
    
    	return 0;
    
    out_reset_hw:
    	spi_writel(as, CR, SPI_BIT(SWRST));
    
    	spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
    
    	clk_disable(clk);
    	free_irq(irq, master);
    out_unmap_regs:
    	iounmap(as->regs);
    out_free_buffer:
    	dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
    			as->buffer_dma);
    out_free:
    	clk_put(clk);
    	spi_master_put(master);
    	return ret;
    }
    
    
    static int atmel_spi_remove(struct platform_device *pdev)
    
    {
    	struct spi_master	*master = platform_get_drvdata(pdev);
    	struct atmel_spi	*as = spi_master_get_devdata(master);
    	struct spi_message	*msg;
    
    	/* reset the hardware and block queue progress */
    	spin_lock_irq(&as->lock);
    	as->stopping = 1;
    	spi_writel(as, CR, SPI_BIT(SWRST));
    
    	spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
    
    	spi_readl(as, SR);
    	spin_unlock_irq(&as->lock);
    
    	/* Terminate remaining queued transfers */
    	list_for_each_entry(msg, &as->queue, queue) {
    		/* REVISIT unmapping the dma is a NOP on ARM and AVR32
    		 * but we shouldn't depend on that...
    		 */
    		msg->status = -ESHUTDOWN;
    		msg->complete(msg->context);
    	}
    
    	dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
    			as->buffer_dma);
    
    	clk_disable(as->clk);
    	clk_put(as->clk);
    	free_irq(as->irq, master);
    	iounmap(as->regs);
    
    	spi_unregister_master(master);
    
    	return 0;
    }
    
    #ifdef	CONFIG_PM
    
    static int atmel_spi_suspend(struct platform_device *pdev, pm_message_t mesg)
    {
    	struct spi_master	*master = platform_get_drvdata(pdev);
    	struct atmel_spi	*as = spi_master_get_devdata(master);
    
    	clk_disable(as->clk);
    	return 0;
    }
    
    static int atmel_spi_resume(struct platform_device *pdev)
    {
    	struct spi_master	*master = platform_get_drvdata(pdev);
    	struct atmel_spi	*as = spi_master_get_devdata(master);
    
    	clk_enable(as->clk);
    	return 0;
    }
    
    #else
    #define	atmel_spi_suspend	NULL
    #define	atmel_spi_resume	NULL
    #endif
    
    
    #if defined(CONFIG_OF)
    static const struct of_device_id atmel_spi_dt_ids[] = {
    	{ .compatible = "atmel,at91rm9200-spi" },
    	{ /* sentinel */ }
    };
    
    MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids);
    #endif
    
    
    static struct platform_driver atmel_spi_driver = {
    	.driver		= {
    		.name	= "atmel_spi",
    		.owner	= THIS_MODULE,
    
    		.of_match_table	= of_match_ptr(atmel_spi_dt_ids),
    
    	},
    	.suspend	= atmel_spi_suspend,
    	.resume		= atmel_spi_resume,
    
    	.probe		= atmel_spi_probe,
    
    module_platform_driver(atmel_spi_driver);
    
    
    MODULE_DESCRIPTION("Atmel AT32/AT91 SPI Controller driver");
    
    MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
    
    MODULE_LICENSE("GPL");
    
    MODULE_ALIAS("platform:atmel_spi");