1b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu/*
2b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu * Freescale SPI/eSPI controller driver library.
3b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu *
4b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu * Maintainer: Kumar Gala
5b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu *
6b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu * Copyright (C) 2006 Polycom, Inc.
7b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu *
8b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu * CPM SPI and QE buffer descriptors mode support:
9b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu * Copyright (c) 2009  MontaVista Software, Inc.
10b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
11b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu *
12b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu * Copyright 2010 Freescale Semiconductor, Inc.
13b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu *
14b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu * This program is free software; you can redistribute  it and/or modify it
15b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu * under  the terms of  the GNU General  Public License as published by the
16b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu * Free Software Foundation;  either version 2 of the  License, or (at your
17b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu * option) any later version.
18b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu */
19b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu#include <linux/kernel.h>
20b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu#include <linux/interrupt.h>
21b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu#include <linux/fsl_devices.h>
22b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu#include <linux/dma-mapping.h>
23b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu#include <linux/mm.h>
24b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu#include <linux/of_platform.h>
25b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu#include <linux/of_spi.h>
26b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu#include <sysdev/fsl_soc.h>
27b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
28ca632f556697d45d67ed5cada7cedf3ddfe0db4bGrant Likely#include "spi-fsl-lib.h"
29b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
30b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu#define MPC8XXX_SPI_RX_BUF(type) 					  \
31b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Huvoid mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
32b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu{									  \
33b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	type *rx = mpc8xxx_spi->rx;					  \
34b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	*rx++ = (type)(data >> mpc8xxx_spi->rx_shift);			  \
35b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	mpc8xxx_spi->rx = rx;						  \
36b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu}
37b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
38b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu#define MPC8XXX_SPI_TX_BUF(type)				\
39b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Huu32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi)	\
40b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu{								\
41b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	u32 data;						\
42b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	const type *tx = mpc8xxx_spi->tx;			\
43b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	if (!tx)						\
44b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		return 0;					\
45b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	data = *tx++ << mpc8xxx_spi->tx_shift;			\
46b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	mpc8xxx_spi->tx = tx;					\
47b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	return data;						\
48b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu}
49b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
50b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai HuMPC8XXX_SPI_RX_BUF(u8)
51b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai HuMPC8XXX_SPI_RX_BUF(u16)
52b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai HuMPC8XXX_SPI_RX_BUF(u32)
53b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai HuMPC8XXX_SPI_TX_BUF(u8)
54b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai HuMPC8XXX_SPI_TX_BUF(u16)
55b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai HuMPC8XXX_SPI_TX_BUF(u32)
56b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
57b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hustruct mpc8xxx_spi_probe_info *to_of_pinfo(struct fsl_spi_platform_data *pdata)
58b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu{
59b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
60b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu}
61b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
62b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Huvoid mpc8xxx_spi_work(struct work_struct *work)
63b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu{
64b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
65b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu						       work);
66b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
67b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	spin_lock_irq(&mpc8xxx_spi->lock);
68b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	while (!list_empty(&mpc8xxx_spi->queue)) {
69b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		struct spi_message *m = container_of(mpc8xxx_spi->queue.next,
70b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu						   struct spi_message, queue);
71b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
72b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		list_del_init(&m->queue);
73b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		spin_unlock_irq(&mpc8xxx_spi->lock);
74b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
75b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		if (mpc8xxx_spi->spi_do_one_msg)
76b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu			mpc8xxx_spi->spi_do_one_msg(m);
77b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
78b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		spin_lock_irq(&mpc8xxx_spi->lock);
79b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	}
80b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	spin_unlock_irq(&mpc8xxx_spi->lock);
81b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu}
82b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
83b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Huint mpc8xxx_spi_transfer(struct spi_device *spi,
84b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu				struct spi_message *m)
85b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu{
86b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
87b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	unsigned long flags;
88b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
89b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	m->actual_length = 0;
90b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	m->status = -EINPROGRESS;
91b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
92b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	spin_lock_irqsave(&mpc8xxx_spi->lock, flags);
93b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	list_add_tail(&m->queue, &mpc8xxx_spi->queue);
94b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work);
95b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags);
96b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
97b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	return 0;
98b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu}
99b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
100b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Huvoid mpc8xxx_spi_cleanup(struct spi_device *spi)
101b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu{
102b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	kfree(spi->controller_state);
103b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu}
104b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
105b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Huconst char *mpc8xxx_spi_strmode(unsigned int flags)
106b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu{
107b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	if (flags & SPI_QE_CPU_MODE) {
108b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		return "QE CPU";
109b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	} else if (flags & SPI_CPM_MODE) {
110b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		if (flags & SPI_QE)
111b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu			return "QE";
112b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		else if (flags & SPI_CPM2)
113b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu			return "CPM2";
114b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		else
115b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu			return "CPM1";
116b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	}
117b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	return "CPU";
118b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu}
119b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
120b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Huint mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
121b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu			unsigned int irq)
122b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu{
123b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	struct fsl_spi_platform_data *pdata = dev->platform_data;
124b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	struct spi_master *master;
125b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	struct mpc8xxx_spi *mpc8xxx_spi;
126b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	int ret = 0;
127b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
128b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	master = dev_get_drvdata(dev);
129b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
130b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	/* the spi->mode bits understood by this driver: */
131b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
132b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu			| SPI_LSB_FIRST | SPI_LOOP;
133b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
134b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	master->transfer = mpc8xxx_spi_transfer;
135b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	master->cleanup = mpc8xxx_spi_cleanup;
136b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	master->dev.of_node = dev->of_node;
137b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
138b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	mpc8xxx_spi = spi_master_get_devdata(master);
139b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	mpc8xxx_spi->dev = dev;
140b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
141b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
142b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	mpc8xxx_spi->flags = pdata->flags;
143b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	mpc8xxx_spi->spibrg = pdata->sysclk;
144b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	mpc8xxx_spi->irq = irq;
145b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
146b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	mpc8xxx_spi->rx_shift = 0;
147b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	mpc8xxx_spi->tx_shift = 0;
148b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
149b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	init_completion(&mpc8xxx_spi->done);
150b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
151b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	master->bus_num = pdata->bus_num;
152b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	master->num_chipselect = pdata->max_chipselect;
153b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
154b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	spin_lock_init(&mpc8xxx_spi->lock);
155b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	init_completion(&mpc8xxx_spi->done);
156b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work);
157b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	INIT_LIST_HEAD(&mpc8xxx_spi->queue);
158b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
159b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	mpc8xxx_spi->workqueue = create_singlethread_workqueue(
160b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		dev_name(master->dev.parent));
161b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	if (mpc8xxx_spi->workqueue == NULL) {
162b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		ret = -EBUSY;
163b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		goto err;
164b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	}
165b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
166b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	return 0;
167b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
168b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Huerr:
169b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	return ret;
170b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu}
171b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
172b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Huint __devexit mpc8xxx_spi_remove(struct device *dev)
173b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu{
174b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	struct mpc8xxx_spi *mpc8xxx_spi;
175b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	struct spi_master *master;
176b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
177b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	master = dev_get_drvdata(dev);
178b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	mpc8xxx_spi = spi_master_get_devdata(master);
179b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
180b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	flush_workqueue(mpc8xxx_spi->workqueue);
181b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	destroy_workqueue(mpc8xxx_spi->workqueue);
182b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	spi_unregister_master(master);
183b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
184b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
185b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
186b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	if (mpc8xxx_spi->spi_remove)
187b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		mpc8xxx_spi->spi_remove(mpc8xxx_spi);
188b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
189b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	return 0;
190b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu}
191b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
19218d306d1375696b0e6b5b39e4744d7fa2ad5e170Grant Likelyint __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev)
193b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu{
194b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	struct device *dev = &ofdev->dev;
195b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	struct device_node *np = ofdev->dev.of_node;
196b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	struct mpc8xxx_spi_probe_info *pinfo;
197b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	struct fsl_spi_platform_data *pdata;
198b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	const void *prop;
199b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	int ret = -ENOMEM;
200b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
201b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
202b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	if (!pinfo)
203b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		return -ENOMEM;
204b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
205b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	pdata = &pinfo->pdata;
206b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	dev->platform_data = pdata;
207b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
208b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	/* Allocate bus num dynamically. */
209b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	pdata->bus_num = -1;
210b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
211b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	/* SPI controller is either clocked from QE or SoC clock. */
212b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	pdata->sysclk = get_brgfreq();
213b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	if (pdata->sysclk == -1) {
214b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		pdata->sysclk = fsl_get_sys_freq();
215b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		if (pdata->sysclk == -1) {
216b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu			ret = -ENODEV;
217b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu			goto err;
218b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		}
219b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	}
220b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
221b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	prop = of_get_property(np, "mode", NULL);
222b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	if (prop && !strcmp(prop, "cpu-qe"))
223b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		pdata->flags = SPI_QE_CPU_MODE;
224b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	else if (prop && !strcmp(prop, "qe"))
225b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		pdata->flags = SPI_CPM_MODE | SPI_QE;
226b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	else if (of_device_is_compatible(np, "fsl,cpm2-spi"))
227b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		pdata->flags = SPI_CPM_MODE | SPI_CPM2;
228b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	else if (of_device_is_compatible(np, "fsl,cpm1-spi"))
229b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu		pdata->flags = SPI_CPM_MODE | SPI_CPM1;
230b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
231b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	return 0;
232b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu
233b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Huerr:
234b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	kfree(pinfo);
235b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu	return ret;
236b36ece832512c1a0afa54ff0a56d63492a1caf08Mingkai Hu}
237