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