Blame view
drivers/spi/spi-imx.c
23.8 KB
b5f3294f0 spi: add SPI driv... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/* * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright (C) 2008 Juergen Beisert * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301, USA. */ #include <linux/clk.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/gpio.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> |
5a0e3ad6a include cleanup: ... |
33 |
#include <linux/slab.h> |
b5f3294f0 spi: add SPI driv... |
34 35 36 |
#include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> #include <linux/types.h> |
22a85e4cd spi/imx: add devi... |
37 38 39 |
#include <linux/of.h> #include <linux/of_device.h> #include <linux/of_gpio.h> |
b5f3294f0 spi: add SPI driv... |
40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
#include <mach/spi.h> #define DRIVER_NAME "spi_imx" #define MXC_CSPIRXDATA 0x00 #define MXC_CSPITXDATA 0x04 #define MXC_CSPICTRL 0x08 #define MXC_CSPIINT 0x0c #define MXC_RESET 0x1c /* generic defines to abstract from the different register layouts */ #define MXC_INT_RR (1 << 0) /* Receive data ready interrupt */ #define MXC_INT_TE (1 << 1) /* Transmit FIFO empty interrupt */ |
6cdeb0021 spi-imx: rename s... |
54 |
struct spi_imx_config { |
b5f3294f0 spi: add SPI driv... |
55 56 57 |
unsigned int speed_hz; unsigned int bpw; unsigned int mode; |
3b2aa89eb spi/imx: save the... |
58 |
u8 cs; |
b5f3294f0 spi: add SPI driv... |
59 |
}; |
f4ba6315c spi/imx: convert ... |
60 |
enum spi_imx_devtype { |
04ee58549 spi/imx: use soc ... |
61 62 63 64 65 66 |
IMX1_CSPI, IMX21_CSPI, IMX27_CSPI, IMX31_CSPI, IMX35_CSPI, /* CSPI on all i.mx except above */ IMX51_ECSPI, /* ECSPI on i.mx51 and later */ |
f4ba6315c spi/imx: convert ... |
67 68 69 70 71 72 73 74 75 |
}; struct spi_imx_data; struct spi_imx_devtype_data { void (*intctrl)(struct spi_imx_data *, int); int (*config)(struct spi_imx_data *, struct spi_imx_config *); void (*trigger)(struct spi_imx_data *); int (*rx_available)(struct spi_imx_data *); |
1723e66b0 spi/imx: get rid ... |
76 |
void (*reset)(struct spi_imx_data *); |
04ee58549 spi/imx: use soc ... |
77 |
enum spi_imx_devtype devtype; |
f4ba6315c spi/imx: convert ... |
78 |
}; |
6cdeb0021 spi-imx: rename s... |
79 |
struct spi_imx_data { |
b5f3294f0 spi: add SPI driv... |
80 81 82 83 84 85 86 |
struct spi_bitbang bitbang; struct completion xfer_done; void *base; int irq; struct clk *clk; unsigned long spi_clk; |
b5f3294f0 spi: add SPI driv... |
87 88 |
unsigned int count; |
6cdeb0021 spi-imx: rename s... |
89 90 |
void (*tx)(struct spi_imx_data *); void (*rx)(struct spi_imx_data *); |
b5f3294f0 spi: add SPI driv... |
91 92 93 |
void *rx_buf; const void *tx_buf; unsigned int txfifo; /* number of words pushed in tx FIFO */ |
edd501bbf spi/imx: do not m... |
94 |
struct spi_imx_devtype_data *devtype_data; |
c2387cb9e spi/imx: copy gpi... |
95 |
int chipselect[0]; |
b5f3294f0 spi: add SPI driv... |
96 |
}; |
04ee58549 spi/imx: use soc ... |
97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
static inline int is_imx27_cspi(struct spi_imx_data *d) { return d->devtype_data->devtype == IMX27_CSPI; } static inline int is_imx35_cspi(struct spi_imx_data *d) { return d->devtype_data->devtype == IMX35_CSPI; } static inline unsigned spi_imx_get_fifosize(struct spi_imx_data *d) { return (d->devtype_data->devtype == IMX51_ECSPI) ? 64 : 8; } |
b5f3294f0 spi: add SPI driv... |
111 |
#define MXC_SPI_BUF_RX(type) \ |
6cdeb0021 spi-imx: rename s... |
112 |
static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx) \ |
b5f3294f0 spi: add SPI driv... |
113 |
{ \ |
6cdeb0021 spi-imx: rename s... |
114 |
unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA); \ |
b5f3294f0 spi: add SPI driv... |
115 |
\ |
6cdeb0021 spi-imx: rename s... |
116 117 118 |
if (spi_imx->rx_buf) { \ *(type *)spi_imx->rx_buf = val; \ spi_imx->rx_buf += sizeof(type); \ |
b5f3294f0 spi: add SPI driv... |
119 120 121 122 |
} \ } #define MXC_SPI_BUF_TX(type) \ |
6cdeb0021 spi-imx: rename s... |
123 |
static void spi_imx_buf_tx_##type(struct spi_imx_data *spi_imx) \ |
b5f3294f0 spi: add SPI driv... |
124 125 126 |
{ \ type val = 0; \ \ |
6cdeb0021 spi-imx: rename s... |
127 128 129 |
if (spi_imx->tx_buf) { \ val = *(type *)spi_imx->tx_buf; \ spi_imx->tx_buf += sizeof(type); \ |
b5f3294f0 spi: add SPI driv... |
130 131 |
} \ \ |
6cdeb0021 spi-imx: rename s... |
132 |
spi_imx->count -= sizeof(type); \ |
b5f3294f0 spi: add SPI driv... |
133 |
\ |
6cdeb0021 spi-imx: rename s... |
134 |
writel(val, spi_imx->base + MXC_CSPITXDATA); \ |
b5f3294f0 spi: add SPI driv... |
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
} MXC_SPI_BUF_RX(u8) MXC_SPI_BUF_TX(u8) MXC_SPI_BUF_RX(u16) MXC_SPI_BUF_TX(u16) MXC_SPI_BUF_RX(u32) MXC_SPI_BUF_TX(u32) /* First entry is reserved, second entry is valid only if SDHC_SPIEN is set * (which is currently not the case in this driver) */ static int mxc_clkdivs[] = {0, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024}; /* MX21, MX27 */ |
6cdeb0021 spi-imx: rename s... |
151 |
static unsigned int spi_imx_clkdiv_1(unsigned int fin, |
04ee58549 spi/imx: use soc ... |
152 |
unsigned int fspi, unsigned int max) |
b5f3294f0 spi: add SPI driv... |
153 |
{ |
04ee58549 spi/imx: use soc ... |
154 |
int i; |
b5f3294f0 spi: add SPI driv... |
155 156 157 158 159 160 161 |
for (i = 2; i < max; i++) if (fspi * mxc_clkdivs[i] >= fin) return i; return max; } |
0b599603d spi/imx: add supp... |
162 |
/* MX1, MX31, MX35, MX51 CSPI */ |
6cdeb0021 spi-imx: rename s... |
163 |
static unsigned int spi_imx_clkdiv_2(unsigned int fin, |
b5f3294f0 spi: add SPI driv... |
164 165 166 167 168 169 170 171 172 173 174 175 |
unsigned int fspi) { int i, div = 4; for (i = 0; i < 7; i++) { if (fspi * div >= fin) return i; div <<= 1; } return 7; } |
66de757c5 spi/imx: do not u... |
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
#define MX51_ECSPI_CTRL 0x08 #define MX51_ECSPI_CTRL_ENABLE (1 << 0) #define MX51_ECSPI_CTRL_XCH (1 << 2) #define MX51_ECSPI_CTRL_MODE_MASK (0xf << 4) #define MX51_ECSPI_CTRL_POSTDIV_OFFSET 8 #define MX51_ECSPI_CTRL_PREDIV_OFFSET 12 #define MX51_ECSPI_CTRL_CS(cs) ((cs) << 18) #define MX51_ECSPI_CTRL_BL_OFFSET 20 #define MX51_ECSPI_CONFIG 0x0c #define MX51_ECSPI_CONFIG_SCLKPHA(cs) (1 << ((cs) + 0)) #define MX51_ECSPI_CONFIG_SCLKPOL(cs) (1 << ((cs) + 4)) #define MX51_ECSPI_CONFIG_SBBCTRL(cs) (1 << ((cs) + 8)) #define MX51_ECSPI_CONFIG_SSBPOL(cs) (1 << ((cs) + 12)) #define MX51_ECSPI_INT 0x10 #define MX51_ECSPI_INT_TEEN (1 << 0) #define MX51_ECSPI_INT_RREN (1 << 3) #define MX51_ECSPI_STAT 0x18 #define MX51_ECSPI_STAT_RR (1 << 3) |
0b599603d spi/imx: add supp... |
197 198 |
/* MX51 eCSPI */ |
66de757c5 spi/imx: do not u... |
199 |
static unsigned int mx51_ecspi_clkdiv(unsigned int fin, unsigned int fspi) |
0b599603d spi/imx: add supp... |
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
{ /* * there are two 4-bit dividers, the pre-divider divides by * $pre, the post-divider by 2^$post */ unsigned int pre, post; if (unlikely(fspi > fin)) return 0; post = fls(fin) - fls(fspi); if (fin > fspi << post) post++; /* now we have: (fin <= fspi << post) with post being minimal */ post = max(4U, post) - 4; if (unlikely(post > 0xf)) { pr_err("%s: cannot set clock freq: %u (base freq: %u) ", __func__, fspi, fin); return 0xff; } pre = DIV_ROUND_UP(fin, fspi << post) - 1; pr_debug("%s: fin: %u, fspi: %u, post: %u, pre: %u ", __func__, fin, fspi, post, pre); |
66de757c5 spi/imx: do not u... |
229 230 |
return (pre << MX51_ECSPI_CTRL_PREDIV_OFFSET) | (post << MX51_ECSPI_CTRL_POSTDIV_OFFSET); |
0b599603d spi/imx: add supp... |
231 |
} |
66de757c5 spi/imx: do not u... |
232 |
static void __maybe_unused mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int enable) |
0b599603d spi/imx: add supp... |
233 234 235 236 |
{ unsigned val = 0; if (enable & MXC_INT_TE) |
66de757c5 spi/imx: do not u... |
237 |
val |= MX51_ECSPI_INT_TEEN; |
0b599603d spi/imx: add supp... |
238 239 |
if (enable & MXC_INT_RR) |
66de757c5 spi/imx: do not u... |
240 |
val |= MX51_ECSPI_INT_RREN; |
0b599603d spi/imx: add supp... |
241 |
|
66de757c5 spi/imx: do not u... |
242 |
writel(val, spi_imx->base + MX51_ECSPI_INT); |
0b599603d spi/imx: add supp... |
243 |
} |
66de757c5 spi/imx: do not u... |
244 |
static void __maybe_unused mx51_ecspi_trigger(struct spi_imx_data *spi_imx) |
0b599603d spi/imx: add supp... |
245 246 |
{ u32 reg; |
66de757c5 spi/imx: do not u... |
247 248 249 |
reg = readl(spi_imx->base + MX51_ECSPI_CTRL); reg |= MX51_ECSPI_CTRL_XCH; writel(reg, spi_imx->base + MX51_ECSPI_CTRL); |
0b599603d spi/imx: add supp... |
250 |
} |
66de757c5 spi/imx: do not u... |
251 |
static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx, |
0b599603d spi/imx: add supp... |
252 253 |
struct spi_imx_config *config) { |
66de757c5 spi/imx: do not u... |
254 |
u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0; |
0b599603d spi/imx: add supp... |
255 |
|
f020c39e5 spi/imx: select m... |
256 257 258 259 260 261 262 |
/* * The hardware seems to have a race condition when changing modes. The * current assumption is that the selection of the channel arrives * earlier in the hardware than the mode bits when they are written at * the same time. * So set master mode for all channels as we do not support slave mode. */ |
66de757c5 spi/imx: do not u... |
263 |
ctrl |= MX51_ECSPI_CTRL_MODE_MASK; |
0b599603d spi/imx: add supp... |
264 265 |
/* set clock speed */ |
66de757c5 spi/imx: do not u... |
266 |
ctrl |= mx51_ecspi_clkdiv(spi_imx->spi_clk, config->speed_hz); |
0b599603d spi/imx: add supp... |
267 268 |
/* set chip select to use */ |
66de757c5 spi/imx: do not u... |
269 |
ctrl |= MX51_ECSPI_CTRL_CS(config->cs); |
0b599603d spi/imx: add supp... |
270 |
|
66de757c5 spi/imx: do not u... |
271 |
ctrl |= (config->bpw - 1) << MX51_ECSPI_CTRL_BL_OFFSET; |
0b599603d spi/imx: add supp... |
272 |
|
66de757c5 spi/imx: do not u... |
273 |
cfg |= MX51_ECSPI_CONFIG_SBBCTRL(config->cs); |
0b599603d spi/imx: add supp... |
274 275 |
if (config->mode & SPI_CPHA) |
66de757c5 spi/imx: do not u... |
276 |
cfg |= MX51_ECSPI_CONFIG_SCLKPHA(config->cs); |
0b599603d spi/imx: add supp... |
277 278 |
if (config->mode & SPI_CPOL) |
66de757c5 spi/imx: do not u... |
279 |
cfg |= MX51_ECSPI_CONFIG_SCLKPOL(config->cs); |
0b599603d spi/imx: add supp... |
280 281 |
if (config->mode & SPI_CS_HIGH) |
66de757c5 spi/imx: do not u... |
282 |
cfg |= MX51_ECSPI_CONFIG_SSBPOL(config->cs); |
0b599603d spi/imx: add supp... |
283 |
|
66de757c5 spi/imx: do not u... |
284 285 |
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG); |
0b599603d spi/imx: add supp... |
286 287 288 |
return 0; } |
66de757c5 spi/imx: do not u... |
289 |
static int __maybe_unused mx51_ecspi_rx_available(struct spi_imx_data *spi_imx) |
0b599603d spi/imx: add supp... |
290 |
{ |
66de757c5 spi/imx: do not u... |
291 |
return readl(spi_imx->base + MX51_ECSPI_STAT) & MX51_ECSPI_STAT_RR; |
0b599603d spi/imx: add supp... |
292 |
} |
66de757c5 spi/imx: do not u... |
293 |
static void __maybe_unused mx51_ecspi_reset(struct spi_imx_data *spi_imx) |
0b599603d spi/imx: add supp... |
294 295 |
{ /* drain receive buffer */ |
66de757c5 spi/imx: do not u... |
296 |
while (mx51_ecspi_rx_available(spi_imx)) |
0b599603d spi/imx: add supp... |
297 298 |
readl(spi_imx->base + MXC_CSPIRXDATA); } |
b5f3294f0 spi: add SPI driv... |
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
#define MX31_INTREG_TEEN (1 << 0) #define MX31_INTREG_RREN (1 << 3) #define MX31_CSPICTRL_ENABLE (1 << 0) #define MX31_CSPICTRL_MASTER (1 << 1) #define MX31_CSPICTRL_XCH (1 << 2) #define MX31_CSPICTRL_POL (1 << 4) #define MX31_CSPICTRL_PHA (1 << 5) #define MX31_CSPICTRL_SSCTL (1 << 6) #define MX31_CSPICTRL_SSPOL (1 << 7) #define MX31_CSPICTRL_BC_SHIFT 8 #define MX35_CSPICTRL_BL_SHIFT 20 #define MX31_CSPICTRL_CS_SHIFT 24 #define MX35_CSPICTRL_CS_SHIFT 12 #define MX31_CSPICTRL_DR_SHIFT 16 #define MX31_CSPISTATUS 0x14 #define MX31_STATUS_RR (1 << 3) /* These functions also work for the i.MX35, but be aware that * the i.MX35 has a slightly different register layout for bits * we do not use here. */ |
f4ba6315c spi/imx: convert ... |
322 |
static void __maybe_unused mx31_intctrl(struct spi_imx_data *spi_imx, int enable) |
b5f3294f0 spi: add SPI driv... |
323 324 325 326 327 328 329 |
{ unsigned int val = 0; if (enable & MXC_INT_TE) val |= MX31_INTREG_TEEN; if (enable & MXC_INT_RR) val |= MX31_INTREG_RREN; |
6cdeb0021 spi-imx: rename s... |
330 |
writel(val, spi_imx->base + MXC_CSPIINT); |
b5f3294f0 spi: add SPI driv... |
331 |
} |
f4ba6315c spi/imx: convert ... |
332 |
static void __maybe_unused mx31_trigger(struct spi_imx_data *spi_imx) |
b5f3294f0 spi: add SPI driv... |
333 334 |
{ unsigned int reg; |
6cdeb0021 spi-imx: rename s... |
335 |
reg = readl(spi_imx->base + MXC_CSPICTRL); |
b5f3294f0 spi: add SPI driv... |
336 |
reg |= MX31_CSPICTRL_XCH; |
6cdeb0021 spi-imx: rename s... |
337 |
writel(reg, spi_imx->base + MXC_CSPICTRL); |
b5f3294f0 spi: add SPI driv... |
338 |
} |
2a64a90a2 spi/imx: merge ty... |
339 |
static int __maybe_unused mx31_config(struct spi_imx_data *spi_imx, |
1723e66b0 spi/imx: get rid ... |
340 341 342 |
struct spi_imx_config *config) { unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER; |
3b2aa89eb spi/imx: save the... |
343 |
int cs = spi_imx->chipselect[config->cs]; |
1723e66b0 spi/imx: get rid ... |
344 345 346 |
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) << MX31_CSPICTRL_DR_SHIFT; |
04ee58549 spi/imx: use soc ... |
347 |
if (is_imx35_cspi(spi_imx)) { |
2a64a90a2 spi/imx: merge ty... |
348 349 350 351 352 |
reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT; reg |= MX31_CSPICTRL_SSCTL; } else { reg |= (config->bpw - 1) << MX31_CSPICTRL_BC_SHIFT; } |
1723e66b0 spi/imx: get rid ... |
353 354 355 356 357 358 359 |
if (config->mode & SPI_CPHA) reg |= MX31_CSPICTRL_PHA; if (config->mode & SPI_CPOL) reg |= MX31_CSPICTRL_POL; if (config->mode & SPI_CS_HIGH) reg |= MX31_CSPICTRL_SSPOL; |
3b2aa89eb spi/imx: save the... |
360 |
if (cs < 0) |
2a64a90a2 spi/imx: merge ty... |
361 |
reg |= (cs + 32) << |
04ee58549 spi/imx: use soc ... |
362 363 |
(is_imx35_cspi(spi_imx) ? MX35_CSPICTRL_CS_SHIFT : MX31_CSPICTRL_CS_SHIFT); |
1723e66b0 spi/imx: get rid ... |
364 365 366 367 368 |
writel(reg, spi_imx->base + MXC_CSPICTRL); return 0; } |
f4ba6315c spi/imx: convert ... |
369 |
static int __maybe_unused mx31_rx_available(struct spi_imx_data *spi_imx) |
b5f3294f0 spi: add SPI driv... |
370 |
{ |
6cdeb0021 spi-imx: rename s... |
371 |
return readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR; |
b5f3294f0 spi: add SPI driv... |
372 |
} |
2a64a90a2 spi/imx: merge ty... |
373 |
static void __maybe_unused mx31_reset(struct spi_imx_data *spi_imx) |
1723e66b0 spi/imx: get rid ... |
374 375 |
{ /* drain receive buffer */ |
2a64a90a2 spi/imx: merge ty... |
376 |
while (readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR) |
1723e66b0 spi/imx: get rid ... |
377 378 |
readl(spi_imx->base + MXC_CSPIRXDATA); } |
3451fb156 spi/imx: use mx21... |
379 380 381 382 383 384 385 386 387 388 389 390 391 392 |
#define MX21_INTREG_RR (1 << 4) #define MX21_INTREG_TEEN (1 << 9) #define MX21_INTREG_RREN (1 << 13) #define MX21_CSPICTRL_POL (1 << 5) #define MX21_CSPICTRL_PHA (1 << 6) #define MX21_CSPICTRL_SSPOL (1 << 8) #define MX21_CSPICTRL_XCH (1 << 9) #define MX21_CSPICTRL_ENABLE (1 << 10) #define MX21_CSPICTRL_MASTER (1 << 11) #define MX21_CSPICTRL_DR_SHIFT 14 #define MX21_CSPICTRL_CS_SHIFT 19 static void __maybe_unused mx21_intctrl(struct spi_imx_data *spi_imx, int enable) |
b5f3294f0 spi: add SPI driv... |
393 394 395 396 |
{ unsigned int val = 0; if (enable & MXC_INT_TE) |
3451fb156 spi/imx: use mx21... |
397 |
val |= MX21_INTREG_TEEN; |
b5f3294f0 spi: add SPI driv... |
398 |
if (enable & MXC_INT_RR) |
3451fb156 spi/imx: use mx21... |
399 |
val |= MX21_INTREG_RREN; |
b5f3294f0 spi: add SPI driv... |
400 |
|
6cdeb0021 spi-imx: rename s... |
401 |
writel(val, spi_imx->base + MXC_CSPIINT); |
b5f3294f0 spi: add SPI driv... |
402 |
} |
3451fb156 spi/imx: use mx21... |
403 |
static void __maybe_unused mx21_trigger(struct spi_imx_data *spi_imx) |
b5f3294f0 spi: add SPI driv... |
404 405 |
{ unsigned int reg; |
6cdeb0021 spi-imx: rename s... |
406 |
reg = readl(spi_imx->base + MXC_CSPICTRL); |
3451fb156 spi/imx: use mx21... |
407 |
reg |= MX21_CSPICTRL_XCH; |
6cdeb0021 spi-imx: rename s... |
408 |
writel(reg, spi_imx->base + MXC_CSPICTRL); |
b5f3294f0 spi: add SPI driv... |
409 |
} |
3451fb156 spi/imx: use mx21... |
410 |
static int __maybe_unused mx21_config(struct spi_imx_data *spi_imx, |
6cdeb0021 spi-imx: rename s... |
411 |
struct spi_imx_config *config) |
b5f3294f0 spi: add SPI driv... |
412 |
{ |
3451fb156 spi/imx: use mx21... |
413 |
unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_MASTER; |
3b2aa89eb spi/imx: save the... |
414 |
int cs = spi_imx->chipselect[config->cs]; |
04ee58549 spi/imx: use soc ... |
415 |
unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18; |
b5f3294f0 spi: add SPI driv... |
416 |
|
04ee58549 spi/imx: use soc ... |
417 |
reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, config->speed_hz, max) << |
3451fb156 spi/imx: use mx21... |
418 |
MX21_CSPICTRL_DR_SHIFT; |
b5f3294f0 spi: add SPI driv... |
419 420 421 |
reg |= config->bpw - 1; if (config->mode & SPI_CPHA) |
3451fb156 spi/imx: use mx21... |
422 |
reg |= MX21_CSPICTRL_PHA; |
b5f3294f0 spi: add SPI driv... |
423 |
if (config->mode & SPI_CPOL) |
3451fb156 spi/imx: use mx21... |
424 |
reg |= MX21_CSPICTRL_POL; |
b5f3294f0 spi: add SPI driv... |
425 |
if (config->mode & SPI_CS_HIGH) |
3451fb156 spi/imx: use mx21... |
426 |
reg |= MX21_CSPICTRL_SSPOL; |
3b2aa89eb spi/imx: save the... |
427 |
if (cs < 0) |
3451fb156 spi/imx: use mx21... |
428 |
reg |= (cs + 32) << MX21_CSPICTRL_CS_SHIFT; |
b5f3294f0 spi: add SPI driv... |
429 |
|
6cdeb0021 spi-imx: rename s... |
430 |
writel(reg, spi_imx->base + MXC_CSPICTRL); |
b5f3294f0 spi: add SPI driv... |
431 432 433 |
return 0; } |
3451fb156 spi/imx: use mx21... |
434 |
static int __maybe_unused mx21_rx_available(struct spi_imx_data *spi_imx) |
b5f3294f0 spi: add SPI driv... |
435 |
{ |
3451fb156 spi/imx: use mx21... |
436 |
return readl(spi_imx->base + MXC_CSPIINT) & MX21_INTREG_RR; |
b5f3294f0 spi: add SPI driv... |
437 |
} |
3451fb156 spi/imx: use mx21... |
438 |
static void __maybe_unused mx21_reset(struct spi_imx_data *spi_imx) |
1723e66b0 spi/imx: get rid ... |
439 440 441 |
{ writel(1, spi_imx->base + MXC_RESET); } |
b5f3294f0 spi: add SPI driv... |
442 443 444 445 446 447 448 449 450 451 |
#define MX1_INTREG_RR (1 << 3) #define MX1_INTREG_TEEN (1 << 8) #define MX1_INTREG_RREN (1 << 11) #define MX1_CSPICTRL_POL (1 << 4) #define MX1_CSPICTRL_PHA (1 << 5) #define MX1_CSPICTRL_XCH (1 << 8) #define MX1_CSPICTRL_ENABLE (1 << 9) #define MX1_CSPICTRL_MASTER (1 << 10) #define MX1_CSPICTRL_DR_SHIFT 13 |
f4ba6315c spi/imx: convert ... |
452 |
static void __maybe_unused mx1_intctrl(struct spi_imx_data *spi_imx, int enable) |
b5f3294f0 spi: add SPI driv... |
453 454 455 456 457 458 459 |
{ unsigned int val = 0; if (enable & MXC_INT_TE) val |= MX1_INTREG_TEEN; if (enable & MXC_INT_RR) val |= MX1_INTREG_RREN; |
6cdeb0021 spi-imx: rename s... |
460 |
writel(val, spi_imx->base + MXC_CSPIINT); |
b5f3294f0 spi: add SPI driv... |
461 |
} |
f4ba6315c spi/imx: convert ... |
462 |
static void __maybe_unused mx1_trigger(struct spi_imx_data *spi_imx) |
b5f3294f0 spi: add SPI driv... |
463 464 |
{ unsigned int reg; |
6cdeb0021 spi-imx: rename s... |
465 |
reg = readl(spi_imx->base + MXC_CSPICTRL); |
b5f3294f0 spi: add SPI driv... |
466 |
reg |= MX1_CSPICTRL_XCH; |
6cdeb0021 spi-imx: rename s... |
467 |
writel(reg, spi_imx->base + MXC_CSPICTRL); |
b5f3294f0 spi: add SPI driv... |
468 |
} |
f4ba6315c spi/imx: convert ... |
469 |
static int __maybe_unused mx1_config(struct spi_imx_data *spi_imx, |
6cdeb0021 spi-imx: rename s... |
470 |
struct spi_imx_config *config) |
b5f3294f0 spi: add SPI driv... |
471 472 |
{ unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER; |
6cdeb0021 spi-imx: rename s... |
473 |
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) << |
b5f3294f0 spi: add SPI driv... |
474 475 476 477 478 479 480 |
MX1_CSPICTRL_DR_SHIFT; reg |= config->bpw - 1; if (config->mode & SPI_CPHA) reg |= MX1_CSPICTRL_PHA; if (config->mode & SPI_CPOL) reg |= MX1_CSPICTRL_POL; |
6cdeb0021 spi-imx: rename s... |
481 |
writel(reg, spi_imx->base + MXC_CSPICTRL); |
b5f3294f0 spi: add SPI driv... |
482 483 484 |
return 0; } |
f4ba6315c spi/imx: convert ... |
485 |
static int __maybe_unused mx1_rx_available(struct spi_imx_data *spi_imx) |
b5f3294f0 spi: add SPI driv... |
486 |
{ |
6cdeb0021 spi-imx: rename s... |
487 |
return readl(spi_imx->base + MXC_CSPIINT) & MX1_INTREG_RR; |
b5f3294f0 spi: add SPI driv... |
488 |
} |
1723e66b0 spi/imx: get rid ... |
489 490 491 492 |
static void __maybe_unused mx1_reset(struct spi_imx_data *spi_imx) { writel(1, spi_imx->base + MXC_RESET); } |
04ee58549 spi/imx: use soc ... |
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 |
static struct spi_imx_devtype_data imx1_cspi_devtype_data = { .intctrl = mx1_intctrl, .config = mx1_config, .trigger = mx1_trigger, .rx_available = mx1_rx_available, .reset = mx1_reset, .devtype = IMX1_CSPI, }; static struct spi_imx_devtype_data imx21_cspi_devtype_data = { .intctrl = mx21_intctrl, .config = mx21_config, .trigger = mx21_trigger, .rx_available = mx21_rx_available, .reset = mx21_reset, .devtype = IMX21_CSPI, }; static struct spi_imx_devtype_data imx27_cspi_devtype_data = { /* i.mx27 cspi shares the functions with i.mx21 one */ .intctrl = mx21_intctrl, .config = mx21_config, .trigger = mx21_trigger, .rx_available = mx21_rx_available, .reset = mx21_reset, .devtype = IMX27_CSPI, }; static struct spi_imx_devtype_data imx31_cspi_devtype_data = { .intctrl = mx31_intctrl, .config = mx31_config, .trigger = mx31_trigger, .rx_available = mx31_rx_available, .reset = mx31_reset, .devtype = IMX31_CSPI, }; static struct spi_imx_devtype_data imx35_cspi_devtype_data = { /* i.mx35 and later cspi shares the functions with i.mx31 one */ .intctrl = mx31_intctrl, .config = mx31_config, .trigger = mx31_trigger, .rx_available = mx31_rx_available, .reset = mx31_reset, .devtype = IMX35_CSPI, }; static struct spi_imx_devtype_data imx51_ecspi_devtype_data = { .intctrl = mx51_ecspi_intctrl, .config = mx51_ecspi_config, .trigger = mx51_ecspi_trigger, .rx_available = mx51_ecspi_rx_available, .reset = mx51_ecspi_reset, .devtype = IMX51_ECSPI, }; static struct platform_device_id spi_imx_devtype[] = { { .name = "imx1-cspi", .driver_data = (kernel_ulong_t) &imx1_cspi_devtype_data, }, { .name = "imx21-cspi", .driver_data = (kernel_ulong_t) &imx21_cspi_devtype_data, }, { .name = "imx27-cspi", .driver_data = (kernel_ulong_t) &imx27_cspi_devtype_data, }, { .name = "imx31-cspi", .driver_data = (kernel_ulong_t) &imx31_cspi_devtype_data, }, { .name = "imx35-cspi", .driver_data = (kernel_ulong_t) &imx35_cspi_devtype_data, }, { .name = "imx51-ecspi", .driver_data = (kernel_ulong_t) &imx51_ecspi_devtype_data, }, { /* sentinel */ } |
f4ba6315c spi/imx: convert ... |
571 |
}; |
22a85e4cd spi/imx: add devi... |
572 573 574 575 576 577 578 579 580 |
static const struct of_device_id spi_imx_dt_ids[] = { { .compatible = "fsl,imx1-cspi", .data = &imx1_cspi_devtype_data, }, { .compatible = "fsl,imx21-cspi", .data = &imx21_cspi_devtype_data, }, { .compatible = "fsl,imx27-cspi", .data = &imx27_cspi_devtype_data, }, { .compatible = "fsl,imx31-cspi", .data = &imx31_cspi_devtype_data, }, { .compatible = "fsl,imx35-cspi", .data = &imx35_cspi_devtype_data, }, { .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, }, { /* sentinel */ } }; |
6cdeb0021 spi-imx: rename s... |
581 |
static void spi_imx_chipselect(struct spi_device *spi, int is_active) |
b5f3294f0 spi: add SPI driv... |
582 |
{ |
6cdeb0021 spi-imx: rename s... |
583 |
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); |
6cdeb0021 spi-imx: rename s... |
584 |
int gpio = spi_imx->chipselect[spi->chip_select]; |
e6a0a8bfe spi-imx: strip do... |
585 586 |
int active = is_active != BITBANG_CS_INACTIVE; int dev_is_lowactive = !(spi->mode & SPI_CS_HIGH); |
b5f3294f0 spi: add SPI driv... |
587 |
|
e6a0a8bfe spi-imx: strip do... |
588 |
if (gpio < 0) |
b5f3294f0 spi: add SPI driv... |
589 |
return; |
b5f3294f0 spi: add SPI driv... |
590 |
|
e6a0a8bfe spi-imx: strip do... |
591 |
gpio_set_value(gpio, dev_is_lowactive ^ active); |
b5f3294f0 spi: add SPI driv... |
592 |
} |
6cdeb0021 spi-imx: rename s... |
593 |
static void spi_imx_push(struct spi_imx_data *spi_imx) |
b5f3294f0 spi: add SPI driv... |
594 |
{ |
04ee58549 spi/imx: use soc ... |
595 |
while (spi_imx->txfifo < spi_imx_get_fifosize(spi_imx)) { |
6cdeb0021 spi-imx: rename s... |
596 |
if (!spi_imx->count) |
b5f3294f0 spi: add SPI driv... |
597 |
break; |
6cdeb0021 spi-imx: rename s... |
598 599 |
spi_imx->tx(spi_imx); spi_imx->txfifo++; |
b5f3294f0 spi: add SPI driv... |
600 |
} |
edd501bbf spi/imx: do not m... |
601 |
spi_imx->devtype_data->trigger(spi_imx); |
b5f3294f0 spi: add SPI driv... |
602 |
} |
6cdeb0021 spi-imx: rename s... |
603 |
static irqreturn_t spi_imx_isr(int irq, void *dev_id) |
b5f3294f0 spi: add SPI driv... |
604 |
{ |
6cdeb0021 spi-imx: rename s... |
605 |
struct spi_imx_data *spi_imx = dev_id; |
b5f3294f0 spi: add SPI driv... |
606 |
|
edd501bbf spi/imx: do not m... |
607 |
while (spi_imx->devtype_data->rx_available(spi_imx)) { |
6cdeb0021 spi-imx: rename s... |
608 609 |
spi_imx->rx(spi_imx); spi_imx->txfifo--; |
b5f3294f0 spi: add SPI driv... |
610 |
} |
6cdeb0021 spi-imx: rename s... |
611 612 |
if (spi_imx->count) { spi_imx_push(spi_imx); |
b5f3294f0 spi: add SPI driv... |
613 614 |
return IRQ_HANDLED; } |
6cdeb0021 spi-imx: rename s... |
615 |
if (spi_imx->txfifo) { |
b5f3294f0 spi: add SPI driv... |
616 617 618 |
/* No data left to push, but still waiting for rx data, * enable receive data available interrupt. */ |
edd501bbf spi/imx: do not m... |
619 |
spi_imx->devtype_data->intctrl( |
f4ba6315c spi/imx: convert ... |
620 |
spi_imx, MXC_INT_RR); |
b5f3294f0 spi: add SPI driv... |
621 622 |
return IRQ_HANDLED; } |
edd501bbf spi/imx: do not m... |
623 |
spi_imx->devtype_data->intctrl(spi_imx, 0); |
6cdeb0021 spi-imx: rename s... |
624 |
complete(&spi_imx->xfer_done); |
b5f3294f0 spi: add SPI driv... |
625 626 627 |
return IRQ_HANDLED; } |
6cdeb0021 spi-imx: rename s... |
628 |
static int spi_imx_setupxfer(struct spi_device *spi, |
b5f3294f0 spi: add SPI driv... |
629 630 |
struct spi_transfer *t) { |
6cdeb0021 spi-imx: rename s... |
631 632 |
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); struct spi_imx_config config; |
b5f3294f0 spi: add SPI driv... |
633 634 635 636 |
config.bpw = t ? t->bits_per_word : spi->bits_per_word; config.speed_hz = t ? t->speed_hz : spi->max_speed_hz; config.mode = spi->mode; |
3b2aa89eb spi/imx: save the... |
637 |
config.cs = spi->chip_select; |
b5f3294f0 spi: add SPI driv... |
638 |
|
462d26b5d spi-imx: update s... |
639 640 641 642 643 644 |
if (!config.speed_hz) config.speed_hz = spi->max_speed_hz; if (!config.bpw) config.bpw = spi->bits_per_word; if (!config.speed_hz) config.speed_hz = spi->max_speed_hz; |
e6a0a8bfe spi-imx: strip do... |
645 646 647 648 649 650 651 652 653 654 655 656 |
/* Initialize the functions for transfer */ if (config.bpw <= 8) { spi_imx->rx = spi_imx_buf_rx_u8; spi_imx->tx = spi_imx_buf_tx_u8; } else if (config.bpw <= 16) { spi_imx->rx = spi_imx_buf_rx_u16; spi_imx->tx = spi_imx_buf_tx_u16; } else if (config.bpw <= 32) { spi_imx->rx = spi_imx_buf_rx_u32; spi_imx->tx = spi_imx_buf_tx_u32; } else BUG(); |
edd501bbf spi/imx: do not m... |
657 |
spi_imx->devtype_data->config(spi_imx, &config); |
b5f3294f0 spi: add SPI driv... |
658 659 660 |
return 0; } |
6cdeb0021 spi-imx: rename s... |
661 |
static int spi_imx_transfer(struct spi_device *spi, |
b5f3294f0 spi: add SPI driv... |
662 663 |
struct spi_transfer *transfer) { |
6cdeb0021 spi-imx: rename s... |
664 |
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); |
b5f3294f0 spi: add SPI driv... |
665 |
|
6cdeb0021 spi-imx: rename s... |
666 667 668 669 |
spi_imx->tx_buf = transfer->tx_buf; spi_imx->rx_buf = transfer->rx_buf; spi_imx->count = transfer->len; spi_imx->txfifo = 0; |
b5f3294f0 spi: add SPI driv... |
670 |
|
6cdeb0021 spi-imx: rename s... |
671 |
init_completion(&spi_imx->xfer_done); |
b5f3294f0 spi: add SPI driv... |
672 |
|
6cdeb0021 spi-imx: rename s... |
673 |
spi_imx_push(spi_imx); |
b5f3294f0 spi: add SPI driv... |
674 |
|
edd501bbf spi/imx: do not m... |
675 |
spi_imx->devtype_data->intctrl(spi_imx, MXC_INT_TE); |
b5f3294f0 spi: add SPI driv... |
676 |
|
6cdeb0021 spi-imx: rename s... |
677 |
wait_for_completion(&spi_imx->xfer_done); |
b5f3294f0 spi: add SPI driv... |
678 679 680 |
return transfer->len; } |
6cdeb0021 spi-imx: rename s... |
681 |
static int spi_imx_setup(struct spi_device *spi) |
b5f3294f0 spi: add SPI driv... |
682 |
{ |
6c23e5d43 spi-imx: fix init... |
683 684 |
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); int gpio = spi_imx->chipselect[spi->chip_select]; |
f4d4ecfe7 spi/spi_imx: add ... |
685 686 |
dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz ", __func__, |
b5f3294f0 spi: add SPI driv... |
687 |
spi->mode, spi->bits_per_word, spi->max_speed_hz); |
6c23e5d43 spi-imx: fix init... |
688 689 |
if (gpio >= 0) gpio_direction_output(gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); |
6cdeb0021 spi-imx: rename s... |
690 |
spi_imx_chipselect(spi, BITBANG_CS_INACTIVE); |
b5f3294f0 spi: add SPI driv... |
691 692 693 |
return 0; } |
6cdeb0021 spi-imx: rename s... |
694 |
static void spi_imx_cleanup(struct spi_device *spi) |
b5f3294f0 spi: add SPI driv... |
695 696 |
{ } |
965346e3b spi: fix probe/re... |
697 |
static int __devinit spi_imx_probe(struct platform_device *pdev) |
b5f3294f0 spi: add SPI driv... |
698 |
{ |
22a85e4cd spi/imx: add devi... |
699 700 701 702 703 |
struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id = of_match_device(spi_imx_dt_ids, &pdev->dev); struct spi_imx_master *mxc_platform_info = dev_get_platdata(&pdev->dev); |
b5f3294f0 spi: add SPI driv... |
704 |
struct spi_master *master; |
6cdeb0021 spi-imx: rename s... |
705 |
struct spi_imx_data *spi_imx; |
b5f3294f0 spi: add SPI driv... |
706 |
struct resource *res; |
c2387cb9e spi/imx: copy gpi... |
707 |
int i, ret, num_cs; |
b5f3294f0 spi: add SPI driv... |
708 |
|
22a85e4cd spi/imx: add devi... |
709 |
if (!np && !mxc_platform_info) { |
b5f3294f0 spi: add SPI driv... |
710 711 712 713 |
dev_err(&pdev->dev, "can't get the platform data "); return -EINVAL; } |
22a85e4cd spi/imx: add devi... |
714 715 716 |
ret = of_property_read_u32(np, "fsl,spi-num-chipselects", &num_cs); if (ret < 0) num_cs = mxc_platform_info->num_chipselect; |
c2387cb9e spi/imx: copy gpi... |
717 718 |
master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data) + sizeof(int) * num_cs); |
b5f3294f0 spi: add SPI driv... |
719 720 721 722 723 724 |
if (!master) return -ENOMEM; platform_set_drvdata(pdev, master); master->bus_num = pdev->id; |
c2387cb9e spi/imx: copy gpi... |
725 |
master->num_chipselect = num_cs; |
b5f3294f0 spi: add SPI driv... |
726 |
|
6cdeb0021 spi-imx: rename s... |
727 728 |
spi_imx = spi_master_get_devdata(master); spi_imx->bitbang.master = spi_master_get(master); |
b5f3294f0 spi: add SPI driv... |
729 730 |
for (i = 0; i < master->num_chipselect; i++) { |
22a85e4cd spi/imx: add devi... |
731 732 733 |
int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); if (cs_gpio < 0) cs_gpio = mxc_platform_info->chipselect[i]; |
4cc122ac9 spi/imx: Fix spi-... |
734 735 |
spi_imx->chipselect[i] = cs_gpio; |
22a85e4cd spi/imx: add devi... |
736 |
if (cs_gpio < 0) |
b5f3294f0 spi: add SPI driv... |
737 |
continue; |
4cc122ac9 spi/imx: Fix spi-... |
738 |
|
6cdeb0021 spi-imx: rename s... |
739 |
ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME); |
b5f3294f0 spi: add SPI driv... |
740 |
if (ret) { |
bbd050af0 spi/i.MX: fix bro... |
741 742 |
while (i > 0) { i--; |
6cdeb0021 spi-imx: rename s... |
743 |
if (spi_imx->chipselect[i] >= 0) |
bbd050af0 spi/i.MX: fix bro... |
744 745 746 747 |
gpio_free(spi_imx->chipselect[i]); } dev_err(&pdev->dev, "can't get cs gpios "); |
b5f3294f0 spi: add SPI driv... |
748 749 |
goto out_master_put; } |
b5f3294f0 spi: add SPI driv... |
750 |
} |
6cdeb0021 spi-imx: rename s... |
751 752 753 754 755 |
spi_imx->bitbang.chipselect = spi_imx_chipselect; spi_imx->bitbang.setup_transfer = spi_imx_setupxfer; spi_imx->bitbang.txrx_bufs = spi_imx_transfer; spi_imx->bitbang.master->setup = spi_imx_setup; spi_imx->bitbang.master->cleanup = spi_imx_cleanup; |
3910f2cff spi-imx: setup mo... |
756 |
spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; |
b5f3294f0 spi: add SPI driv... |
757 |
|
6cdeb0021 spi-imx: rename s... |
758 |
init_completion(&spi_imx->xfer_done); |
b5f3294f0 spi: add SPI driv... |
759 |
|
22a85e4cd spi/imx: add devi... |
760 |
spi_imx->devtype_data = of_id ? of_id->data : |
04ee58549 spi/imx: use soc ... |
761 |
(struct spi_imx_devtype_data *) pdev->id_entry->driver_data; |
f4ba6315c spi/imx: convert ... |
762 |
|
b5f3294f0 spi: add SPI driv... |
763 764 765 766 767 768 769 770 771 772 773 774 775 776 |
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "can't get platform resource "); ret = -ENOMEM; goto out_gpio_free; } if (!request_mem_region(res->start, resource_size(res), pdev->name)) { dev_err(&pdev->dev, "request_mem_region failed "); ret = -EBUSY; goto out_gpio_free; } |
6cdeb0021 spi-imx: rename s... |
777 778 |
spi_imx->base = ioremap(res->start, resource_size(res)); if (!spi_imx->base) { |
b5f3294f0 spi: add SPI driv... |
779 780 781 |
ret = -EINVAL; goto out_release_mem; } |
6cdeb0021 spi-imx: rename s... |
782 |
spi_imx->irq = platform_get_irq(pdev, 0); |
735759389 spi/imx: correct ... |
783 |
if (spi_imx->irq < 0) { |
b5f3294f0 spi: add SPI driv... |
784 785 786 |
ret = -EINVAL; goto out_iounmap; } |
6cdeb0021 spi-imx: rename s... |
787 |
ret = request_irq(spi_imx->irq, spi_imx_isr, 0, DRIVER_NAME, spi_imx); |
b5f3294f0 spi: add SPI driv... |
788 |
if (ret) { |
6cdeb0021 spi-imx: rename s... |
789 790 |
dev_err(&pdev->dev, "can't get irq%d: %d ", spi_imx->irq, ret); |
b5f3294f0 spi: add SPI driv... |
791 792 |
goto out_iounmap; } |
6cdeb0021 spi-imx: rename s... |
793 794 |
spi_imx->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(spi_imx->clk)) { |
b5f3294f0 spi: add SPI driv... |
795 796 |
dev_err(&pdev->dev, "unable to get clock "); |
6cdeb0021 spi-imx: rename s... |
797 |
ret = PTR_ERR(spi_imx->clk); |
b5f3294f0 spi: add SPI driv... |
798 799 |
goto out_free_irq; } |
6cdeb0021 spi-imx: rename s... |
800 801 |
clk_enable(spi_imx->clk); spi_imx->spi_clk = clk_get_rate(spi_imx->clk); |
b5f3294f0 spi: add SPI driv... |
802 |
|
edd501bbf spi/imx: do not m... |
803 |
spi_imx->devtype_data->reset(spi_imx); |
ce1807b2e spi/i.mx: drain M... |
804 |
|
edd501bbf spi/imx: do not m... |
805 |
spi_imx->devtype_data->intctrl(spi_imx, 0); |
b5f3294f0 spi: add SPI driv... |
806 |
|
22a85e4cd spi/imx: add devi... |
807 |
master->dev.of_node = pdev->dev.of_node; |
6cdeb0021 spi-imx: rename s... |
808 |
ret = spi_bitbang_start(&spi_imx->bitbang); |
b5f3294f0 spi: add SPI driv... |
809 810 811 812 813 814 815 816 817 818 819 820 |
if (ret) { dev_err(&pdev->dev, "bitbang start failed with %d ", ret); goto out_clk_put; } dev_info(&pdev->dev, "probed "); return ret; out_clk_put: |
6cdeb0021 spi-imx: rename s... |
821 822 |
clk_disable(spi_imx->clk); clk_put(spi_imx->clk); |
b5f3294f0 spi: add SPI driv... |
823 |
out_free_irq: |
6cdeb0021 spi-imx: rename s... |
824 |
free_irq(spi_imx->irq, spi_imx); |
b5f3294f0 spi: add SPI driv... |
825 |
out_iounmap: |
6cdeb0021 spi-imx: rename s... |
826 |
iounmap(spi_imx->base); |
b5f3294f0 spi: add SPI driv... |
827 828 829 830 |
out_release_mem: release_mem_region(res->start, resource_size(res)); out_gpio_free: for (i = 0; i < master->num_chipselect; i++) |
6cdeb0021 spi-imx: rename s... |
831 832 |
if (spi_imx->chipselect[i] >= 0) gpio_free(spi_imx->chipselect[i]); |
b5f3294f0 spi: add SPI driv... |
833 834 835 836 837 838 |
out_master_put: spi_master_put(master); kfree(master); platform_set_drvdata(pdev, NULL); return ret; } |
965346e3b spi: fix probe/re... |
839 |
static int __devexit spi_imx_remove(struct platform_device *pdev) |
b5f3294f0 spi: add SPI driv... |
840 841 842 |
{ struct spi_master *master = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
6cdeb0021 spi-imx: rename s... |
843 |
struct spi_imx_data *spi_imx = spi_master_get_devdata(master); |
b5f3294f0 spi: add SPI driv... |
844 |
int i; |
6cdeb0021 spi-imx: rename s... |
845 |
spi_bitbang_stop(&spi_imx->bitbang); |
b5f3294f0 spi: add SPI driv... |
846 |
|
6cdeb0021 spi-imx: rename s... |
847 848 849 850 851 |
writel(0, spi_imx->base + MXC_CSPICTRL); clk_disable(spi_imx->clk); clk_put(spi_imx->clk); free_irq(spi_imx->irq, spi_imx); iounmap(spi_imx->base); |
b5f3294f0 spi: add SPI driv... |
852 853 |
for (i = 0; i < master->num_chipselect; i++) |
6cdeb0021 spi-imx: rename s... |
854 855 |
if (spi_imx->chipselect[i] >= 0) gpio_free(spi_imx->chipselect[i]); |
b5f3294f0 spi: add SPI driv... |
856 857 858 859 860 861 862 863 864 |
spi_master_put(master); release_mem_region(res->start, resource_size(res)); platform_set_drvdata(pdev, NULL); return 0; } |
6cdeb0021 spi-imx: rename s... |
865 |
static struct platform_driver spi_imx_driver = { |
b5f3294f0 spi: add SPI driv... |
866 867 868 |
.driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, |
22a85e4cd spi/imx: add devi... |
869 |
.of_match_table = spi_imx_dt_ids, |
b5f3294f0 spi: add SPI driv... |
870 |
}, |
f4ba6315c spi/imx: convert ... |
871 |
.id_table = spi_imx_devtype, |
6cdeb0021 spi-imx: rename s... |
872 |
.probe = spi_imx_probe, |
965346e3b spi: fix probe/re... |
873 |
.remove = __devexit_p(spi_imx_remove), |
b5f3294f0 spi: add SPI driv... |
874 |
}; |
940ab8896 drivercore: Add h... |
875 |
module_platform_driver(spi_imx_driver); |
b5f3294f0 spi: add SPI driv... |
876 877 878 879 |
MODULE_DESCRIPTION("SPI Master Controller driver"); MODULE_AUTHOR("Sascha Hauer, Pengutronix"); MODULE_LICENSE("GPL"); |