aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2011-03-15 11:41:15 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-03-15 11:41:26 -0400
commit9b963f32c38b4c7d2da667e4458967b550f30bee (patch)
treebe4ed36669fe831fe0d5feaddcc8dfb39809e32e
parent4c4070a3097fe9ef57af9ebca6f57a2c57bc6ff1 (diff)
parent60d97a840175d3becb2e6de36537a5cdfc0ec3a9 (diff)
Merge branch 'davinci-next-2' of git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci into devel-stable
-rw-r--r--arch/arm/mach-davinci/board-dm644x-evm.c8
-rw-r--r--arch/arm/mach-davinci/board-tnetv107x-evm.c57
-rw-r--r--arch/arm/mach-davinci/devices-tnetv107x.c25
-rw-r--r--arch/arm/mach-davinci/include/mach/tnetv107x.h2
-rw-r--r--arch/arm/mach-davinci/tnetv107x.c2
-rw-r--r--drivers/mfd/Kconfig11
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/ti-ssp.c476
-rw-r--r--drivers/spi/Kconfig10
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/ti-ssp-spi.c402
-rw-r--r--include/linux/mfd/ti_ssp.h93
12 files changed, 1082 insertions, 6 deletions
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
index 0ca90b834586..556bbd468db3 100644
--- a/arch/arm/mach-davinci/board-dm644x-evm.c
+++ b/arch/arm/mach-davinci/board-dm644x-evm.c
@@ -440,11 +440,6 @@ evm_u35_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
440 gpio_request(gpio + 7, "nCF_SEL"); 440 gpio_request(gpio + 7, "nCF_SEL");
441 gpio_direction_output(gpio + 7, 1); 441 gpio_direction_output(gpio + 7, 1);
442 442
443 /* irlml6401 switches over 1A, in under 8 msec;
444 * now it can be managed by nDRV_VBUS ...
445 */
446 davinci_setup_usb(1000, 8);
447
448 return 0; 443 return 0;
449} 444}
450 445
@@ -705,6 +700,9 @@ static __init void davinci_evm_init(void)
705 davinci_serial_init(&uart_config); 700 davinci_serial_init(&uart_config);
706 dm644x_init_asp(&dm644x_evm_snd_data); 701 dm644x_init_asp(&dm644x_evm_snd_data);
707 702
703 /* irlml6401 switches over 1A, in under 8 msec */
704 davinci_setup_usb(1000, 8);
705
708 soc_info->emac_pdata->phy_id = DM644X_EVM_PHY_ID; 706 soc_info->emac_pdata->phy_id = DM644X_EVM_PHY_ID;
709 /* Register the fixup for PHY on DaVinci */ 707 /* Register the fixup for PHY on DaVinci */
710 phy_register_fixup_for_uid(LXT971_PHY_ID, LXT971_PHY_MASK, 708 phy_register_fixup_for_uid(LXT971_PHY_ID, LXT971_PHY_MASK,
diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
index a6db85460227..1a656e882262 100644
--- a/arch/arm/mach-davinci/board-tnetv107x-evm.c
+++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c
@@ -25,6 +25,7 @@
25#include <linux/mtd/partitions.h> 25#include <linux/mtd/partitions.h>
26#include <linux/input.h> 26#include <linux/input.h>
27#include <linux/input/matrix_keypad.h> 27#include <linux/input/matrix_keypad.h>
28#include <linux/spi/spi.h>
28 29
29#include <asm/mach/arch.h> 30#include <asm/mach/arch.h>
30#include <asm/mach-types.h> 31#include <asm/mach-types.h>
@@ -37,6 +38,7 @@
37 38
38#define EVM_MMC_WP_GPIO 21 39#define EVM_MMC_WP_GPIO 21
39#define EVM_MMC_CD_GPIO 24 40#define EVM_MMC_CD_GPIO 24
41#define EVM_SPI_CS_GPIO 54
40 42
41static int initialize_gpio(int gpio, char *desc) 43static int initialize_gpio(int gpio, char *desc)
42{ 44{
@@ -99,6 +101,12 @@ static const short uart1_pins[] __initdata = {
99 -1 101 -1
100}; 102};
101 103
104static const short ssp_pins[] __initdata = {
105 TNETV107X_SSP0_0, TNETV107X_SSP0_1, TNETV107X_SSP0_2,
106 TNETV107X_SSP1_0, TNETV107X_SSP1_1, TNETV107X_SSP1_2,
107 TNETV107X_SSP1_3, -1
108};
109
102static struct mtd_partition nand_partitions[] = { 110static struct mtd_partition nand_partitions[] = {
103 /* bootloader (U-Boot, etc) in first 12 sectors */ 111 /* bootloader (U-Boot, etc) in first 12 sectors */
104 { 112 {
@@ -196,19 +204,68 @@ static struct matrix_keypad_platform_data keypad_config = {
196 .no_autorepeat = 0, 204 .no_autorepeat = 0,
197}; 205};
198 206
207static void spi_select_device(int cs)
208{
209 static int gpio;
210
211 if (!gpio) {
212 int ret;
213 ret = gpio_request(EVM_SPI_CS_GPIO, "spi chipsel");
214 if (ret < 0) {
215 pr_err("cannot open spi chipsel gpio\n");
216 gpio = -ENOSYS;
217 return;
218 } else {
219 gpio = EVM_SPI_CS_GPIO;
220 gpio_direction_output(gpio, 0);
221 }
222 }
223
224 if (gpio < 0)
225 return;
226
227 return gpio_set_value(gpio, cs ? 1 : 0);
228}
229
230static struct ti_ssp_spi_data spi_master_data = {
231 .num_cs = 2,
232 .select = spi_select_device,
233 .iosel = SSP_PIN_SEL(0, SSP_CLOCK) | SSP_PIN_SEL(1, SSP_DATA) |
234 SSP_PIN_SEL(2, SSP_CHIPSEL) | SSP_PIN_SEL(3, SSP_IN) |
235 SSP_INPUT_SEL(3),
236};
237
238static struct ti_ssp_data ssp_config = {
239 .out_clock = 250 * 1000,
240 .dev_data = {
241 [1] = {
242 .dev_name = "ti-ssp-spi",
243 .pdata = &spi_master_data,
244 .pdata_size = sizeof(spi_master_data),
245 },
246 },
247};
248
199static struct tnetv107x_device_info evm_device_info __initconst = { 249static struct tnetv107x_device_info evm_device_info __initconst = {
200 .serial_config = &serial_config, 250 .serial_config = &serial_config,
201 .mmc_config[1] = &mmc_config, /* controller 1 */ 251 .mmc_config[1] = &mmc_config, /* controller 1 */
202 .nand_config[0] = &nand_config, /* chip select 0 */ 252 .nand_config[0] = &nand_config, /* chip select 0 */
203 .keypad_config = &keypad_config, 253 .keypad_config = &keypad_config,
254 .ssp_config = &ssp_config,
255};
256
257static struct spi_board_info spi_info[] __initconst = {
204}; 258};
205 259
206static __init void tnetv107x_evm_board_init(void) 260static __init void tnetv107x_evm_board_init(void)
207{ 261{
208 davinci_cfg_reg_list(sdio1_pins); 262 davinci_cfg_reg_list(sdio1_pins);
209 davinci_cfg_reg_list(uart1_pins); 263 davinci_cfg_reg_list(uart1_pins);
264 davinci_cfg_reg_list(ssp_pins);
210 265
211 tnetv107x_devices_init(&evm_device_info); 266 tnetv107x_devices_init(&evm_device_info);
267
268 spi_register_board_info(spi_info, ARRAY_SIZE(spi_info));
212} 269}
213 270
214#ifdef CONFIG_SERIAL_8250_CONSOLE 271#ifdef CONFIG_SERIAL_8250_CONSOLE
diff --git a/arch/arm/mach-davinci/devices-tnetv107x.c b/arch/arm/mach-davinci/devices-tnetv107x.c
index 85503debda51..6162cae7f868 100644
--- a/arch/arm/mach-davinci/devices-tnetv107x.c
+++ b/arch/arm/mach-davinci/devices-tnetv107x.c
@@ -35,6 +35,7 @@
35#define TNETV107X_SDIO0_BASE 0x08088700 35#define TNETV107X_SDIO0_BASE 0x08088700
36#define TNETV107X_SDIO1_BASE 0x08088800 36#define TNETV107X_SDIO1_BASE 0x08088800
37#define TNETV107X_KEYPAD_BASE 0x08088a00 37#define TNETV107X_KEYPAD_BASE 0x08088a00
38#define TNETV107X_SSP_BASE 0x08088c00
38#define TNETV107X_ASYNC_EMIF_CNTRL_BASE 0x08200000 39#define TNETV107X_ASYNC_EMIF_CNTRL_BASE 0x08200000
39#define TNETV107X_ASYNC_EMIF_DATA_CE0_BASE 0x30000000 40#define TNETV107X_ASYNC_EMIF_DATA_CE0_BASE 0x30000000
40#define TNETV107X_ASYNC_EMIF_DATA_CE1_BASE 0x40000000 41#define TNETV107X_ASYNC_EMIF_DATA_CE1_BASE 0x40000000
@@ -342,6 +343,25 @@ static struct platform_device tsc_device = {
342 .resource = tsc_resources, 343 .resource = tsc_resources,
343}; 344};
344 345
346static struct resource ssp_resources[] = {
347 {
348 .start = TNETV107X_SSP_BASE,
349 .end = TNETV107X_SSP_BASE + 0x1ff,
350 .flags = IORESOURCE_MEM,
351 },
352 {
353 .start = IRQ_TNETV107X_SSP,
354 .flags = IORESOURCE_IRQ,
355 },
356};
357
358static struct platform_device ssp_device = {
359 .name = "ti-ssp",
360 .id = -1,
361 .num_resources = ARRAY_SIZE(ssp_resources),
362 .resource = ssp_resources,
363};
364
345void __init tnetv107x_devices_init(struct tnetv107x_device_info *info) 365void __init tnetv107x_devices_init(struct tnetv107x_device_info *info)
346{ 366{
347 int i, error; 367 int i, error;
@@ -380,4 +400,9 @@ void __init tnetv107x_devices_init(struct tnetv107x_device_info *info)
380 keypad_device.dev.platform_data = info->keypad_config; 400 keypad_device.dev.platform_data = info->keypad_config;
381 platform_device_register(&keypad_device); 401 platform_device_register(&keypad_device);
382 } 402 }
403
404 if (info->ssp_config) {
405 ssp_device.dev.platform_data = info->ssp_config;
406 platform_device_register(&ssp_device);
407 }
383} 408}
diff --git a/arch/arm/mach-davinci/include/mach/tnetv107x.h b/arch/arm/mach-davinci/include/mach/tnetv107x.h
index 5a681d880dcb..89c1fdc63c0b 100644
--- a/arch/arm/mach-davinci/include/mach/tnetv107x.h
+++ b/arch/arm/mach-davinci/include/mach/tnetv107x.h
@@ -34,6 +34,7 @@
34 34
35#include <linux/serial_8250.h> 35#include <linux/serial_8250.h>
36#include <linux/input/matrix_keypad.h> 36#include <linux/input/matrix_keypad.h>
37#include <linux/mfd/ti_ssp.h>
37 38
38#include <mach/mmc.h> 39#include <mach/mmc.h>
39#include <mach/nand.h> 40#include <mach/nand.h>
@@ -44,6 +45,7 @@ struct tnetv107x_device_info {
44 struct davinci_mmc_config *mmc_config[2]; /* 2 controllers */ 45 struct davinci_mmc_config *mmc_config[2]; /* 2 controllers */
45 struct davinci_nand_pdata *nand_config[4]; /* 4 chipsels */ 46 struct davinci_nand_pdata *nand_config[4]; /* 4 chipsels */
46 struct matrix_keypad_platform_data *keypad_config; 47 struct matrix_keypad_platform_data *keypad_config;
48 struct ti_ssp_data *ssp_config;
47}; 49};
48 50
49extern struct platform_device tnetv107x_wdt_device; 51extern struct platform_device tnetv107x_wdt_device;
diff --git a/arch/arm/mach-davinci/tnetv107x.c b/arch/arm/mach-davinci/tnetv107x.c
index 6fcdecec8d8c..1b28fdd892a6 100644
--- a/arch/arm/mach-davinci/tnetv107x.c
+++ b/arch/arm/mach-davinci/tnetv107x.c
@@ -278,7 +278,7 @@ static struct clk_lookup clks[] = {
278 CLK(NULL, "timer1", &clk_timer1), 278 CLK(NULL, "timer1", &clk_timer1),
279 CLK("tnetv107x_wdt.0", NULL, &clk_wdt_arm), 279 CLK("tnetv107x_wdt.0", NULL, &clk_wdt_arm),
280 CLK(NULL, "clk_wdt_dsp", &clk_wdt_dsp), 280 CLK(NULL, "clk_wdt_dsp", &clk_wdt_dsp),
281 CLK("ti-ssp.0", NULL, &clk_ssp), 281 CLK("ti-ssp", NULL, &clk_ssp),
282 CLK(NULL, "clk_tdm0", &clk_tdm0), 282 CLK(NULL, "clk_tdm0", &clk_tdm0),
283 CLK(NULL, "clk_vlynq", &clk_vlynq), 283 CLK(NULL, "clk_vlynq", &clk_vlynq),
284 CLK(NULL, "clk_mcdma", &clk_mcdma), 284 CLK(NULL, "clk_mcdma", &clk_mcdma),
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index fd018366d670..0284c53c210c 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -81,6 +81,17 @@ config MFD_DM355EVM_MSP
81 boards. MSP430 firmware manages resets and power sequencing, 81 boards. MSP430 firmware manages resets and power sequencing,
82 inputs from buttons and the IR remote, LEDs, an RTC, and more. 82 inputs from buttons and the IR remote, LEDs, an RTC, and more.
83 83
84config MFD_TI_SSP
85 tristate "TI Sequencer Serial Port support"
86 depends on ARCH_DAVINCI_TNETV107X
87 select MFD_CORE
88 ---help---
89 Say Y here if you want support for the Sequencer Serial Port
90 in a Texas Instruments TNETV107X SoC.
91
92 To compile this driver as a module, choose M here: the
93 module will be called ti-ssp.
94
84config HTC_EGPIO 95config HTC_EGPIO
85 bool "HTC EGPIO support" 96 bool "HTC EGPIO support"
86 depends on GENERIC_HARDIRQS && GPIOLIB && ARM 97 depends on GENERIC_HARDIRQS && GPIOLIB && ARM
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index a54e2c7c6a1c..c56b6c7232ed 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o
14 14
15obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o 15obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o
16obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o 16obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
17obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o
17 18
18obj-$(CONFIG_MFD_STMPE) += stmpe.o 19obj-$(CONFIG_MFD_STMPE) += stmpe.o
19obj-$(CONFIG_MFD_TC3589X) += tc3589x.o 20obj-$(CONFIG_MFD_TC3589X) += tc3589x.o
diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c
new file mode 100644
index 000000000000..af9ab0e5ca64
--- /dev/null
+++ b/drivers/mfd/ti-ssp.c
@@ -0,0 +1,476 @@
1/*
2 * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs
3 *
4 * Copyright (C) 2010 Texas Instruments Inc
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <linux/errno.h>
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/slab.h>
25#include <linux/err.h>
26#include <linux/init.h>
27#include <linux/wait.h>
28#include <linux/clk.h>
29#include <linux/interrupt.h>
30#include <linux/device.h>
31#include <linux/spinlock.h>
32#include <linux/platform_device.h>
33#include <linux/delay.h>
34#include <linux/io.h>
35#include <linux/mfd/core.h>
36#include <linux/mfd/ti_ssp.h>
37
38/* Register Offsets */
39#define REG_REV 0x00
40#define REG_IOSEL_1 0x04
41#define REG_IOSEL_2 0x08
42#define REG_PREDIV 0x0c
43#define REG_INTR_ST 0x10
44#define REG_INTR_EN 0x14
45#define REG_TEST_CTRL 0x18
46
47/* Per port registers */
48#define PORT_CFG_2 0x00
49#define PORT_ADDR 0x04
50#define PORT_DATA 0x08
51#define PORT_CFG_1 0x0c
52#define PORT_STATE 0x10
53
54#define SSP_PORT_CONFIG_MASK (SSP_EARLY_DIN | SSP_DELAY_DOUT)
55#define SSP_PORT_CLKRATE_MASK 0x0f
56
57#define SSP_SEQRAM_WR_EN BIT(4)
58#define SSP_SEQRAM_RD_EN BIT(5)
59#define SSP_START BIT(15)
60#define SSP_BUSY BIT(10)
61#define SSP_PORT_ASL BIT(7)
62#define SSP_PORT_CFO1 BIT(6)
63
64#define SSP_PORT_SEQRAM_SIZE 32
65
66static const int ssp_port_base[] = {0x040, 0x080};
67static const int ssp_port_seqram[] = {0x100, 0x180};
68
69struct ti_ssp {
70 struct resource *res;
71 struct device *dev;
72 void __iomem *regs;
73 spinlock_t lock;
74 struct clk *clk;
75 int irq;
76 wait_queue_head_t wqh;
77
78 /*
79 * Some of the iosel2 register bits always read-back as 0, we need to
80 * remember these values so that we don't clobber previously set
81 * values.
82 */
83 u32 iosel2;
84};
85
86static inline struct ti_ssp *dev_to_ssp(struct device *dev)
87{
88 return dev_get_drvdata(dev->parent);
89}
90
91static inline int dev_to_port(struct device *dev)
92{
93 return to_platform_device(dev)->id;
94}
95
96/* Register Access Helpers, rmw() functions need to run locked */
97static inline u32 ssp_read(struct ti_ssp *ssp, int reg)
98{
99 return __raw_readl(ssp->regs + reg);
100}
101
102static inline void ssp_write(struct ti_ssp *ssp, int reg, u32 val)
103{
104 __raw_writel(val, ssp->regs + reg);
105}
106
107static inline void ssp_rmw(struct ti_ssp *ssp, int reg, u32 mask, u32 bits)
108{
109 ssp_write(ssp, reg, (ssp_read(ssp, reg) & ~mask) | bits);
110}
111
112static inline u32 ssp_port_read(struct ti_ssp *ssp, int port, int reg)
113{
114 return ssp_read(ssp, ssp_port_base[port] + reg);
115}
116
117static inline void ssp_port_write(struct ti_ssp *ssp, int port, int reg,
118 u32 val)
119{
120 ssp_write(ssp, ssp_port_base[port] + reg, val);
121}
122
123static inline void ssp_port_rmw(struct ti_ssp *ssp, int port, int reg,
124 u32 mask, u32 bits)
125{
126 ssp_rmw(ssp, ssp_port_base[port] + reg, mask, bits);
127}
128
129static inline void ssp_port_clr_bits(struct ti_ssp *ssp, int port, int reg,
130 u32 bits)
131{
132 ssp_port_rmw(ssp, port, reg, bits, 0);
133}
134
135static inline void ssp_port_set_bits(struct ti_ssp *ssp, int port, int reg,
136 u32 bits)
137{
138 ssp_port_rmw(ssp, port, reg, 0, bits);
139}
140
141/* Called to setup port clock mode, caller must hold ssp->lock */
142static int __set_mode(struct ti_ssp *ssp, int port, int mode)
143{
144 mode &= SSP_PORT_CONFIG_MASK;
145 ssp_port_rmw(ssp, port, PORT_CFG_1, SSP_PORT_CONFIG_MASK, mode);
146
147 return 0;
148}
149
150int ti_ssp_set_mode(struct device *dev, int mode)
151{
152 struct ti_ssp *ssp = dev_to_ssp(dev);
153 int port = dev_to_port(dev);
154 int ret;
155
156 spin_lock(&ssp->lock);
157 ret = __set_mode(ssp, port, mode);
158 spin_unlock(&ssp->lock);
159
160 return ret;
161}
162EXPORT_SYMBOL(ti_ssp_set_mode);
163
164/* Called to setup iosel2, caller must hold ssp->lock */
165static void __set_iosel2(struct ti_ssp *ssp, u32 mask, u32 val)
166{
167 ssp->iosel2 = (ssp->iosel2 & ~mask) | val;
168 ssp_write(ssp, REG_IOSEL_2, ssp->iosel2);
169}
170
171/* Called to setup port iosel, caller must hold ssp->lock */
172static void __set_iosel(struct ti_ssp *ssp, int port, u32 iosel)
173{
174 unsigned val, shift = port ? 16 : 0;
175
176 /* IOSEL1 gets the least significant 16 bits */
177 val = ssp_read(ssp, REG_IOSEL_1);
178 val &= 0xffff << (port ? 0 : 16);
179 val |= (iosel & 0xffff) << (port ? 16 : 0);
180 ssp_write(ssp, REG_IOSEL_1, val);
181
182 /* IOSEL2 gets the most significant 16 bits */
183 val = (iosel >> 16) & 0x7;
184 __set_iosel2(ssp, 0x7 << shift, val << shift);
185}
186
187int ti_ssp_set_iosel(struct device *dev, u32 iosel)
188{
189 struct ti_ssp *ssp = dev_to_ssp(dev);
190 int port = dev_to_port(dev);
191
192 spin_lock(&ssp->lock);
193 __set_iosel(ssp, port, iosel);
194 spin_unlock(&ssp->lock);
195
196 return 0;
197}
198EXPORT_SYMBOL(ti_ssp_set_iosel);
199
200int ti_ssp_load(struct device *dev, int offs, u32* prog, int len)
201{
202 struct ti_ssp *ssp = dev_to_ssp(dev);
203 int port = dev_to_port(dev);
204 int i;
205
206 if (len > SSP_PORT_SEQRAM_SIZE)
207 return -ENOSPC;
208
209 spin_lock(&ssp->lock);
210
211 /* Enable SeqRAM access */
212 ssp_port_set_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
213
214 /* Copy code */
215 for (i = 0; i < len; i++) {
216 __raw_writel(prog[i], ssp->regs + offs + 4*i +
217 ssp_port_seqram[port]);
218 }
219
220 /* Disable SeqRAM access */
221 ssp_port_clr_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
222
223 spin_unlock(&ssp->lock);
224
225 return 0;
226}
227EXPORT_SYMBOL(ti_ssp_load);
228
229int ti_ssp_raw_read(struct device *dev)
230{
231 struct ti_ssp *ssp = dev_to_ssp(dev);
232 int port = dev_to_port(dev);
233 int shift = port ? 27 : 11;
234
235 return (ssp_read(ssp, REG_IOSEL_2) >> shift) & 0xf;
236}
237EXPORT_SYMBOL(ti_ssp_raw_read);
238
239int ti_ssp_raw_write(struct device *dev, u32 val)
240{
241 struct ti_ssp *ssp = dev_to_ssp(dev);
242 int port = dev_to_port(dev), shift;
243
244 spin_lock(&ssp->lock);
245
246 shift = port ? 22 : 6;
247 val &= 0xf;
248 __set_iosel2(ssp, 0xf << shift, val << shift);
249
250 spin_unlock(&ssp->lock);
251
252 return 0;
253}
254EXPORT_SYMBOL(ti_ssp_raw_write);
255
256static inline int __xfer_done(struct ti_ssp *ssp, int port)
257{
258 return !(ssp_port_read(ssp, port, PORT_CFG_1) & SSP_BUSY);
259}
260
261int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output)
262{
263 struct ti_ssp *ssp = dev_to_ssp(dev);
264 int port = dev_to_port(dev);
265 int ret;
266
267 if (pc & ~(0x3f))
268 return -EINVAL;
269
270 /* Grab ssp->lock to serialize rmw on ssp registers */
271 spin_lock(&ssp->lock);
272
273 ssp_port_write(ssp, port, PORT_ADDR, input >> 16);
274 ssp_port_write(ssp, port, PORT_DATA, input & 0xffff);
275 ssp_port_rmw(ssp, port, PORT_CFG_1, 0x3f, pc);
276
277 /* grab wait queue head lock to avoid race with the isr */
278 spin_lock_irq(&ssp->wqh.lock);
279
280 /* kick off sequence execution in hardware */
281 ssp_port_set_bits(ssp, port, PORT_CFG_1, SSP_START);
282
283 /* drop ssp lock; no register writes beyond this */
284 spin_unlock(&ssp->lock);
285
286 ret = wait_event_interruptible_locked_irq(ssp->wqh,
287 __xfer_done(ssp, port));
288 spin_unlock_irq(&ssp->wqh.lock);
289
290 if (ret < 0)
291 return ret;
292
293 if (output) {
294 *output = (ssp_port_read(ssp, port, PORT_ADDR) << 16) |
295 (ssp_port_read(ssp, port, PORT_DATA) & 0xffff);
296 }
297
298 ret = ssp_port_read(ssp, port, PORT_STATE) & 0x3f; /* stop address */
299
300 return ret;
301}
302EXPORT_SYMBOL(ti_ssp_run);
303
304static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data)
305{
306 struct ti_ssp *ssp = dev_data;
307
308 spin_lock(&ssp->wqh.lock);
309
310 ssp_write(ssp, REG_INTR_ST, 0x3);
311 wake_up_locked(&ssp->wqh);
312
313 spin_unlock(&ssp->wqh.lock);
314
315 return IRQ_HANDLED;
316}
317
318static int __devinit ti_ssp_probe(struct platform_device *pdev)
319{
320 static struct ti_ssp *ssp;
321 const struct ti_ssp_data *pdata = pdev->dev.platform_data;
322 int error = 0, prediv = 0xff, id;
323 unsigned long sysclk;
324 struct device *dev = &pdev->dev;
325 struct mfd_cell cells[2];
326
327 ssp = kzalloc(sizeof(*ssp), GFP_KERNEL);
328 if (!ssp) {
329 dev_err(dev, "cannot allocate device info\n");
330 return -ENOMEM;
331 }
332
333 ssp->dev = dev;
334 dev_set_drvdata(dev, ssp);
335
336 ssp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
337 if (!ssp->res) {
338 error = -ENODEV;
339 dev_err(dev, "cannot determine register area\n");
340 goto error_res;
341 }
342
343 if (!request_mem_region(ssp->res->start, resource_size(ssp->res),
344 pdev->name)) {
345 error = -ENOMEM;
346 dev_err(dev, "cannot claim register memory\n");
347 goto error_res;
348 }
349
350 ssp->regs = ioremap(ssp->res->start, resource_size(ssp->res));
351 if (!ssp->regs) {
352 error = -ENOMEM;
353 dev_err(dev, "cannot map register memory\n");
354 goto error_map;
355 }
356
357 ssp->clk = clk_get(dev, NULL);
358 if (IS_ERR(ssp->clk)) {
359 error = PTR_ERR(ssp->clk);
360 dev_err(dev, "cannot claim device clock\n");
361 goto error_clk;
362 }
363
364 ssp->irq = platform_get_irq(pdev, 0);
365 if (ssp->irq < 0) {
366 error = -ENODEV;
367 dev_err(dev, "unknown irq\n");
368 goto error_irq;
369 }
370
371 error = request_threaded_irq(ssp->irq, NULL, ti_ssp_interrupt, 0,
372 dev_name(dev), ssp);
373 if (error < 0) {
374 dev_err(dev, "cannot acquire irq\n");
375 goto error_irq;
376 }
377
378 spin_lock_init(&ssp->lock);
379 init_waitqueue_head(&ssp->wqh);
380
381 /* Power on and initialize SSP */
382 error = clk_enable(ssp->clk);
383 if (error) {
384 dev_err(dev, "cannot enable device clock\n");
385 goto error_enable;
386 }
387
388 /* Reset registers to a sensible known state */
389 ssp_write(ssp, REG_IOSEL_1, 0);
390 ssp_write(ssp, REG_IOSEL_2, 0);
391 ssp_write(ssp, REG_INTR_EN, 0x3);
392 ssp_write(ssp, REG_INTR_ST, 0x3);
393 ssp_write(ssp, REG_TEST_CTRL, 0);
394 ssp_port_write(ssp, 0, PORT_CFG_1, SSP_PORT_ASL);
395 ssp_port_write(ssp, 1, PORT_CFG_1, SSP_PORT_ASL);
396 ssp_port_write(ssp, 0, PORT_CFG_2, SSP_PORT_CFO1);
397 ssp_port_write(ssp, 1, PORT_CFG_2, SSP_PORT_CFO1);
398
399 sysclk = clk_get_rate(ssp->clk);
400 if (pdata && pdata->out_clock)
401 prediv = (sysclk / pdata->out_clock) - 1;
402 prediv = clamp(prediv, 0, 0xff);
403 ssp_rmw(ssp, REG_PREDIV, 0xff, prediv);
404
405 memset(cells, 0, sizeof(cells));
406 for (id = 0; id < 2; id++) {
407 const struct ti_ssp_dev_data *data = &pdata->dev_data[id];
408
409 cells[id].id = id;
410 cells[id].name = data->dev_name;
411 cells[id].platform_data = data->pdata;
412 cells[id].data_size = data->pdata_size;
413 }
414
415 error = mfd_add_devices(dev, 0, cells, 2, NULL, 0);
416 if (error < 0) {
417 dev_err(dev, "cannot add mfd cells\n");
418 goto error_enable;
419 }
420
421 return 0;
422
423error_enable:
424 free_irq(ssp->irq, ssp);
425error_irq:
426 clk_put(ssp->clk);
427error_clk:
428 iounmap(ssp->regs);
429error_map:
430 release_mem_region(ssp->res->start, resource_size(ssp->res));
431error_res:
432 kfree(ssp);
433 return error;
434}
435
436static int __devexit ti_ssp_remove(struct platform_device *pdev)
437{
438 struct device *dev = &pdev->dev;
439 struct ti_ssp *ssp = dev_get_drvdata(dev);
440
441 mfd_remove_devices(dev);
442 clk_disable(ssp->clk);
443 free_irq(ssp->irq, ssp);
444 clk_put(ssp->clk);
445 iounmap(ssp->regs);
446 release_mem_region(ssp->res->start, resource_size(ssp->res));
447 kfree(ssp);
448 dev_set_drvdata(dev, NULL);
449 return 0;
450}
451
452static struct platform_driver ti_ssp_driver = {
453 .probe = ti_ssp_probe,
454 .remove = __devexit_p(ti_ssp_remove),
455 .driver = {
456 .name = "ti-ssp",
457 .owner = THIS_MODULE,
458 }
459};
460
461static int __init ti_ssp_init(void)
462{
463 return platform_driver_register(&ti_ssp_driver);
464}
465module_init(ti_ssp_init);
466
467static void __exit ti_ssp_exit(void)
468{
469 platform_driver_unregister(&ti_ssp_driver);
470}
471module_exit(ti_ssp_exit);
472
473MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver");
474MODULE_AUTHOR("Cyril Chemparathy");
475MODULE_LICENSE("GPL");
476MODULE_ALIAS("platform:ti-ssp");
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 996cf0359385..7b90fc361b52 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -350,6 +350,16 @@ config SPI_TEGRA
350 help 350 help
351 SPI driver for NVidia Tegra SoCs 351 SPI driver for NVidia Tegra SoCs
352 352
353config SPI_TI_SSP
354 tristate "TI Sequencer Serial Port - SPI Support"
355 depends on MFD_TI_SSP
356 help
357 This selects an SPI master implementation using a TI sequencer
358 serial port.
359
360 To compile this driver as a module, choose M here: the
361 module will be called ti-ssp-spi.
362
353config SPI_TOPCLIFF_PCH 363config SPI_TOPCLIFF_PCH
354 tristate "Topcliff PCH SPI Controller" 364 tristate "Topcliff PCH SPI Controller"
355 depends on PCI 365 depends on PCI
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 86d1b5f9bbd9..f3f31d988358 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
43obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx_hw.o 43obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx_hw.o
44obj-$(CONFIG_SPI_S3C64XX) += spi_s3c64xx.o 44obj-$(CONFIG_SPI_S3C64XX) += spi_s3c64xx.o
45obj-$(CONFIG_SPI_TEGRA) += spi_tegra.o 45obj-$(CONFIG_SPI_TEGRA) += spi_tegra.o
46obj-$(CONFIG_SPI_TI_SSP) += ti-ssp-spi.o
46obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi_topcliff_pch.o 47obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi_topcliff_pch.o
47obj-$(CONFIG_SPI_TXX9) += spi_txx9.o 48obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
48obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o 49obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
diff --git a/drivers/spi/ti-ssp-spi.c b/drivers/spi/ti-ssp-spi.c
new file mode 100644
index 000000000000..ee22795c7973
--- /dev/null
+++ b/drivers/spi/ti-ssp-spi.c
@@ -0,0 +1,402 @@
1/*
2 * Sequencer Serial Port (SSP) based SPI master driver
3 *
4 * Copyright (C) 2010 Texas Instruments Inc
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <linux/kernel.h>
22#include <linux/err.h>
23#include <linux/completion.h>
24#include <linux/delay.h>
25#include <linux/platform_device.h>
26#include <linux/spi/spi.h>
27#include <linux/mfd/ti_ssp.h>
28
29#define MODE_BITS (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
30
31struct ti_ssp_spi {
32 struct spi_master *master;
33 struct device *dev;
34 spinlock_t lock;
35 struct list_head msg_queue;
36 struct completion complete;
37 bool shutdown;
38 struct workqueue_struct *workqueue;
39 struct work_struct work;
40 u8 mode, bpw;
41 int cs_active;
42 u32 pc_en, pc_dis, pc_wr, pc_rd;
43 void (*select)(int cs);
44};
45
46static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw)
47{
48 u32 ret;
49
50 ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret);
51 return ret;
52}
53
54static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data)
55{
56 ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL);
57}
58
59static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg,
60 struct spi_transfer *t)
61{
62 int count;
63
64 if (hw->bpw <= 8) {
65 u8 *rx = t->rx_buf;
66 const u8 *tx = t->tx_buf;
67
68 for (count = 0; count < t->len; count += 1) {
69 if (t->tx_buf)
70 ti_ssp_spi_tx(hw, *tx++);
71 if (t->rx_buf)
72 *rx++ = ti_ssp_spi_rx(hw);
73 }
74 } else if (hw->bpw <= 16) {
75 u16 *rx = t->rx_buf;
76 const u16 *tx = t->tx_buf;
77
78 for (count = 0; count < t->len; count += 2) {
79 if (t->tx_buf)
80 ti_ssp_spi_tx(hw, *tx++);
81 if (t->rx_buf)
82 *rx++ = ti_ssp_spi_rx(hw);
83 }
84 } else {
85 u32 *rx = t->rx_buf;
86 const u32 *tx = t->tx_buf;
87
88 for (count = 0; count < t->len; count += 4) {
89 if (t->tx_buf)
90 ti_ssp_spi_tx(hw, *tx++);
91 if (t->rx_buf)
92 *rx++ = ti_ssp_spi_rx(hw);
93 }
94 }
95
96 msg->actual_length += count; /* bytes transferred */
97
98 dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n",
99 t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len,
100 hw->bpw, count, (count < t->len) ? " (under)" : "");
101
102 return (count < t->len) ? -EIO : 0; /* left over data */
103}
104
105static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active)
106{
107 cs_active = !!cs_active;
108 if (cs_active == hw->cs_active)
109 return;
110 ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL);
111 hw->cs_active = cs_active;
112}
113
114#define __SHIFT_OUT(bits) (SSP_OPCODE_SHIFT | SSP_OUT_MODE | \
115 cs_en | clk | SSP_COUNT((bits) * 2 - 1))
116#define __SHIFT_IN(bits) (SSP_OPCODE_SHIFT | SSP_IN_MODE | \
117 cs_en | clk | SSP_COUNT((bits) * 2 - 1))
118
119static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode)
120{
121 int error, idx = 0;
122 u32 seqram[16];
123 u32 cs_en, cs_dis, clk;
124 u32 topbits, botbits;
125
126 mode &= MODE_BITS;
127 if (mode == hw->mode && bpw == hw->bpw)
128 return 0;
129
130 cs_en = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW;
131 cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW : SSP_CS_HIGH;
132 clk = (mode & SPI_CPOL) ? SSP_CLK_HIGH : SSP_CLK_LOW;
133
134 /* Construct instructions */
135
136 /* Disable Chip Select */
137 hw->pc_dis = idx;
138 seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk;
139 seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_dis | clk;
140
141 /* Enable Chip Select */
142 hw->pc_en = idx;
143 seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk;
144 seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
145
146 /* Reads and writes need to be split for bpw > 16 */
147 topbits = (bpw > 16) ? 16 : bpw;
148 botbits = bpw - topbits;
149
150 /* Write */
151 hw->pc_wr = idx;
152 seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG;
153 if (botbits)
154 seqram[idx++] = __SHIFT_OUT(botbits) | SSP_DATA_REG;
155 seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
156
157 /* Read */
158 hw->pc_rd = idx;
159 if (botbits)
160 seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG;
161 seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG;
162 seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
163
164 error = ti_ssp_load(hw->dev, 0, seqram, idx);
165 if (error < 0)
166 return error;
167
168 error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ?
169 0 : SSP_EARLY_DIN));
170 if (error < 0)
171 return error;
172
173 hw->bpw = bpw;
174 hw->mode = mode;
175
176 return error;
177}
178
179static void ti_ssp_spi_work(struct work_struct *work)
180{
181 struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work);
182
183 spin_lock(&hw->lock);
184
185 while (!list_empty(&hw->msg_queue)) {
186 struct spi_message *m;
187 struct spi_device *spi;
188 struct spi_transfer *t = NULL;
189 int status = 0;
190
191 m = container_of(hw->msg_queue.next, struct spi_message,
192 queue);
193
194 list_del_init(&m->queue);
195
196 spin_unlock(&hw->lock);
197
198 spi = m->spi;
199
200 if (hw->select)
201 hw->select(spi->chip_select);
202
203 list_for_each_entry(t, &m->transfers, transfer_list) {
204 int bpw = spi->bits_per_word;
205 int xfer_status;
206
207 if (t->bits_per_word)
208 bpw = t->bits_per_word;
209
210 if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0)
211 break;
212
213 ti_ssp_spi_chip_select(hw, 1);
214
215 xfer_status = ti_ssp_spi_txrx(hw, m, t);
216 if (xfer_status < 0)
217 status = xfer_status;
218
219 if (t->delay_usecs)
220 udelay(t->delay_usecs);
221
222 if (t->cs_change)
223 ti_ssp_spi_chip_select(hw, 0);
224 }
225
226 ti_ssp_spi_chip_select(hw, 0);
227 m->status = status;
228 m->complete(m->context);
229
230 spin_lock(&hw->lock);
231 }
232
233 if (hw->shutdown)
234 complete(&hw->complete);
235
236 spin_unlock(&hw->lock);
237}
238
239static int ti_ssp_spi_setup(struct spi_device *spi)
240{
241 if (spi->bits_per_word > 32)
242 return -EINVAL;
243
244 return 0;
245}
246
247static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
248{
249 struct ti_ssp_spi *hw;
250 struct spi_transfer *t;
251 int error = 0;
252
253 m->actual_length = 0;
254 m->status = -EINPROGRESS;
255
256 hw = spi_master_get_devdata(spi->master);
257
258 if (list_empty(&m->transfers) || !m->complete)
259 return -EINVAL;
260
261 list_for_each_entry(t, &m->transfers, transfer_list) {
262 if (t->len && !(t->rx_buf || t->tx_buf)) {
263 dev_err(&spi->dev, "invalid xfer, no buffer\n");
264 return -EINVAL;
265 }
266
267 if (t->len && t->rx_buf && t->tx_buf) {
268 dev_err(&spi->dev, "invalid xfer, full duplex\n");
269 return -EINVAL;
270 }
271
272 if (t->bits_per_word > 32) {
273 dev_err(&spi->dev, "invalid xfer width %d\n",
274 t->bits_per_word);
275 return -EINVAL;
276 }
277 }
278
279 spin_lock(&hw->lock);
280 if (hw->shutdown) {
281 error = -ESHUTDOWN;
282 goto error_unlock;
283 }
284 list_add_tail(&m->queue, &hw->msg_queue);
285 queue_work(hw->workqueue, &hw->work);
286error_unlock:
287 spin_unlock(&hw->lock);
288 return error;
289}
290
291static int __devinit ti_ssp_spi_probe(struct platform_device *pdev)
292{
293 const struct ti_ssp_spi_data *pdata;
294 struct ti_ssp_spi *hw;
295 struct spi_master *master;
296 struct device *dev = &pdev->dev;
297 int error = 0;
298
299 pdata = dev->platform_data;
300 if (!pdata) {
301 dev_err(dev, "platform data not found\n");
302 return -EINVAL;
303 }
304
305 master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi));
306 if (!master) {
307 dev_err(dev, "cannot allocate SPI master\n");
308 return -ENOMEM;
309 }
310
311 hw = spi_master_get_devdata(master);
312 platform_set_drvdata(pdev, hw);
313
314 hw->master = master;
315 hw->dev = dev;
316 hw->select = pdata->select;
317
318 spin_lock_init(&hw->lock);
319 init_completion(&hw->complete);
320 INIT_LIST_HEAD(&hw->msg_queue);
321 INIT_WORK(&hw->work, ti_ssp_spi_work);
322
323 hw->workqueue = create_singlethread_workqueue(dev_name(dev));
324 if (!hw->workqueue) {
325 error = -ENOMEM;
326 dev_err(dev, "work queue creation failed\n");
327 goto error_wq;
328 }
329
330 error = ti_ssp_set_iosel(hw->dev, pdata->iosel);
331 if (error < 0) {
332 dev_err(dev, "io setup failed\n");
333 goto error_iosel;
334 }
335
336 master->bus_num = pdev->id;
337 master->num_chipselect = pdata->num_cs;
338 master->mode_bits = MODE_BITS;
339 master->flags = SPI_MASTER_HALF_DUPLEX;
340 master->setup = ti_ssp_spi_setup;
341 master->transfer = ti_ssp_spi_transfer;
342
343 error = spi_register_master(master);
344 if (error) {
345 dev_err(dev, "master registration failed\n");
346 goto error_reg;
347 }
348
349 return 0;
350
351error_reg:
352error_iosel:
353 destroy_workqueue(hw->workqueue);
354error_wq:
355 spi_master_put(master);
356 return error;
357}
358
359static int __devexit ti_ssp_spi_remove(struct platform_device *pdev)
360{
361 struct ti_ssp_spi *hw = platform_get_drvdata(pdev);
362 int error;
363
364 hw->shutdown = 1;
365 while (!list_empty(&hw->msg_queue)) {
366 error = wait_for_completion_interruptible(&hw->complete);
367 if (error < 0) {
368 hw->shutdown = 0;
369 return error;
370 }
371 }
372 destroy_workqueue(hw->workqueue);
373 spi_unregister_master(hw->master);
374
375 return 0;
376}
377
378static struct platform_driver ti_ssp_spi_driver = {
379 .probe = ti_ssp_spi_probe,
380 .remove = __devexit_p(ti_ssp_spi_remove),
381 .driver = {
382 .name = "ti-ssp-spi",
383 .owner = THIS_MODULE,
384 },
385};
386
387static int __init ti_ssp_spi_init(void)
388{
389 return platform_driver_register(&ti_ssp_spi_driver);
390}
391module_init(ti_ssp_spi_init);
392
393static void __exit ti_ssp_spi_exit(void)
394{
395 platform_driver_unregister(&ti_ssp_spi_driver);
396}
397module_exit(ti_ssp_spi_exit);
398
399MODULE_DESCRIPTION("SSP SPI Master");
400MODULE_AUTHOR("Cyril Chemparathy");
401MODULE_LICENSE("GPL");
402MODULE_ALIAS("platform:ti-ssp-spi");
diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h
new file mode 100644
index 000000000000..dbb4b43bd20e
--- /dev/null
+++ b/include/linux/mfd/ti_ssp.h
@@ -0,0 +1,93 @@
1/*
2 * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs
3 *
4 * Copyright (C) 2010 Texas Instruments Inc
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#ifndef __TI_SSP_H__
22#define __TI_SSP_H__
23
24struct ti_ssp_dev_data {
25 const char *dev_name;
26 void *pdata;
27 size_t pdata_size;
28};
29
30struct ti_ssp_data {
31 unsigned long out_clock;
32 struct ti_ssp_dev_data dev_data[2];
33};
34
35struct ti_ssp_spi_data {
36 unsigned long iosel;
37 int num_cs;
38 void (*select)(int cs);
39};
40
41/*
42 * Sequencer port IO pin configuration bits. These do not correlate 1-1 with
43 * the hardware. The iosel field in the port data combines iosel1 and iosel2,
44 * and is therefore not a direct map to register space. It is best to use the
45 * macros below to construct iosel values.
46 *
47 * least significant 16 bits --> iosel1
48 * most significant 16 bits --> iosel2
49 */
50
51#define SSP_IN 0x0000
52#define SSP_DATA 0x0001
53#define SSP_CLOCK 0x0002
54#define SSP_CHIPSEL 0x0003
55#define SSP_OUT 0x0004
56#define SSP_PIN_SEL(pin, v) ((v) << ((pin) * 3))
57#define SSP_PIN_MASK(pin) SSP_PIN_SEL(pin, 0x7)
58#define SSP_INPUT_SEL(pin) ((pin) << 16)
59
60/* Sequencer port config bits */
61#define SSP_EARLY_DIN BIT(8)
62#define SSP_DELAY_DOUT BIT(9)
63
64/* Sequence map definitions */
65#define SSP_CLK_HIGH BIT(0)
66#define SSP_CLK_LOW 0
67#define SSP_DATA_HIGH BIT(1)
68#define SSP_DATA_LOW 0
69#define SSP_CS_HIGH BIT(2)
70#define SSP_CS_LOW 0
71#define SSP_OUT_MODE BIT(3)
72#define SSP_IN_MODE 0
73#define SSP_DATA_REG BIT(4)
74#define SSP_ADDR_REG 0
75
76#define SSP_OPCODE_DIRECT ((0x0) << 5)
77#define SSP_OPCODE_TOGGLE ((0x1) << 5)
78#define SSP_OPCODE_SHIFT ((0x2) << 5)
79#define SSP_OPCODE_BRANCH0 ((0x4) << 5)
80#define SSP_OPCODE_BRANCH1 ((0x5) << 5)
81#define SSP_OPCODE_BRANCH ((0x6) << 5)
82#define SSP_OPCODE_STOP ((0x7) << 5)
83#define SSP_BRANCH(addr) ((addr) << 8)
84#define SSP_COUNT(cycles) ((cycles) << 8)
85
86int ti_ssp_raw_read(struct device *dev);
87int ti_ssp_raw_write(struct device *dev, u32 val);
88int ti_ssp_load(struct device *dev, int offs, u32* prog, int len);
89int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output);
90int ti_ssp_set_mode(struct device *dev, int mode);
91int ti_ssp_set_iosel(struct device *dev, u32 iosel);
92
93#endif /* __TI_SSP_H__ */