Blame view
drivers/spi/spi-bcm2835aux.c
17.1 KB
c942fddf8 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
1ea29b39f spi: bcm2835aux: ... |
2 3 4 5 6 7 8 9 10 |
/* * Driver for Broadcom BCM2835 auxiliary SPI Controllers * * the driver does not rely on the native chipselects at all * but only uses the gpio type chipselects * * Based on: spi-bcm2835.c * * Copyright (C) 2015 Martin Sperl |
1ea29b39f spi: bcm2835aux: ... |
11 12 13 14 |
*/ #include <linux/clk.h> #include <linux/completion.h> |
8048d151e spi: bcm2835aux: ... |
15 |
#include <linux/debugfs.h> |
1ea29b39f spi: bcm2835aux: ... |
16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#include <linux/delay.h> #include <linux/err.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/of_gpio.h> #include <linux/of_irq.h> #include <linux/regmap.h> #include <linux/spi/spi.h> #include <linux/spinlock.h> |
5fd917afc spi: bcm2835aux: ... |
30 |
/* define polling limits */ |
1a8fa5166 spi: bcm2835aux: ... |
31 |
static unsigned int polling_limit_us = 30; |
5fd917afc spi: bcm2835aux: ... |
32 33 34 35 |
module_param(polling_limit_us, uint, 0664); MODULE_PARM_DESC(polling_limit_us, "time in us to run a transfer in polling mode - if zero no polling is used "); |
1ea29b39f spi: bcm2835aux: ... |
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
/* * spi register defines * * note there is garbage in the "official" documentation, * so some data is taken from the file: * brcm_usrlib/dag/vmcsx/vcinclude/bcm2708_chip/aux_io.h * inside of: * http://www.broadcom.com/docs/support/videocore/Brcm_Android_ICS_Graphics_Stack.tar.gz */ /* SPI register offsets */ #define BCM2835_AUX_SPI_CNTL0 0x00 #define BCM2835_AUX_SPI_CNTL1 0x04 #define BCM2835_AUX_SPI_STAT 0x08 #define BCM2835_AUX_SPI_PEEK 0x0C #define BCM2835_AUX_SPI_IO 0x20 #define BCM2835_AUX_SPI_TXHOLD 0x30 /* Bitfields in CNTL0 */ #define BCM2835_AUX_SPI_CNTL0_SPEED 0xFFF00000 #define BCM2835_AUX_SPI_CNTL0_SPEED_MAX 0xFFF #define BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT 20 #define BCM2835_AUX_SPI_CNTL0_CS 0x000E0000 #define BCM2835_AUX_SPI_CNTL0_POSTINPUT 0x00010000 #define BCM2835_AUX_SPI_CNTL0_VAR_CS 0x00008000 #define BCM2835_AUX_SPI_CNTL0_VAR_WIDTH 0x00004000 #define BCM2835_AUX_SPI_CNTL0_DOUTHOLD 0x00003000 #define BCM2835_AUX_SPI_CNTL0_ENABLE 0x00000800 |
e9dd4edcc spi: bcm2835aux: ... |
64 |
#define BCM2835_AUX_SPI_CNTL0_IN_RISING 0x00000400 |
1ea29b39f spi: bcm2835aux: ... |
65 |
#define BCM2835_AUX_SPI_CNTL0_CLEARFIFO 0x00000200 |
e9dd4edcc spi: bcm2835aux: ... |
66 |
#define BCM2835_AUX_SPI_CNTL0_OUT_RISING 0x00000100 |
1ea29b39f spi: bcm2835aux: ... |
67 68 69 70 71 72 |
#define BCM2835_AUX_SPI_CNTL0_CPOL 0x00000080 #define BCM2835_AUX_SPI_CNTL0_MSBF_OUT 0x00000040 #define BCM2835_AUX_SPI_CNTL0_SHIFTLEN 0x0000003F /* Bitfields in CNTL1 */ #define BCM2835_AUX_SPI_CNTL1_CSHIGH 0x00000700 |
fe0e2304f spi: bcm2835aux: ... |
73 74 |
#define BCM2835_AUX_SPI_CNTL1_TXEMPTY 0x00000080 #define BCM2835_AUX_SPI_CNTL1_IDLE 0x00000040 |
1ea29b39f spi: bcm2835aux: ... |
75 76 77 78 79 80 81 82 83 84 85 86 |
#define BCM2835_AUX_SPI_CNTL1_MSBF_IN 0x00000002 #define BCM2835_AUX_SPI_CNTL1_KEEP_IN 0x00000001 /* Bitfields in STAT */ #define BCM2835_AUX_SPI_STAT_TX_LVL 0xFF000000 #define BCM2835_AUX_SPI_STAT_RX_LVL 0x00FF0000 #define BCM2835_AUX_SPI_STAT_TX_FULL 0x00000400 #define BCM2835_AUX_SPI_STAT_TX_EMPTY 0x00000200 #define BCM2835_AUX_SPI_STAT_RX_FULL 0x00000100 #define BCM2835_AUX_SPI_STAT_RX_EMPTY 0x00000080 #define BCM2835_AUX_SPI_STAT_BUSY 0x00000040 #define BCM2835_AUX_SPI_STAT_BITCOUNT 0x0000003F |
1ea29b39f spi: bcm2835aux: ... |
87 88 89 90 91 92 93 94 95 |
struct bcm2835aux_spi { void __iomem *regs; struct clk *clk; int irq; u32 cntl[2]; const u8 *tx_buf; u8 *rx_buf; int tx_len; int rx_len; |
72aac02b3 spi: bcm2835aux: ... |
96 |
int pending; |
8048d151e spi: bcm2835aux: ... |
97 98 99 100 101 102 |
u64 count_transfer_polling; u64 count_transfer_irq; u64 count_transfer_irq_after_poll; struct dentry *debugfs_dir; |
1ea29b39f spi: bcm2835aux: ... |
103 |
}; |
8048d151e spi: bcm2835aux: ... |
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
#if defined(CONFIG_DEBUG_FS) static void bcm2835aux_debugfs_create(struct bcm2835aux_spi *bs, const char *dname) { char name[64]; struct dentry *dir; /* get full name */ snprintf(name, sizeof(name), "spi-bcm2835aux-%s", dname); /* the base directory */ dir = debugfs_create_dir(name, NULL); bs->debugfs_dir = dir; /* the counters */ debugfs_create_u64("count_transfer_polling", 0444, dir, &bs->count_transfer_polling); debugfs_create_u64("count_transfer_irq", 0444, dir, &bs->count_transfer_irq); debugfs_create_u64("count_transfer_irq_after_poll", 0444, dir, &bs->count_transfer_irq_after_poll); } static void bcm2835aux_debugfs_remove(struct bcm2835aux_spi *bs) { debugfs_remove_recursive(bs->debugfs_dir); bs->debugfs_dir = NULL; } #else |
9b186e9a6 spi: bcm2835aux: ... |
133 134 |
static void bcm2835aux_debugfs_create(struct bcm2835aux_spi *bs, const char *dname) |
8048d151e spi: bcm2835aux: ... |
135 136 137 138 139 140 141 |
{ } static void bcm2835aux_debugfs_remove(struct bcm2835aux_spi *bs) { } #endif /* CONFIG_DEBUG_FS */ |
1ea29b39f spi: bcm2835aux: ... |
142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
static inline u32 bcm2835aux_rd(struct bcm2835aux_spi *bs, unsigned reg) { return readl(bs->regs + reg); } static inline void bcm2835aux_wr(struct bcm2835aux_spi *bs, unsigned reg, u32 val) { writel(val, bs->regs + reg); } static inline void bcm2835aux_rd_fifo(struct bcm2835aux_spi *bs) { u32 data; |
1ea29b39f spi: bcm2835aux: ... |
156 157 158 159 |
int count = min(bs->rx_len, 3); data = bcm2835aux_rd(bs, BCM2835_AUX_SPI_IO); if (bs->rx_buf) { |
72aac02b3 spi: bcm2835aux: ... |
160 |
switch (count) { |
72aac02b3 spi: bcm2835aux: ... |
161 162 163 164 165 166 167 168 169 170 |
case 3: *bs->rx_buf++ = (data >> 16) & 0xff; /* fallthrough */ case 2: *bs->rx_buf++ = (data >> 8) & 0xff; /* fallthrough */ case 1: *bs->rx_buf++ = (data >> 0) & 0xff; /* fallthrough - no default */ } |
1ea29b39f spi: bcm2835aux: ... |
171 172 |
} bs->rx_len -= count; |
72aac02b3 spi: bcm2835aux: ... |
173 |
bs->pending -= count; |
1ea29b39f spi: bcm2835aux: ... |
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
} static inline void bcm2835aux_wr_fifo(struct bcm2835aux_spi *bs) { u32 data; u8 byte; int count; int i; /* gather up to 3 bytes to write to the FIFO */ count = min(bs->tx_len, 3); data = 0; for (i = 0; i < count; i++) { byte = bs->tx_buf ? *bs->tx_buf++ : 0; data |= byte << (8 * (2 - i)); } /* and set the variable bit-length */ data |= (count * 8) << 24; /* and decrement length */ bs->tx_len -= count; |
72aac02b3 spi: bcm2835aux: ... |
196 |
bs->pending += count; |
1ea29b39f spi: bcm2835aux: ... |
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
/* write to the correct TX-register */ if (bs->tx_len) bcm2835aux_wr(bs, BCM2835_AUX_SPI_TXHOLD, data); else bcm2835aux_wr(bs, BCM2835_AUX_SPI_IO, data); } static void bcm2835aux_spi_reset_hw(struct bcm2835aux_spi *bs) { /* disable spi clearing fifo and interrupts */ bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, 0); bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, BCM2835_AUX_SPI_CNTL0_CLEARFIFO); } |
7188a6f0e spi: bcm2835aux: ... |
212 |
static void bcm2835aux_spi_transfer_helper(struct bcm2835aux_spi *bs) |
1ea29b39f spi: bcm2835aux: ... |
213 |
{ |
73b114ee7 spi: bcm2835aux: ... |
214 |
u32 stat = bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT); |
1ea29b39f spi: bcm2835aux: ... |
215 |
/* check if we have data to read */ |
73b114ee7 spi: bcm2835aux: ... |
216 217 |
for (; bs->rx_len && (stat & BCM2835_AUX_SPI_STAT_RX_LVL); stat = bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT)) |
1ea29b39f spi: bcm2835aux: ... |
218 |
bcm2835aux_rd_fifo(bs); |
1ea29b39f spi: bcm2835aux: ... |
219 220 221 |
/* check if we have data to write */ while (bs->tx_len && |
72aac02b3 spi: bcm2835aux: ... |
222 |
(bs->pending < 12) && |
1ea29b39f spi: bcm2835aux: ... |
223 224 225 |
(!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) & BCM2835_AUX_SPI_STAT_TX_FULL))) { bcm2835aux_wr_fifo(bs); |
1ea29b39f spi: bcm2835aux: ... |
226 |
} |
7188a6f0e spi: bcm2835aux: ... |
227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
} static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id) { struct spi_master *master = dev_id; struct bcm2835aux_spi *bs = spi_master_get_devdata(master); /* IRQ may be shared, so return if our interrupts are disabled */ if (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_CNTL1) & (BCM2835_AUX_SPI_CNTL1_TXEMPTY | BCM2835_AUX_SPI_CNTL1_IDLE))) return IRQ_NONE; /* do common fifo handling */ bcm2835aux_spi_transfer_helper(bs); |
1ea29b39f spi: bcm2835aux: ... |
241 |
|
f29ab1845 spi: bcm2835aux: ... |
242 243 244 245 246 |
if (!bs->tx_len) { /* disable tx fifo empty interrupt */ bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1] | BCM2835_AUX_SPI_CNTL1_IDLE); } |
b4e2adef6 spi: bcm2835aux: ... |
247 |
/* and if rx_len is 0 then disable interrupts and wake up completion */ |
1ea29b39f spi: bcm2835aux: ... |
248 |
if (!bs->rx_len) { |
b4e2adef6 spi: bcm2835aux: ... |
249 |
bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]); |
1ea29b39f spi: bcm2835aux: ... |
250 251 |
complete(&master->xfer_completion); } |
7188a6f0e spi: bcm2835aux: ... |
252 |
return IRQ_HANDLED; |
1ea29b39f spi: bcm2835aux: ... |
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
} static int __bcm2835aux_spi_transfer_one_irq(struct spi_master *master, struct spi_device *spi, struct spi_transfer *tfr) { struct bcm2835aux_spi *bs = spi_master_get_devdata(master); /* enable interrupts */ bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1] | BCM2835_AUX_SPI_CNTL1_TXEMPTY | BCM2835_AUX_SPI_CNTL1_IDLE); /* and wait for finish... */ return 1; } static int bcm2835aux_spi_transfer_one_irq(struct spi_master *master, struct spi_device *spi, struct spi_transfer *tfr) { struct bcm2835aux_spi *bs = spi_master_get_devdata(master); |
8048d151e spi: bcm2835aux: ... |
275 276 |
/* update statistics */ bs->count_transfer_irq++; |
1ea29b39f spi: bcm2835aux: ... |
277 278 279 280 281 282 |
/* fill in registers and fifos before enabling interrupts */ bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]); bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]); /* fill in tx fifo with data before enabling interrupts */ while ((bs->tx_len) && |
72aac02b3 spi: bcm2835aux: ... |
283 |
(bs->pending < 12) && |
1ea29b39f spi: bcm2835aux: ... |
284 285 286 287 288 289 290 291 292 293 294 |
(!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) & BCM2835_AUX_SPI_STAT_TX_FULL))) { bcm2835aux_wr_fifo(bs); } /* now run the interrupt mode */ return __bcm2835aux_spi_transfer_one_irq(master, spi, tfr); } static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master, struct spi_device *spi, |
72aac02b3 spi: bcm2835aux: ... |
295 |
struct spi_transfer *tfr) |
1ea29b39f spi: bcm2835aux: ... |
296 297 298 |
{ struct bcm2835aux_spi *bs = spi_master_get_devdata(master); unsigned long timeout; |
1ea29b39f spi: bcm2835aux: ... |
299 |
|
8048d151e spi: bcm2835aux: ... |
300 301 |
/* update statistics */ bs->count_transfer_polling++; |
1ea29b39f spi: bcm2835aux: ... |
302 303 304 |
/* configure spi */ bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]); bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]); |
5fd917afc spi: bcm2835aux: ... |
305 306 |
/* set the timeout to at least 2 jiffies */ timeout = jiffies + 2 + HZ * polling_limit_us / 1000000; |
1ea29b39f spi: bcm2835aux: ... |
307 308 309 |
/* loop until finished the transfer */ while (bs->rx_len) { |
1ea29b39f spi: bcm2835aux: ... |
310 |
|
7188a6f0e spi: bcm2835aux: ... |
311 312 |
/* do common fifo handling */ bcm2835aux_spi_transfer_helper(bs); |
1ea29b39f spi: bcm2835aux: ... |
313 314 315 316 317 318 319 320 321 |
/* there is still data pending to read check the timeout */ if (bs->rx_len && time_after(jiffies, timeout)) { dev_dbg_ratelimited(&spi->dev, "timeout period reached: jiffies: %lu remaining tx/rx: %d/%d - falling back to interrupt mode ", jiffies - timeout, bs->tx_len, bs->rx_len); /* forward to interrupt handler */ |
8048d151e spi: bcm2835aux: ... |
322 |
bs->count_transfer_irq_after_poll++; |
1ea29b39f spi: bcm2835aux: ... |
323 324 325 326 |
return __bcm2835aux_spi_transfer_one_irq(master, spi, tfr); } } |
1ea29b39f spi: bcm2835aux: ... |
327 328 329 330 331 332 333 334 335 |
/* and return without waiting for completion */ return 0; } static int bcm2835aux_spi_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *tfr) { struct bcm2835aux_spi *bs = spi_master_get_devdata(master); |
5fd917afc spi: bcm2835aux: ... |
336 337 |
unsigned long spi_hz, clk_hz, speed, spi_used_hz; unsigned long hz_per_byte, byte_limit; |
1ea29b39f spi: bcm2835aux: ... |
338 339 340 341 342 343 344 345 |
/* calculate the registers to handle * * note that we use the variable data mode, which * is not optimal for longer transfers as we waste registers * resulting (potentially) in more interrupts when transferring * more than 12 bytes */ |
1ea29b39f spi: bcm2835aux: ... |
346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
/* set clock */ spi_hz = tfr->speed_hz; clk_hz = clk_get_rate(bs->clk); if (spi_hz >= clk_hz / 2) { speed = 0; } else if (spi_hz) { speed = DIV_ROUND_UP(clk_hz, 2 * spi_hz) - 1; if (speed > BCM2835_AUX_SPI_CNTL0_SPEED_MAX) speed = BCM2835_AUX_SPI_CNTL0_SPEED_MAX; } else { /* the slowest we can go */ speed = BCM2835_AUX_SPI_CNTL0_SPEED_MAX; } |
b4e2adef6 spi: bcm2835aux: ... |
360 361 362 |
/* mask out old speed from previous spi_transfer */ bs->cntl[0] &= ~(BCM2835_AUX_SPI_CNTL0_SPEED); /* set the new speed */ |
1ea29b39f spi: bcm2835aux: ... |
363 364 365 |
bs->cntl[0] |= speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT; spi_used_hz = clk_hz / (2 * (speed + 1)); |
1ea29b39f spi: bcm2835aux: ... |
366 367 368 369 370 |
/* set transmit buffers and length */ bs->tx_buf = tfr->tx_buf; bs->rx_buf = tfr->rx_buf; bs->tx_len = tfr->len; bs->rx_len = tfr->len; |
72aac02b3 spi: bcm2835aux: ... |
371 |
bs->pending = 0; |
1ea29b39f spi: bcm2835aux: ... |
372 |
|
d704afffe spi: bcm2835aux: ... |
373 374 375 376 377 378 |
/* Calculate the estimated time in us the transfer runs. Note that * there are are 2 idle clocks cycles after each chunk getting * transferred - in our case the chunk size is 3 bytes, so we * approximate this by 9 cycles/byte. This is used to find the number * of Hz per byte per polling limit. E.g., we can transfer 1 byte in * 30 µs per 300,000 Hz of bus clock. |
72aac02b3 spi: bcm2835aux: ... |
379 |
*/ |
5fd917afc spi: bcm2835aux: ... |
380 381 |
hz_per_byte = polling_limit_us ? (9 * 1000000) / polling_limit_us : 0; byte_limit = hz_per_byte ? spi_used_hz / hz_per_byte : 1; |
1ea29b39f spi: bcm2835aux: ... |
382 |
/* run in polling mode for short transfers */ |
5fd917afc spi: bcm2835aux: ... |
383 |
if (tfr->len < byte_limit) |
72aac02b3 spi: bcm2835aux: ... |
384 |
return bcm2835aux_spi_transfer_one_poll(master, spi, tfr); |
1ea29b39f spi: bcm2835aux: ... |
385 386 387 388 |
/* run in interrupt mode for all others */ return bcm2835aux_spi_transfer_one_irq(master, spi, tfr); } |
b4e2adef6 spi: bcm2835aux: ... |
389 390 391 392 393 394 395 396 397 398 399 400 |
static int bcm2835aux_spi_prepare_message(struct spi_master *master, struct spi_message *msg) { struct spi_device *spi = msg->spi; struct bcm2835aux_spi *bs = spi_master_get_devdata(master); bs->cntl[0] = BCM2835_AUX_SPI_CNTL0_ENABLE | BCM2835_AUX_SPI_CNTL0_VAR_WIDTH | BCM2835_AUX_SPI_CNTL0_MSBF_OUT; bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN; /* handle all the modes */ |
e9dd4edcc spi: bcm2835aux: ... |
401 |
if (spi->mode & SPI_CPOL) { |
b4e2adef6 spi: bcm2835aux: ... |
402 |
bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL; |
e9dd4edcc spi: bcm2835aux: ... |
403 404 405 406 |
bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_OUT_RISING; } else { bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_IN_RISING; } |
b4e2adef6 spi: bcm2835aux: ... |
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 |
bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]); bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]); return 0; } static int bcm2835aux_spi_unprepare_message(struct spi_master *master, struct spi_message *msg) { struct bcm2835aux_spi *bs = spi_master_get_devdata(master); bcm2835aux_spi_reset_hw(bs); return 0; } |
1ea29b39f spi: bcm2835aux: ... |
422 423 424 425 426 427 428 |
static void bcm2835aux_spi_handle_err(struct spi_master *master, struct spi_message *msg) { struct bcm2835aux_spi *bs = spi_master_get_devdata(master); bcm2835aux_spi_reset_hw(bs); } |
519f2c22a spi: bcm2835aux: ... |
429 430 431 432 433 434 435 |
static int bcm2835aux_spi_setup(struct spi_device *spi) { int ret; /* sanity check for native cs */ if (spi->mode & SPI_NO_CS) return 0; |
ccd978b70 spi: bcm2835aux: ... |
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 |
if (gpio_is_valid(spi->cs_gpio)) { /* with gpio-cs set the GPIO to the correct level * and as output (in case the dt has the gpio not configured * as output but native cs) */ ret = gpio_direction_output(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ? 0 : 1); if (ret) dev_err(&spi->dev, "could not set gpio %i as output: %i ", spi->cs_gpio, ret); return ret; } |
519f2c22a spi: bcm2835aux: ... |
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 |
/* for dt-backwards compatibility: only support native on CS0 * known things not supported with broken native CS: * * multiple chip-selects: cs0-cs2 are all * simultaniously asserted whenever there is a transfer * this even includes SPI_NO_CS * * SPI_CS_HIGH: cs are always asserted low * * cs_change: cs is deasserted after each spi_transfer * * cs_delay_usec: cs is always deasserted one SCK cycle * after the last transfer * probably more... */ dev_warn(&spi->dev, "Native CS is not supported - please configure cs-gpio in device-tree "); if (spi->chip_select == 0) return 0; dev_warn(&spi->dev, "Native CS is not working for cs > 0 "); return -EINVAL; } |
1ea29b39f spi: bcm2835aux: ... |
475 476 477 478 |
static int bcm2835aux_spi_probe(struct platform_device *pdev) { struct spi_master *master; struct bcm2835aux_spi *bs; |
1ea29b39f spi: bcm2835aux: ... |
479 480 481 482 |
unsigned long clk_hz; int err; master = spi_alloc_master(&pdev->dev, sizeof(*bs)); |
bf93b9512 spi: bcm2835aux: ... |
483 |
if (!master) |
1ea29b39f spi: bcm2835aux: ... |
484 |
return -ENOMEM; |
1ea29b39f spi: bcm2835aux: ... |
485 486 |
platform_set_drvdata(pdev, master); |
e9dd4edcc spi: bcm2835aux: ... |
487 |
master->mode_bits = (SPI_CPOL | SPI_CS_HIGH | SPI_NO_CS); |
1ea29b39f spi: bcm2835aux: ... |
488 |
master->bits_per_word_mask = SPI_BPW_MASK(8); |
509c58362 spi: bcm2835aux: ... |
489 490 491 492 493 494 495 496 497 498 499 500 |
/* even though the driver never officially supported native CS * allow a single native CS for legacy DT support purposes when * no cs-gpio is configured. * Known limitations for native cs are: * * multiple chip-selects: cs0-cs2 are all simultaniously asserted * whenever there is a transfer - this even includes SPI_NO_CS * * SPI_CS_HIGH: is ignores - cs are always asserted low * * cs_change: cs is deasserted after each spi_transfer * * cs_delay_usec: cs is always deasserted one SCK cycle after * a spi_transfer */ master->num_chipselect = 1; |
519f2c22a spi: bcm2835aux: ... |
501 |
master->setup = bcm2835aux_spi_setup; |
1ea29b39f spi: bcm2835aux: ... |
502 503 |
master->transfer_one = bcm2835aux_spi_transfer_one; master->handle_err = bcm2835aux_spi_handle_err; |
b4e2adef6 spi: bcm2835aux: ... |
504 505 |
master->prepare_message = bcm2835aux_spi_prepare_message; master->unprepare_message = bcm2835aux_spi_unprepare_message; |
1ea29b39f spi: bcm2835aux: ... |
506 507 508 509 510 |
master->dev.of_node = pdev->dev.of_node; bs = spi_master_get_devdata(master); /* the main area */ |
d1975d059 spi: bcm2835aux: ... |
511 |
bs->regs = devm_platform_ioremap_resource(pdev, 0); |
1ea29b39f spi: bcm2835aux: ... |
512 513 514 515 516 517 |
if (IS_ERR(bs->regs)) { err = PTR_ERR(bs->regs); goto out_master_put; } bs->clk = devm_clk_get(&pdev->dev, NULL); |
bfc7af6d6 spi: bcm2835aux: ... |
518 |
if (IS_ERR(bs->clk)) { |
1ea29b39f spi: bcm2835aux: ... |
519 520 521 522 523 |
err = PTR_ERR(bs->clk); dev_err(&pdev->dev, "could not get clk: %d ", err); goto out_master_put; } |
07bce09e1 spi: bcm2835aux: ... |
524 |
bs->irq = platform_get_irq(pdev, 0); |
1ea29b39f spi: bcm2835aux: ... |
525 |
if (bs->irq <= 0) { |
1ea29b39f spi: bcm2835aux: ... |
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 |
err = bs->irq ? bs->irq : -ENODEV; goto out_master_put; } /* this also enables the HW block */ err = clk_prepare_enable(bs->clk); if (err) { dev_err(&pdev->dev, "could not prepare clock: %d ", err); goto out_master_put; } /* just checking if the clock returns a sane value */ clk_hz = clk_get_rate(bs->clk); if (!clk_hz) { dev_err(&pdev->dev, "clock returns 0 Hz "); err = -ENODEV; goto out_clk_disable; } |
07bce09e1 spi: bcm2835aux: ... |
546 547 |
/* reset SPI-HW block */ bcm2835aux_spi_reset_hw(bs); |
1ea29b39f spi: bcm2835aux: ... |
548 549 550 551 552 553 554 555 556 |
err = devm_request_irq(&pdev->dev, bs->irq, bcm2835aux_spi_interrupt, IRQF_SHARED, dev_name(&pdev->dev), master); if (err) { dev_err(&pdev->dev, "could not request IRQ: %d ", err); goto out_clk_disable; } |
1ea29b39f spi: bcm2835aux: ... |
557 558 559 560 561 562 |
err = devm_spi_register_master(&pdev->dev, master); if (err) { dev_err(&pdev->dev, "could not register SPI master: %d ", err); goto out_clk_disable; } |
8048d151e spi: bcm2835aux: ... |
563 |
bcm2835aux_debugfs_create(bs, dev_name(&pdev->dev)); |
1ea29b39f spi: bcm2835aux: ... |
564 565 566 567 568 569 570 571 572 573 574 575 576 |
return 0; out_clk_disable: clk_disable_unprepare(bs->clk); out_master_put: spi_master_put(master); return err; } static int bcm2835aux_spi_remove(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); struct bcm2835aux_spi *bs = spi_master_get_devdata(master); |
8048d151e spi: bcm2835aux: ... |
577 |
bcm2835aux_debugfs_remove(bs); |
1ea29b39f spi: bcm2835aux: ... |
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 |
bcm2835aux_spi_reset_hw(bs); /* disable the HW block by releasing the clock */ clk_disable_unprepare(bs->clk); return 0; } static const struct of_device_id bcm2835aux_spi_match[] = { { .compatible = "brcm,bcm2835-aux-spi", }, {} }; MODULE_DEVICE_TABLE(of, bcm2835aux_spi_match); static struct platform_driver bcm2835aux_spi_driver = { .driver = { .name = "spi-bcm2835aux", .of_match_table = bcm2835aux_spi_match, }, .probe = bcm2835aux_spi_probe, .remove = bcm2835aux_spi_remove, }; module_platform_driver(bcm2835aux_spi_driver); MODULE_DESCRIPTION("SPI controller driver for Broadcom BCM2835 aux"); MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>"); |
22bf6cd2c spi: bcm2835: mak... |
604 |
MODULE_LICENSE("GPL"); |