1ca632f556697d45d67ed5cada7cedf3ddfe0db4bGrant Likely/* 230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun * Copyright (c) 2009 Nuvoton technology. 330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun * Wan ZongShun <mcuos.com@gmail.com> 430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun * 530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun * This program is free software; you can redistribute it and/or modify 630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun * it under the terms of the GNU General Public License version 2 as 730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun * published by the Free Software Foundation. 830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun * 9ca632f556697d45d67ed5cada7cedf3ddfe0db4bGrant Likely */ 1030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 1100d2952caa6b0b2cd113494ae39f08c4663f371bAxel Lin#include <linux/module.h> 1230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#include <linux/init.h> 1330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#include <linux/spinlock.h> 1430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#include <linux/workqueue.h> 1530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#include <linux/interrupt.h> 1630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#include <linux/delay.h> 1730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#include <linux/errno.h> 1830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#include <linux/err.h> 1930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#include <linux/clk.h> 2030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#include <linux/device.h> 2130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#include <linux/platform_device.h> 2230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#include <linux/gpio.h> 2330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#include <linux/io.h> 245a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 2530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 2630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#include <linux/spi/spi.h> 2730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#include <linux/spi/spi_bitbang.h> 2830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 2930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#include <mach/nuc900_spi.h> 3030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 3130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun/* usi registers offset */ 3230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#define USI_CNT 0x00 3330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#define USI_DIV 0x04 3430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#define USI_SSR 0x08 3530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#define USI_RX0 0x10 3630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#define USI_TX0 0x10 3730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 3830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun/* usi register bit */ 3930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#define ENINT (0x01 << 17) 4030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#define ENFLG (0x01 << 16) 4130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#define TXNUM (0x03 << 8) 4230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#define TXNEG (0x01 << 2) 4330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#define RXNEG (0x01 << 1) 4430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#define LSB (0x01 << 10) 4530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#define SELECTLEV (0x01 << 2) 4630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#define SELECTPOL (0x01 << 31) 4730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#define SELECTSLAVE 0x01 4830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun#define GOBUSY 0x01 4930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 5030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstruct nuc900_spi { 5130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun struct spi_bitbang bitbang; 5230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun struct completion done; 5330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun void __iomem *regs; 5430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun int irq; 5530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun int len; 5630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun int count; 5730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun const unsigned char *tx; 5830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned char *rx; 5930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun struct clk *clk; 6030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun struct resource *ioarea; 6130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun struct spi_master *master; 6230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun struct spi_device *curdev; 6330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun struct device *dev; 6430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun struct nuc900_spi_info *pdata; 6530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spinlock_t lock; 6630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun struct resource *res; 6730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun}; 6830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 6930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic inline struct nuc900_spi *to_hw(struct spi_device *sdev) 7030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 7130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun return spi_master_get_devdata(sdev->master); 7230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 7330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 7430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic void nuc900_slave_select(struct spi_device *spi, unsigned int ssr) 7530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 7630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun struct nuc900_spi *hw = to_hw(spi); 7730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned int val; 7830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned int cs = spi->mode & SPI_CS_HIGH ? 1 : 0; 7930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned int cpol = spi->mode & SPI_CPOL ? 1 : 0; 8030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned long flags; 8130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 8230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_lock_irqsave(&hw->lock, flags); 8330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 8430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val = __raw_readl(hw->regs + USI_SSR); 8530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 8630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (!cs) 8730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val &= ~SELECTLEV; 8830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun else 8930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val |= SELECTLEV; 9030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 9130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (!ssr) 9230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val &= ~SELECTSLAVE; 9330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun else 9430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val |= SELECTSLAVE; 9530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 9630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun __raw_writel(val, hw->regs + USI_SSR); 9730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 9830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val = __raw_readl(hw->regs + USI_CNT); 9930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 10030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (!cpol) 10130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val &= ~SELECTPOL; 10230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun else 10330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val |= SELECTPOL; 10430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 10530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun __raw_writel(val, hw->regs + USI_CNT); 10630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 10730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_unlock_irqrestore(&hw->lock, flags); 10830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 10930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 11030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic void nuc900_spi_chipsel(struct spi_device *spi, int value) 11130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 11230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun switch (value) { 11330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun case BITBANG_CS_INACTIVE: 11430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun nuc900_slave_select(spi, 0); 11530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun break; 11630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 11730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun case BITBANG_CS_ACTIVE: 11830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun nuc900_slave_select(spi, 1); 11930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun break; 12030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun } 12130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 12230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 12330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic void nuc900_spi_setup_txnum(struct nuc900_spi *hw, 12430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned int txnum) 12530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 12630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned int val; 12730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned long flags; 12830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 12930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_lock_irqsave(&hw->lock, flags); 13030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 13130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val = __raw_readl(hw->regs + USI_CNT); 13230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 13330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (!txnum) 13430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val &= ~TXNUM; 13530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun else 13630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val |= txnum << 0x08; 13730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 13830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun __raw_writel(val, hw->regs + USI_CNT); 13930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 14030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_unlock_irqrestore(&hw->lock, flags); 14130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 14230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 14330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 14430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic void nuc900_spi_setup_txbitlen(struct nuc900_spi *hw, 14530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned int txbitlen) 14630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 14730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned int val; 14830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned long flags; 14930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 15030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_lock_irqsave(&hw->lock, flags); 15130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 15230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val = __raw_readl(hw->regs + USI_CNT); 15330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 15430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val |= (txbitlen << 0x03); 15530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 15630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun __raw_writel(val, hw->regs + USI_CNT); 15730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 15830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_unlock_irqrestore(&hw->lock, flags); 15930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 16030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 16130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic void nuc900_spi_gobusy(struct nuc900_spi *hw) 16230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 16330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned int val; 16430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned long flags; 16530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 16630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_lock_irqsave(&hw->lock, flags); 16730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 16830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val = __raw_readl(hw->regs + USI_CNT); 16930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 17030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val |= GOBUSY; 17130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 17230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun __raw_writel(val, hw->regs + USI_CNT); 17330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 17430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_unlock_irqrestore(&hw->lock, flags); 17530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 17630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 17730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic int nuc900_spi_setupxfer(struct spi_device *spi, 17830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun struct spi_transfer *t) 17930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 18030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun return 0; 18130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 18230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 18330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic int nuc900_spi_setup(struct spi_device *spi) 18430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 18530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun return 0; 18630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 18730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 18830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic inline unsigned int hw_txbyte(struct nuc900_spi *hw, int count) 18930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 19030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun return hw->tx ? hw->tx[count] : 0; 19130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 19230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 19330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic int nuc900_spi_txrx(struct spi_device *spi, struct spi_transfer *t) 19430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 19530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun struct nuc900_spi *hw = to_hw(spi); 19630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 19730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->tx = t->tx_buf; 19830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->rx = t->rx_buf; 19930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->len = t->len; 20030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->count = 0; 20130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 20230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun __raw_writel(hw_txbyte(hw, 0x0), hw->regs + USI_TX0); 20330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 20430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun nuc900_spi_gobusy(hw); 20530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 20630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun wait_for_completion(&hw->done); 20730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 20830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun return hw->count; 20930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 21030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 21130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic irqreturn_t nuc900_spi_irq(int irq, void *dev) 21230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 21330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun struct nuc900_spi *hw = dev; 21430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned int status; 21530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned int count = hw->count; 21630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 21730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun status = __raw_readl(hw->regs + USI_CNT); 21830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun __raw_writel(status, hw->regs + USI_CNT); 21930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 22030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (status & ENFLG) { 22130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->count++; 22230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 22330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (hw->rx) 22430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->rx[count] = __raw_readl(hw->regs + USI_RX0); 22530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun count++; 22630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 22730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (count < hw->len) { 22830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun __raw_writel(hw_txbyte(hw, count), hw->regs + USI_TX0); 22930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun nuc900_spi_gobusy(hw); 23030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun } else { 23130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun complete(&hw->done); 23230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun } 23330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 23430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun return IRQ_HANDLED; 23530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun } 23630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 23730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun complete(&hw->done); 23830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun return IRQ_HANDLED; 23930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 24030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 24130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic void nuc900_tx_edge(struct nuc900_spi *hw, unsigned int edge) 24230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 24330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned int val; 24430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned long flags; 24530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 24630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_lock_irqsave(&hw->lock, flags); 24730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 24830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val = __raw_readl(hw->regs + USI_CNT); 24930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 25030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (edge) 25130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val |= TXNEG; 25230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun else 25330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val &= ~TXNEG; 25430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun __raw_writel(val, hw->regs + USI_CNT); 25530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 25630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_unlock_irqrestore(&hw->lock, flags); 25730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 25830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 25930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic void nuc900_rx_edge(struct nuc900_spi *hw, unsigned int edge) 26030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 26130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned int val; 26230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned long flags; 26330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 26430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_lock_irqsave(&hw->lock, flags); 26530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 26630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val = __raw_readl(hw->regs + USI_CNT); 26730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 26830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (edge) 26930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val |= RXNEG; 27030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun else 27130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val &= ~RXNEG; 27230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun __raw_writel(val, hw->regs + USI_CNT); 27330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 27430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_unlock_irqrestore(&hw->lock, flags); 27530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 27630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 27730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic void nuc900_send_first(struct nuc900_spi *hw, unsigned int lsb) 27830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 27930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned int val; 28030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned long flags; 28130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 28230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_lock_irqsave(&hw->lock, flags); 28330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 28430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val = __raw_readl(hw->regs + USI_CNT); 28530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 28630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (lsb) 28730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val |= LSB; 28830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun else 28930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val &= ~LSB; 29030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun __raw_writel(val, hw->regs + USI_CNT); 29130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 29230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_unlock_irqrestore(&hw->lock, flags); 29330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 29430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 29530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic void nuc900_set_sleep(struct nuc900_spi *hw, unsigned int sleep) 29630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 29730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned int val; 29830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned long flags; 29930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 30030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_lock_irqsave(&hw->lock, flags); 30130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 30230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val = __raw_readl(hw->regs + USI_CNT); 30330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 30430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (sleep) 30530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val |= (sleep << 12); 30630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun else 30730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val &= ~(0x0f << 12); 30830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun __raw_writel(val, hw->regs + USI_CNT); 30930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 31030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_unlock_irqrestore(&hw->lock, flags); 31130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 31230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 31330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic void nuc900_enable_int(struct nuc900_spi *hw) 31430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 31530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned int val; 31630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun unsigned long flags; 31730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 31830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_lock_irqsave(&hw->lock, flags); 31930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 32030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val = __raw_readl(hw->regs + USI_CNT); 32130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 32230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun val |= ENINT; 32330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 32430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun __raw_writel(val, hw->regs + USI_CNT); 32530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 32630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_unlock_irqrestore(&hw->lock, flags); 32730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 32830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 32930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic void nuc900_set_divider(struct nuc900_spi *hw) 33030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 33130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun __raw_writel(hw->pdata->divider, hw->regs + USI_DIV); 33230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 33330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 33430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic void nuc900_init_spi(struct nuc900_spi *hw) 33530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 33630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun clk_enable(hw->clk); 33730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spin_lock_init(&hw->lock); 33830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 33930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun nuc900_tx_edge(hw, hw->pdata->txneg); 34030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun nuc900_rx_edge(hw, hw->pdata->rxneg); 34130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun nuc900_send_first(hw, hw->pdata->lsb); 34230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun nuc900_set_sleep(hw, hw->pdata->sleep); 34330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun nuc900_spi_setup_txbitlen(hw, hw->pdata->txbitlen); 34430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun nuc900_spi_setup_txnum(hw, hw->pdata->txnum); 34530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun nuc900_set_divider(hw); 34630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun nuc900_enable_int(hw); 34730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 34830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 34930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic int __devinit nuc900_spi_probe(struct platform_device *pdev) 35030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 35130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun struct nuc900_spi *hw; 35230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun struct spi_master *master; 35330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun int err = 0; 35430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 35530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun master = spi_alloc_master(&pdev->dev, sizeof(struct nuc900_spi)); 35630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (master == NULL) { 35730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun dev_err(&pdev->dev, "No memory for spi_master\n"); 35830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun err = -ENOMEM; 35930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun goto err_nomem; 36030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun } 36130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 36230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw = spi_master_get_devdata(master); 36330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->master = spi_master_get(master); 36430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->pdata = pdev->dev.platform_data; 36530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->dev = &pdev->dev; 36630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 36730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (hw->pdata == NULL) { 36830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun dev_err(&pdev->dev, "No platform data supplied\n"); 36930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun err = -ENOENT; 37030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun goto err_pdata; 37130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun } 37230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 37330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun platform_set_drvdata(pdev, hw); 37430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun init_completion(&hw->done); 37530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 37630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun master->mode_bits = SPI_MODE_0; 37730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun master->num_chipselect = hw->pdata->num_cs; 37830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun master->bus_num = hw->pdata->bus_num; 37930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->bitbang.master = hw->master; 38030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->bitbang.setup_transfer = nuc900_spi_setupxfer; 38130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->bitbang.chipselect = nuc900_spi_chipsel; 38230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->bitbang.txrx_bufs = nuc900_spi_txrx; 38330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->bitbang.master->setup = nuc900_spi_setup; 38430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 38530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 38630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (hw->res == NULL) { 38730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); 38830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun err = -ENOENT; 38930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun goto err_pdata; 39030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun } 39130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 39230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->ioarea = request_mem_region(hw->res->start, 39330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun resource_size(hw->res), pdev->name); 39430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 39530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (hw->ioarea == NULL) { 39630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun dev_err(&pdev->dev, "Cannot reserve region\n"); 39730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun err = -ENXIO; 39830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun goto err_pdata; 39930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun } 40030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 40130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->regs = ioremap(hw->res->start, resource_size(hw->res)); 40230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (hw->regs == NULL) { 40330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun dev_err(&pdev->dev, "Cannot map IO\n"); 40430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun err = -ENXIO; 40530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun goto err_iomap; 40630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun } 40730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 40830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->irq = platform_get_irq(pdev, 0); 40930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (hw->irq < 0) { 41030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun dev_err(&pdev->dev, "No IRQ specified\n"); 41130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun err = -ENOENT; 41230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun goto err_irq; 41330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun } 41430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 41530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun err = request_irq(hw->irq, nuc900_spi_irq, 0, pdev->name, hw); 41630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (err) { 41730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun dev_err(&pdev->dev, "Cannot claim IRQ\n"); 41830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun goto err_irq; 41930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun } 42030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 42130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun hw->clk = clk_get(&pdev->dev, "spi"); 42230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (IS_ERR(hw->clk)) { 42330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun dev_err(&pdev->dev, "No clock for device\n"); 42430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun err = PTR_ERR(hw->clk); 42530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun goto err_clk; 42630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun } 42730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 42897371fa99c1900a84a5220639edd726b35d73931Axel Lin mfp_set_groupg(&pdev->dev, NULL); 42930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun nuc900_init_spi(hw); 43030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 43130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun err = spi_bitbang_start(&hw->bitbang); 43230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun if (err) { 43330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun dev_err(&pdev->dev, "Failed to register SPI master\n"); 43430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun goto err_register; 43530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun } 43630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 43730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun return 0; 43830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 43930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunerr_register: 44030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun clk_disable(hw->clk); 44130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun clk_put(hw->clk); 44230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunerr_clk: 44330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun free_irq(hw->irq, hw); 44430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunerr_irq: 44530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun iounmap(hw->regs); 44630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunerr_iomap: 44730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun release_mem_region(hw->res->start, resource_size(hw->res)); 44830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun kfree(hw->ioarea); 44930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunerr_pdata: 450bc3f67a3e1b20756d4bfa5886a6b8fd0c068e6a4Joe Perches spi_master_put(hw->master); 45130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 45230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunerr_nomem: 45330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun return err; 45430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 45530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 45630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic int __devexit nuc900_spi_remove(struct platform_device *dev) 45730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun{ 45830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun struct nuc900_spi *hw = platform_get_drvdata(dev); 45930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 46030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun free_irq(hw->irq, hw); 46130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 46230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun platform_set_drvdata(dev, NULL); 46330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 464708a7e438806c02add92a585b0a6b4b2ae50159bAxel Lin spi_bitbang_stop(&hw->bitbang); 46530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 46630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun clk_disable(hw->clk); 46730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun clk_put(hw->clk); 46830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 46930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun iounmap(hw->regs); 47030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 47130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun release_mem_region(hw->res->start, resource_size(hw->res)); 47230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun kfree(hw->ioarea); 47330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 47430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun spi_master_put(hw->master); 47530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun return 0; 47630eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun} 47730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 47830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunstatic struct platform_driver nuc900_spi_driver = { 47930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun .probe = nuc900_spi_probe, 48030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun .remove = __devexit_p(nuc900_spi_remove), 48130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun .driver = { 48230eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun .name = "nuc900-spi", 48330eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun .owner = THIS_MODULE, 48430eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun }, 48530eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun}; 486940ab88962bc1aff3273a8356d64577a6e386736Grant Likelymodule_platform_driver(nuc900_spi_driver); 48730eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShun 48830eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunMODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); 48930eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunMODULE_DESCRIPTION("nuc900 spi driver!"); 49030eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunMODULE_LICENSE("GPL"); 49130eaed053c9bced7a23624e4bab5602e5b85124fWan ZongShunMODULE_ALIAS("platform:nuc900-spi"); 492