diff options
-rw-r--r-- | drivers/mfd/Kconfig | 8 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/stmpe-spi.c | 148 | ||||
-rw-r--r-- | drivers/mfd/stmpe.h | 1 |
4 files changed, 157 insertions, 1 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 7bc55819ab4a..06766ec5e288 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -258,7 +258,7 @@ config TWL6040_CORE | |||
258 | 258 | ||
259 | config MFD_STMPE | 259 | config MFD_STMPE |
260 | bool "Support STMicroelectronics STMPE" | 260 | bool "Support STMicroelectronics STMPE" |
261 | depends on I2C=y && GENERIC_HARDIRQS | 261 | depends on (I2C=y || SPI_MASTER=y) && GENERIC_HARDIRQS |
262 | select MFD_CORE | 262 | select MFD_CORE |
263 | help | 263 | help |
264 | Support for the STMPE family of I/O Expanders from | 264 | Support for the STMPE family of I/O Expanders from |
@@ -288,6 +288,12 @@ config STMPE_I2C | |||
288 | default y | 288 | default y |
289 | help | 289 | help |
290 | This is used to enable I2C interface of STMPE | 290 | This is used to enable I2C interface of STMPE |
291 | |||
292 | config STMPE_SPI | ||
293 | bool "STMPE SPI Inteface" | ||
294 | depends on SPI_MASTER | ||
295 | help | ||
296 | This is used to enable SPI interface of STMPE | ||
291 | endmenu | 297 | endmenu |
292 | 298 | ||
293 | config MFD_TC3589X | 299 | config MFD_TC3589X |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 5eb90a70c1a5..7f389a8895cb 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -17,6 +17,7 @@ obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o | |||
17 | 17 | ||
18 | obj-$(CONFIG_MFD_STMPE) += stmpe.o | 18 | obj-$(CONFIG_MFD_STMPE) += stmpe.o |
19 | obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o | 19 | obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o |
20 | obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o | ||
20 | obj-$(CONFIG_MFD_TC3589X) += tc3589x.o | 21 | obj-$(CONFIG_MFD_TC3589X) += tc3589x.o |
21 | obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o | 22 | obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o |
22 | obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o | 23 | obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o |
diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c new file mode 100644 index 000000000000..53efce4fe294 --- /dev/null +++ b/drivers/mfd/stmpe-spi.c | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * ST Microelectronics MFD: stmpe's spi client specific driver | ||
3 | * | ||
4 | * Copyright (C) ST Microelectronics SA 2011 | ||
5 | * | ||
6 | * License Terms: GNU General Public License, version 2 | ||
7 | * Author: Viresh Kumar <viresh.kumar@st.com> for ST Microelectronics | ||
8 | */ | ||
9 | |||
10 | #include <linux/spi/spi.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/types.h> | ||
15 | #include "stmpe.h" | ||
16 | |||
17 | #define READ_CMD (1 << 7) | ||
18 | |||
19 | static int spi_reg_read(struct stmpe *stmpe, u8 reg) | ||
20 | { | ||
21 | struct spi_device *spi = stmpe->client; | ||
22 | int status = spi_w8r16(spi, reg | READ_CMD); | ||
23 | |||
24 | return (status < 0) ? status : status >> 8; | ||
25 | } | ||
26 | |||
27 | static int spi_reg_write(struct stmpe *stmpe, u8 reg, u8 val) | ||
28 | { | ||
29 | struct spi_device *spi = stmpe->client; | ||
30 | u16 cmd = (val << 8) | reg; | ||
31 | |||
32 | return spi_write(spi, (const u8 *)&cmd, 2); | ||
33 | } | ||
34 | |||
35 | static int spi_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values) | ||
36 | { | ||
37 | int ret, i; | ||
38 | |||
39 | for (i = 0; i < length; i++) { | ||
40 | ret = spi_reg_read(stmpe, reg + i); | ||
41 | if (ret < 0) | ||
42 | return ret; | ||
43 | *(values + i) = ret; | ||
44 | } | ||
45 | |||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static int spi_block_write(struct stmpe *stmpe, u8 reg, u8 length, | ||
50 | const u8 *values) | ||
51 | { | ||
52 | int ret = 0, i; | ||
53 | |||
54 | for (i = length; i > 0; i--, reg++) { | ||
55 | ret = spi_reg_write(stmpe, reg, *(values + i - 1)); | ||
56 | if (ret < 0) | ||
57 | return ret; | ||
58 | } | ||
59 | |||
60 | return ret; | ||
61 | } | ||
62 | |||
63 | static void spi_init(struct stmpe *stmpe) | ||
64 | { | ||
65 | struct spi_device *spi = stmpe->client; | ||
66 | |||
67 | spi->bits_per_word = 8; | ||
68 | |||
69 | /* This register is only present for stmpe811 */ | ||
70 | if (stmpe->variant->id_val == 0x0811) | ||
71 | spi_reg_write(stmpe, STMPE811_REG_SPI_CFG, spi->mode); | ||
72 | |||
73 | if (spi_setup(spi) < 0) | ||
74 | dev_dbg(&spi->dev, "spi_setup failed\n"); | ||
75 | } | ||
76 | |||
77 | static struct stmpe_client_info spi_ci = { | ||
78 | .read_byte = spi_reg_read, | ||
79 | .write_byte = spi_reg_write, | ||
80 | .read_block = spi_block_read, | ||
81 | .write_block = spi_block_write, | ||
82 | .init = spi_init, | ||
83 | }; | ||
84 | |||
85 | static int __devinit | ||
86 | stmpe_spi_probe(struct spi_device *spi) | ||
87 | { | ||
88 | const struct spi_device_id *id = spi_get_device_id(spi); | ||
89 | |||
90 | /* don't exceed max specified rate - 1MHz - Limitation of STMPE */ | ||
91 | if (spi->max_speed_hz > 1000000) { | ||
92 | dev_dbg(&spi->dev, "f(sample) %d KHz?\n", | ||
93 | (spi->max_speed_hz/1000)); | ||
94 | return -EINVAL; | ||
95 | } | ||
96 | |||
97 | spi_ci.irq = spi->irq; | ||
98 | spi_ci.client = spi; | ||
99 | spi_ci.dev = &spi->dev; | ||
100 | |||
101 | return stmpe_probe(&spi_ci, id->driver_data); | ||
102 | } | ||
103 | |||
104 | static int __devexit stmpe_spi_remove(struct spi_device *spi) | ||
105 | { | ||
106 | struct stmpe *stmpe = dev_get_drvdata(&spi->dev); | ||
107 | |||
108 | return stmpe_remove(stmpe); | ||
109 | } | ||
110 | |||
111 | static const struct spi_device_id stmpe_spi_id[] = { | ||
112 | { "stmpe811", STMPE811 }, | ||
113 | { "stmpe1601", STMPE1601 }, | ||
114 | { "stmpe2401", STMPE2401 }, | ||
115 | { "stmpe2403", STMPE2403 }, | ||
116 | { } | ||
117 | }; | ||
118 | MODULE_DEVICE_TABLE(spi, stmpe_id); | ||
119 | |||
120 | static struct spi_driver stmpe_spi_driver = { | ||
121 | .driver = { | ||
122 | .name = "stmpe-spi", | ||
123 | .bus = &spi_bus_type, | ||
124 | .owner = THIS_MODULE, | ||
125 | #ifdef CONFIG_PM | ||
126 | .pm = &stmpe_dev_pm_ops, | ||
127 | #endif | ||
128 | }, | ||
129 | .probe = stmpe_spi_probe, | ||
130 | .remove = __devexit_p(stmpe_spi_remove), | ||
131 | .id_table = stmpe_spi_id, | ||
132 | }; | ||
133 | |||
134 | static int __init stmpe_init(void) | ||
135 | { | ||
136 | return spi_register_driver(&stmpe_spi_driver); | ||
137 | } | ||
138 | subsys_initcall(stmpe_init); | ||
139 | |||
140 | static void __exit stmpe_exit(void) | ||
141 | { | ||
142 | spi_unregister_driver(&stmpe_spi_driver); | ||
143 | } | ||
144 | module_exit(stmpe_exit); | ||
145 | |||
146 | MODULE_LICENSE("GPL v2"); | ||
147 | MODULE_DESCRIPTION("STMPE MFD SPI Interface Driver"); | ||
148 | MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>"); | ||
diff --git a/drivers/mfd/stmpe.h b/drivers/mfd/stmpe.h index 18d89a68ce40..a73f4c1085f2 100644 --- a/drivers/mfd/stmpe.h +++ b/drivers/mfd/stmpe.h | |||
@@ -120,6 +120,7 @@ int stmpe_remove(struct stmpe *stmpe); | |||
120 | 120 | ||
121 | #define STMPE811_REG_CHIP_ID 0x00 | 121 | #define STMPE811_REG_CHIP_ID 0x00 |
122 | #define STMPE811_REG_SYS_CTRL2 0x04 | 122 | #define STMPE811_REG_SYS_CTRL2 0x04 |
123 | #define STMPE811_REG_SPI_CFG 0x08 | ||
123 | #define STMPE811_REG_INT_CTRL 0x09 | 124 | #define STMPE811_REG_INT_CTRL 0x09 |
124 | #define STMPE811_REG_INT_EN 0x0A | 125 | #define STMPE811_REG_INT_EN 0x0A |
125 | #define STMPE811_REG_INT_STA 0x0B | 126 | #define STMPE811_REG_INT_STA 0x0B |