1 | /* |
---|
2 | * SPICTRL SPI driver implmenetation |
---|
3 | * |
---|
4 | * COPYRIGHT (c) 2009. |
---|
5 | * Cobham Gaisler AB. |
---|
6 | * |
---|
7 | * The license and distribution terms for this file may be |
---|
8 | * found in the file LICENSE in this distribution or at |
---|
9 | * http://www.rtems.com/license/LICENSE. |
---|
10 | */ |
---|
11 | |
---|
12 | #include <bsp.h> |
---|
13 | #include <rtems/libio.h> |
---|
14 | #include <stdlib.h> |
---|
15 | #include <assert.h> |
---|
16 | #include <rtems/bspIo.h> |
---|
17 | #include <string.h> |
---|
18 | #include <stdio.h> |
---|
19 | |
---|
20 | #include <drvmgr/drvmgr.h> |
---|
21 | #include <drvmgr/ambapp_bus.h> |
---|
22 | #include <spictrl.h> |
---|
23 | #include <ambapp.h> |
---|
24 | |
---|
25 | #include <rtems/libi2c.h> |
---|
26 | |
---|
27 | /*#define DEBUG 1*/ |
---|
28 | |
---|
29 | #ifdef DEBUG |
---|
30 | #define DBG(x...) printk(x) |
---|
31 | #define STATIC |
---|
32 | #else |
---|
33 | #define DBG(x...) |
---|
34 | #define STATIC static |
---|
35 | #endif |
---|
36 | |
---|
37 | /*** CAPABILITY REGISTER 0x00 ***/ |
---|
38 | #define SPICTRL_CAP_SSSZ_BIT 24 |
---|
39 | #define SPICTRL_CAP_AMODE_BIT 18 |
---|
40 | #define SPICTRL_CAP_ASELA_BIT 17 |
---|
41 | #define SPICTRL_CAP_SSEN_BIT 16 |
---|
42 | #define SPICTRL_CAP_FDEPTH_BIT 8 |
---|
43 | #define SPICTRL_CAP_REV_BIT 0 |
---|
44 | |
---|
45 | #define SPICTRL_CAP_SSSZ (0xff << SPICTRL_CAP_SSSZ_BIT) |
---|
46 | #define SPICTRL_CAP_AMODE (1<<SPICTRL_CAP_AMODE_BIT) |
---|
47 | #define SPICTRL_CAP_ASELA (1<<SPICTRL_CAP_ASELA_BIT) |
---|
48 | #define SPICTRL_CAP_SSEN (1 << SPICTRL_CAP_SSEN_BIT) |
---|
49 | #define SPICTRL_CAP_FDEPTH (0xff << SPICTRL_CAP_FDEPTH_BIT) |
---|
50 | #define SPICTRL_CAP_REV (0xff << SPICTRL_CAP_REV_BIT) |
---|
51 | |
---|
52 | /*** MODE REGISTER 0x20 ***/ |
---|
53 | #define SPICTRL_MODE_AMEN_BIT 31 |
---|
54 | #define SPICTRL_MODE_LOOP_BIT 30 |
---|
55 | #define SPICTRL_MODE_CPOL_BIT 29 |
---|
56 | #define SPICTRL_MODE_CPHA_BIT 28 |
---|
57 | #define SPICTRL_MODE_DIV16_BIT 27 |
---|
58 | #define SPICTRL_MODE_REV_BIT 26 |
---|
59 | #define SPICTRL_MODE_MS_BIT 25 |
---|
60 | #define SPICTRL_MODE_EN_BIT 24 |
---|
61 | #define SPICTRL_MODE_LEN_BIT 20 |
---|
62 | #define SPICTRL_MODE_PM_BIT 16 |
---|
63 | #define SPICTRL_MODE_ASEL_BIT 14 |
---|
64 | #define SPICTRL_MODE_FACT_BIT 13 |
---|
65 | #define SPICTRL_MODE_CG_BIT 7 |
---|
66 | #define SPICTRL_MODE_TAC_BIT 4 |
---|
67 | |
---|
68 | #define SPICTRL_MODE_AMEN (1 << SPICTRL_MODE_AMEN_BIT) |
---|
69 | #define SPICTRL_MODE_LOOP (1 << SPICTRL_MODE_LOOP_BIT) |
---|
70 | #define SPICTRL_MODE_CPOL (1 << SPICTRL_MODE_CPOL_BIT) |
---|
71 | #define SPICTRL_MODE_CPHA (1 << SPICTRL_MODE_CPHA_BIT) |
---|
72 | #define SPICTRL_MODE_DIV16 (1 << SPICTRL_MODE_DIV16_BIT) |
---|
73 | #define SPICTRL_MODE_REV (1 << SPICTRL_MODE_REV_BIT) |
---|
74 | #define SPICTRL_MODE_MS (1 << SPICTRL_MODE_MS_BIT) |
---|
75 | #define SPICTRL_MODE_EN (1 << SPICTRL_MODE_EN_BIT) |
---|
76 | #define SPICTRL_MODE_LEN (0xf << SPICTRL_MODE_LEN_BIT) |
---|
77 | #define SPICTRL_MODE_PM (0xf << SPICTRL_MODE_PM_BIT) |
---|
78 | #define SPICTRL_MODE_ASEL (1 << SPICTRL_MODE_ASEL_BIT) |
---|
79 | #define SPICTRL_MODE_FACT (1 << SPICTRL_MODE_FACT_BIT) |
---|
80 | #define SPICTRL_MODE_CG (0x1f << SPICTRL_MODE_CG_BIT) |
---|
81 | #define SPICTRL_MODE_TAC (0x1 << SPICTRL_MODE_TAC_BIT) |
---|
82 | |
---|
83 | /*** EVENT REGISTER 0x24 ***/ |
---|
84 | #define SPICTRL_EVENT_AT_BIT 15 |
---|
85 | #define SPICTRL_EVENT_LT_BIT 14 |
---|
86 | #define SPICTRL_EVENT_OV_BIT 12 |
---|
87 | #define SPICTRL_EVENT_UN_BIT 11 |
---|
88 | #define SPICTRL_EVENT_MME_BIT 10 |
---|
89 | #define SPICTRL_EVENT_NE_BIT 9 |
---|
90 | #define SPICTRL_EVENT_NF_BIT 8 |
---|
91 | |
---|
92 | #define SPICTRL_EVENT_AT (1 << SPICTRL_EVENT_AT_BIT) |
---|
93 | #define SPICTRL_EVENT_LT (1 << SPICTRL_EVENT_LT_BIT) |
---|
94 | #define SPICTRL_EVENT_OV (1 << SPICTRL_EVENT_OV_BIT) |
---|
95 | #define SPICTRL_EVENT_UN (1 << SPICTRL_EVENT_UN_BIT) |
---|
96 | #define SPICTRL_EVENT_MME (1 << SPICTRL_EVENT_MME_BIT) |
---|
97 | #define SPICTRL_EVENT_NE (1 << SPICTRL_EVENT_NE_BIT) |
---|
98 | #define SPICTRL_EVENT_NF (1 << SPICTRL_EVENT_NF_BIT) |
---|
99 | |
---|
100 | /*** MASK REGISTER 0x28 ***/ |
---|
101 | #define SPICTRL_MASK_ATE_BIT 15 |
---|
102 | #define SPICTRL_MASK_LTE_BIT 14 |
---|
103 | #define SPICTRL_MASK_OVE_BIT 12 |
---|
104 | #define SPICTRL_MASK_UNE_BIT 11 |
---|
105 | #define SPICTRL_MASK_MMEE_BIT 10 |
---|
106 | #define SPICTRL_MASK_NEE_BIT 9 |
---|
107 | #define SPICTRL_MASK_NFE_BIT 8 |
---|
108 | |
---|
109 | #define SPICTRL_MASK_ATE (1 << SPICTRL_MASK_ATE_BIT) |
---|
110 | #define SPICTRL_MASK_LTE (1 << SPICTRL_MASK_LTE_BIT) |
---|
111 | #define SPICTRL_MASK_OVE (1 << SPICTRL_MASK_OVE_BIT) |
---|
112 | #define SPICTRL_MASK_UNE (1 << SPICTRL_MASK_UNE_BIT) |
---|
113 | #define SPICTRL_MASK_MMEE (1 << SPICTRL_MASK_MMEE_BIT) |
---|
114 | #define SPICTRL_MASK_NEE (1 << SPICTRL_MASK_NEE_BIT) |
---|
115 | #define SPICTRL_MASK_NFE (1 << SPICTRL_MASK_NFE_BIT) |
---|
116 | |
---|
117 | /*** COMMAND REGISTER 0x2c ***/ |
---|
118 | #define SPICTRL_CMD_LST_BIT 22 |
---|
119 | #define SPICTRL_CMD_LST (1 << SPICTRL_CMD_LST_BIT) |
---|
120 | |
---|
121 | /*** TRANSMIT REGISTER 0x30 ***/ |
---|
122 | #define SPICTRL_TX_TDATA_BIT 0 |
---|
123 | #define SPICTRL_TX_TDATA 0xffffffff |
---|
124 | |
---|
125 | /*** RECEIVE REGISTER 0x34 ***/ |
---|
126 | #define SPICTRL_RX_RDATA_BIT 0 |
---|
127 | #define SPICTRL_RX_RDATA 0xffffffff |
---|
128 | |
---|
129 | /*** SLAVE SELECT REGISTER 0x38 - VARIABLE ***/ |
---|
130 | |
---|
131 | /*** AM CONFIGURATION REGISTER 0x40 ***/ |
---|
132 | #define SPICTRL_AMCFG_ERPT_BIT 6 |
---|
133 | #define SPICTRL_AMCFG_SEQ_BIT 5 |
---|
134 | #define SPICTRL_AMCFG_STRICT_BIT 4 |
---|
135 | #define SPICTRL_AMCFG_OVTB_BIT 3 |
---|
136 | #define SPICTRL_AMCFG_OVDB_BIT 2 |
---|
137 | #define SPICTRL_AMCFG_ACT_BIT 1 |
---|
138 | #define SPICTRL_AMCFG_EACT_BIT 0 |
---|
139 | |
---|
140 | #define SPICTRL_AMCFG_ERPT (1<<SPICTRL_AMCFG_ERPT_BIT) |
---|
141 | #define SPICTRL_AMCFG_SEQ (1<<SPICTRL_AMCFG_SEQ_BIT) |
---|
142 | #define SPICTRL_AMCFG_STRICT (1<<SPICTRL_AMCFG_STRICT_BIT) |
---|
143 | #define SPICTRL_AMCFG_OVTB (1<<SPICTRL_AMCFG_OVTB_BIT) |
---|
144 | #define SPICTRL_AMCFG_OVDB (1<<SPICTRL_AMCFG_OVDB_BIT) |
---|
145 | #define SPICTRL_AMCFG_ACT (1<<SPICTRL_AMCFG_ACT_BIT) |
---|
146 | #define SPICTRL_AMCFG_EACT (1<<SPICTRL_AMCFG_EACT_BIT) |
---|
147 | |
---|
148 | struct spictrl_priv { |
---|
149 | rtems_libi2c_bus_t i2clib_desc; |
---|
150 | struct drvmgr_dev *dev; |
---|
151 | struct spictrl_regs *regs; |
---|
152 | int irq; |
---|
153 | int minor; |
---|
154 | unsigned int core_freq_hz; |
---|
155 | |
---|
156 | /* Driver */ |
---|
157 | int fdepth; |
---|
158 | int bits_per_char; |
---|
159 | int lsb_first; |
---|
160 | int txshift; |
---|
161 | int rxshift; |
---|
162 | unsigned int idle_char; |
---|
163 | int (*slvSelFunc)(void *regs, uint32_t addr, int select); |
---|
164 | |
---|
165 | /* Automated Periodic transfers */ |
---|
166 | int periodic_started; |
---|
167 | struct spictrl_ioctl_config periodic_cfg; |
---|
168 | }; |
---|
169 | |
---|
170 | /******************* Driver Manager Part ***********************/ |
---|
171 | |
---|
172 | int spictrl_device_init(struct spictrl_priv *priv); |
---|
173 | |
---|
174 | int spictrl_init2(struct drvmgr_dev *dev); |
---|
175 | int spictrl_init3(struct drvmgr_dev *dev); |
---|
176 | |
---|
177 | struct drvmgr_drv_ops spictrl_ops = |
---|
178 | { |
---|
179 | .init = {NULL, spictrl_init2, spictrl_init3, NULL}, |
---|
180 | .remove = NULL, |
---|
181 | .info = NULL |
---|
182 | }; |
---|
183 | |
---|
184 | struct amba_dev_id spictrl_ids[] = |
---|
185 | { |
---|
186 | {VENDOR_GAISLER, GAISLER_SPICTRL}, |
---|
187 | {0, 0} /* Mark end of table */ |
---|
188 | }; |
---|
189 | |
---|
190 | struct amba_drv_info spictrl_drv_info = |
---|
191 | { |
---|
192 | { |
---|
193 | DRVMGR_OBJ_DRV, /* Driver */ |
---|
194 | NULL, /* Next driver */ |
---|
195 | NULL, /* Device list */ |
---|
196 | DRIVER_AMBAPP_GAISLER_SPICTRL_ID, /* Driver ID */ |
---|
197 | "SPICTRL_DRV", /* Driver Name */ |
---|
198 | DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */ |
---|
199 | &spictrl_ops, |
---|
200 | NULL, /* Funcs */ |
---|
201 | 0, /* No devices yet */ |
---|
202 | 0, |
---|
203 | }, |
---|
204 | &spictrl_ids[0] |
---|
205 | }; |
---|
206 | |
---|
207 | void spictrl_register_drv (void) |
---|
208 | { |
---|
209 | DBG("Registering SPICTRL driver\n"); |
---|
210 | drvmgr_drv_register(&spictrl_drv_info.general); |
---|
211 | } |
---|
212 | |
---|
213 | int spictrl_init2(struct drvmgr_dev *dev) |
---|
214 | { |
---|
215 | struct spictrl_priv *priv; |
---|
216 | |
---|
217 | DBG("SPICTRL[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name); |
---|
218 | |
---|
219 | priv = dev->priv = malloc(sizeof(struct spictrl_priv)); |
---|
220 | if ( !priv ) |
---|
221 | return DRVMGR_NOMEM; |
---|
222 | memset(priv, 0, sizeof(*priv)); |
---|
223 | priv->dev = dev; |
---|
224 | |
---|
225 | /* This core will not find other cores, so we wait for init2() */ |
---|
226 | |
---|
227 | return DRVMGR_OK; |
---|
228 | } |
---|
229 | |
---|
230 | int spictrl_init3(struct drvmgr_dev *dev) |
---|
231 | { |
---|
232 | struct spictrl_priv *priv; |
---|
233 | char prefix[32]; |
---|
234 | char devName[32]; |
---|
235 | int rc; |
---|
236 | |
---|
237 | priv = (struct spictrl_priv *)dev->priv; |
---|
238 | |
---|
239 | /* Do initialization */ |
---|
240 | |
---|
241 | /* Initialize i2c library */ |
---|
242 | rc = rtems_libi2c_initialize(); |
---|
243 | if (rc != 0) { |
---|
244 | DBG("SPICTRL: rtems_libi2c_initialize failed, exiting...\n"); |
---|
245 | free(dev->priv); |
---|
246 | dev->priv = NULL; |
---|
247 | return DRVMGR_FAIL; |
---|
248 | } |
---|
249 | |
---|
250 | /* I/O system registered and initialized |
---|
251 | * Now we take care of device initialization. |
---|
252 | */ |
---|
253 | |
---|
254 | /* Get frequency */ |
---|
255 | if ( drvmgr_freq_get(dev, DEV_APB_SLV, &priv->core_freq_hz) ) { |
---|
256 | return DRVMGR_FAIL; |
---|
257 | } |
---|
258 | |
---|
259 | if ( spictrl_device_init(priv) ) { |
---|
260 | free(dev->priv); |
---|
261 | dev->priv = NULL; |
---|
262 | return DRVMGR_FAIL; |
---|
263 | } |
---|
264 | |
---|
265 | /* Get Filesystem name prefix */ |
---|
266 | prefix[0] = '\0'; |
---|
267 | if ( drvmgr_get_dev_prefix(dev, prefix) ) { |
---|
268 | /* Failed to get prefix, make sure of a unique FS name |
---|
269 | * by using the driver minor. |
---|
270 | */ |
---|
271 | sprintf(devName, "/dev/spi%d", dev->minor_drv+1); |
---|
272 | } else { |
---|
273 | /* Got special prefix, this means we have a bus prefix |
---|
274 | * And we should use our "bus minor" |
---|
275 | */ |
---|
276 | sprintf(devName, "/dev/%sspi%d", prefix, dev->minor_bus+1); |
---|
277 | } |
---|
278 | |
---|
279 | /* Register Bus for this Device */ |
---|
280 | rc = rtems_libi2c_register_bus(devName, &priv->i2clib_desc); |
---|
281 | if (rc < 0) { |
---|
282 | DBG("SPICTRL: rtems_libi2c_register_bus(%s) failed\n", devName); |
---|
283 | free(dev->priv); |
---|
284 | dev->priv = NULL; |
---|
285 | return DRVMGR_FAIL; |
---|
286 | } |
---|
287 | priv->minor = rc; |
---|
288 | |
---|
289 | return DRVMGR_OK; |
---|
290 | } |
---|
291 | |
---|
292 | /******************* Driver Implementation ***********************/ |
---|
293 | |
---|
294 | STATIC rtems_status_code spictrl_libi2c_send_addr(rtems_libi2c_bus_t *bushdl, |
---|
295 | uint32_t addr, int rw); |
---|
296 | |
---|
297 | /* Set as high frequency of SCK as possible but not higher than |
---|
298 | * requested frequency (freq). |
---|
299 | */ |
---|
300 | static int spictrl_set_freq(struct spictrl_priv *priv, unsigned int freq) |
---|
301 | { |
---|
302 | unsigned int core_freq_hz = priv->core_freq_hz; |
---|
303 | unsigned int lowest_freq_possible; |
---|
304 | unsigned int div, div16, pm, fact; |
---|
305 | |
---|
306 | /* Lowest possible when DIV16 is set and PM is 0xf */ |
---|
307 | lowest_freq_possible = core_freq_hz / (16 * 4 * (0xf + 1)); |
---|
308 | |
---|
309 | if ( freq < lowest_freq_possible ) { |
---|
310 | DBG("SPICTRL: TOO LOW FREQ %u, CORE FREQ %u, LOWEST FREQ %u\n", |
---|
311 | freq, core_freq_hz, lowest_freq_possible); |
---|
312 | return -1; |
---|
313 | } |
---|
314 | |
---|
315 | div = ((core_freq_hz / 2) + (freq-1)) / freq; |
---|
316 | DBG("SPICTRL: DIV=%d, FREQ=%d\n", div, freq); |
---|
317 | |
---|
318 | /* Is DIV16 neccessary? */ |
---|
319 | if ( div > 16 ) { |
---|
320 | div = (div + (16 - 1)) / 16; |
---|
321 | div16 = 1; |
---|
322 | } else { |
---|
323 | div16 = 0; |
---|
324 | } |
---|
325 | |
---|
326 | if ( div > 0xf ) { |
---|
327 | fact = 0; /* FACT adds an factor /2 */ |
---|
328 | div = (div + (2 - 1)) / 2; |
---|
329 | } else { |
---|
330 | fact = 1; |
---|
331 | } |
---|
332 | |
---|
333 | pm = div-1; |
---|
334 | |
---|
335 | /* Update hardware */ |
---|
336 | priv->regs->mode = |
---|
337 | (priv->regs->mode & ~(SPICTRL_MODE_PM|SPICTRL_MODE_DIV16|SPICTRL_MODE_FACT)) | |
---|
338 | (pm << SPICTRL_MODE_PM_BIT) | (div16 << SPICTRL_MODE_DIV16_BIT) | |
---|
339 | (fact << SPICTRL_MODE_FACT_BIT); |
---|
340 | |
---|
341 | DBG("SPICTRL: Effective bit rate %u (requested %u), PM: %x, FACT: %d, div16: %x, core_freq: %u\n", |
---|
342 | core_freq_hz / (2 * (fact ? 1 : 2) * (div) * (div16 ? 16 : 1)), |
---|
343 | freq, pm, fact, div16, core_freq_hz); |
---|
344 | |
---|
345 | return 0; |
---|
346 | } |
---|
347 | |
---|
348 | /* Start Automated Periodic transfers, after this call read can be done */ |
---|
349 | static int spictrl_start_periodic(struct spictrl_priv *priv) |
---|
350 | { |
---|
351 | struct spictrl_ioctl_config *cfg = &priv->periodic_cfg; |
---|
352 | unsigned int am_cfg; |
---|
353 | |
---|
354 | /* Clear the events */ |
---|
355 | priv->regs->event = 0xffffffff; |
---|
356 | |
---|
357 | /* Enable core */ |
---|
358 | priv->regs->mode |= SPICTRL_MODE_EN | SPICTRL_MODE_MS; |
---|
359 | |
---|
360 | /* Update hardware config from flags and period */ |
---|
361 | priv->regs->am_period = cfg->period; |
---|
362 | |
---|
363 | /* Remove SPICTRL_PERIOD_FLAGS_ASEL and ACT bit and shift into posistion */ |
---|
364 | am_cfg = (cfg->period_flags & 0x1f8) >> 1; |
---|
365 | priv->regs->am_cfg = am_cfg; |
---|
366 | |
---|
367 | /* Start automated periodic transfers */ |
---|
368 | if ( cfg->period_flags & SPICTRL_PERIOD_FLAGS_EACT ) { |
---|
369 | /* Enable external triggering */ |
---|
370 | priv->regs->am_cfg = am_cfg | SPICTRL_AMCFG_EACT; |
---|
371 | } else { |
---|
372 | /* Activate periodic transfers */ |
---|
373 | priv->regs->am_cfg = am_cfg | SPICTRL_AMCFG_ACT; |
---|
374 | } |
---|
375 | |
---|
376 | return 0; |
---|
377 | } |
---|
378 | |
---|
379 | /* Stop Automated Periodic transfers */ |
---|
380 | static void spictrl_stop_periodic(struct spictrl_priv *priv) |
---|
381 | { |
---|
382 | priv->regs->am_cfg = 0; |
---|
383 | } |
---|
384 | |
---|
385 | /* Return the status of the SPI controller (the event register), |
---|
386 | * it may be needed in periodic mode to look at the Not Full bit (NF) |
---|
387 | * in order not to hang in an infinte loop when read is called. |
---|
388 | */ |
---|
389 | static inline unsigned int spictrl_status(struct spictrl_priv *priv) |
---|
390 | { |
---|
391 | return priv->regs->event; |
---|
392 | } |
---|
393 | |
---|
394 | static int spictrl_read_periodic( |
---|
395 | struct spictrl_priv *priv, |
---|
396 | struct spictrl_period_io *rarg) |
---|
397 | { |
---|
398 | int i, rxi, rxshift, bits_per_char, reg; |
---|
399 | unsigned int rx_word, mask; |
---|
400 | void *rxbuf; |
---|
401 | |
---|
402 | if ( rarg->options & 0x1 ) { |
---|
403 | /* Read mask registers */ |
---|
404 | for (i=0; i<4; i++) { |
---|
405 | rarg->masks[i] = priv->regs->am_mask[i]; |
---|
406 | } |
---|
407 | } |
---|
408 | |
---|
409 | if ( rarg->options & 0x2 ) { |
---|
410 | /* Read receive registers (after updating masks so that the caller can |
---|
411 | * read current buffer without knowning of actual register mask). |
---|
412 | */ |
---|
413 | |
---|
414 | /* If not started we could be hanging here forever. */ |
---|
415 | if ( !priv->periodic_started ) |
---|
416 | return -1; |
---|
417 | |
---|
418 | rxshift = priv->rxshift; |
---|
419 | bits_per_char = priv->bits_per_char; |
---|
420 | rx_word = 0; |
---|
421 | |
---|
422 | rxbuf = rarg->data; |
---|
423 | if ( !rxbuf ) { |
---|
424 | /* If no data pointer specified we cannot copy data... */ |
---|
425 | return -1; |
---|
426 | } |
---|
427 | |
---|
428 | /* Wait until all data is available (if started) */ |
---|
429 | while ( (priv->regs->event & SPICTRL_EVENT_NE) == 0 ) { |
---|
430 | ; |
---|
431 | } |
---|
432 | |
---|
433 | rxi = 0; |
---|
434 | for (i=0; i<4; i++) { |
---|
435 | mask = rarg->masks[i]; |
---|
436 | reg = 0; |
---|
437 | while ( mask ) { |
---|
438 | if ( mask & 1 ) { |
---|
439 | /* Update Register */ |
---|
440 | rx_word = priv->regs->am_rx[i*32 + reg] >> rxshift; |
---|
441 | |
---|
442 | if ( bits_per_char <= 8 ) { |
---|
443 | *((unsigned char *)rxbuf + rxi) = rx_word; |
---|
444 | } else if ( bits_per_char <= 16 ) { |
---|
445 | *((unsigned short *)rxbuf + rxi) = rx_word; |
---|
446 | } else { |
---|
447 | *((unsigned int *)rxbuf + rxi) = rx_word; |
---|
448 | } |
---|
449 | rxi++; |
---|
450 | } |
---|
451 | |
---|
452 | mask = mask>>1; |
---|
453 | reg++; |
---|
454 | } |
---|
455 | } |
---|
456 | } |
---|
457 | |
---|
458 | return 0; |
---|
459 | } |
---|
460 | |
---|
461 | static int spictrl_write_periodic( |
---|
462 | struct spictrl_priv *priv, |
---|
463 | struct spictrl_period_io *warg) |
---|
464 | { |
---|
465 | int i, txi, txshift, bits_per_char, reg; |
---|
466 | unsigned int tx_word, mask; |
---|
467 | void *txbuf; |
---|
468 | |
---|
469 | if ( warg->options & 0x2 ) { |
---|
470 | |
---|
471 | /* Make sure core is enabled, otherwise TX registers writes are lost */ |
---|
472 | priv->regs->mode |= SPICTRL_MODE_EN; |
---|
473 | |
---|
474 | /* Update Transmit registers (before updating masks so that we do not |
---|
475 | * transmit invalid data) |
---|
476 | */ |
---|
477 | |
---|
478 | txshift = priv->txshift; |
---|
479 | bits_per_char = priv->bits_per_char; |
---|
480 | tx_word = 0; |
---|
481 | |
---|
482 | txbuf = warg->data; |
---|
483 | if ( !txbuf ) { |
---|
484 | /* If no data pointer specified we fill up with |
---|
485 | * idle chars. |
---|
486 | */ |
---|
487 | tx_word = priv->idle_char << txshift; |
---|
488 | } |
---|
489 | |
---|
490 | txi = 0; |
---|
491 | for (i=0; i<4; i++) { |
---|
492 | mask = warg->masks[i]; |
---|
493 | reg = 0; |
---|
494 | while ( mask ) { |
---|
495 | if ( mask & 1 ) { |
---|
496 | if ( txbuf ) { |
---|
497 | if ( bits_per_char <= 8 ) { |
---|
498 | tx_word = *((unsigned char *)txbuf + txi); |
---|
499 | } else if ( bits_per_char <= 16 ) { |
---|
500 | tx_word = *((unsigned short *)txbuf + txi); |
---|
501 | } else { |
---|
502 | tx_word = *((unsigned int *)txbuf + txi); |
---|
503 | } |
---|
504 | tx_word = tx_word << txshift; |
---|
505 | txi++; |
---|
506 | } |
---|
507 | |
---|
508 | /* Update Register */ |
---|
509 | DBG("WRITE 0x%08x to 0x%08x\n", tx_word, &priv->regs->am_tx[i*32 + reg]); |
---|
510 | priv->regs->am_tx[i*32 + reg] = tx_word; |
---|
511 | } |
---|
512 | |
---|
513 | mask = mask>>1; |
---|
514 | reg++; |
---|
515 | } |
---|
516 | } |
---|
517 | } |
---|
518 | |
---|
519 | if ( warg->options & 0x1 ) { |
---|
520 | /* Update mask registers */ |
---|
521 | for (i=0; i<4; i++) { |
---|
522 | DBG("WRITE 0x%08x to 0x%08x (MSK%d)\n", warg->masks[i], &priv->regs->am_mask[i], i); |
---|
523 | priv->regs->am_mask[i] = warg->masks[i]; |
---|
524 | } |
---|
525 | } |
---|
526 | |
---|
527 | return 0; |
---|
528 | } |
---|
529 | |
---|
530 | static int spictrl_read_write( |
---|
531 | struct spictrl_priv *priv, |
---|
532 | void *rxbuf, |
---|
533 | void *txbuf, |
---|
534 | int len) |
---|
535 | { |
---|
536 | unsigned int tx_word, rx_word, tmp; |
---|
537 | int txshift = priv->txshift; |
---|
538 | int rxshift = priv->rxshift; |
---|
539 | int txi, rxi, bits_per_char; |
---|
540 | int length; |
---|
541 | |
---|
542 | /* Use IOCTL for periodic reads. The FIFO is not supported in automated |
---|
543 | * periodic mode |
---|
544 | */ |
---|
545 | if ( priv->periodic_cfg.periodic_mode ) { |
---|
546 | return -1; |
---|
547 | } |
---|
548 | |
---|
549 | bits_per_char = priv->bits_per_char; |
---|
550 | tx_word = 0; |
---|
551 | if ( !txbuf ) { |
---|
552 | tx_word = priv->idle_char << txshift; |
---|
553 | } |
---|
554 | |
---|
555 | /* Clear the events */ |
---|
556 | priv->regs->event = 0xffffffff; |
---|
557 | |
---|
558 | /* Enable core */ |
---|
559 | priv->regs->mode |= SPICTRL_MODE_EN | SPICTRL_MODE_MS; |
---|
560 | |
---|
561 | length = len; |
---|
562 | if ( bits_per_char > 8 ) { |
---|
563 | length = length / 2; |
---|
564 | if ( bits_per_char > 16 ) |
---|
565 | length = length / 2; |
---|
566 | } |
---|
567 | DBG("SPICTRL: LENGTH = %d, Bits/Char: %d, Shift: %d, %d\n", length, bits_per_char, txshift, rxshift); |
---|
568 | |
---|
569 | txi=0; |
---|
570 | rxi=0; |
---|
571 | while ( (rxi < length) || (txi < length) ) { |
---|
572 | /* Get transmit word */ |
---|
573 | if ( length > txi ) { |
---|
574 | if ( txbuf ) { |
---|
575 | if ( bits_per_char <= 8 ) { |
---|
576 | tx_word = *((unsigned char *)txbuf + txi); |
---|
577 | } else if ( bits_per_char <= 16 ) { |
---|
578 | tx_word = *((unsigned short *)txbuf + txi); |
---|
579 | } else { |
---|
580 | tx_word = *((unsigned int *)txbuf + txi); |
---|
581 | } |
---|
582 | tx_word = tx_word << txshift; |
---|
583 | } |
---|
584 | |
---|
585 | /* Wait for SPICTRL to get ready for another TX char */ |
---|
586 | while ( (priv->regs->event & SPICTRL_EVENT_NF) == 0 ) { |
---|
587 | /* Wait for all chars to transmit */ |
---|
588 | /* Could implement waiting for SPICTRL IRQ here */ |
---|
589 | } |
---|
590 | |
---|
591 | DBG("SPICTRL: Writing 0x%x\n", tx_word); |
---|
592 | |
---|
593 | /* Transmit word */ |
---|
594 | priv->regs->tx = tx_word; |
---|
595 | txi++; |
---|
596 | } |
---|
597 | |
---|
598 | /* Read */ |
---|
599 | while ( priv->regs->event & SPICTRL_EVENT_NE ) { |
---|
600 | /* Read to avoid overrun */ |
---|
601 | tmp = priv->regs->rx; |
---|
602 | DBG("SPICTRL: Read 0x%x\n", tmp); |
---|
603 | |
---|
604 | if ( rxbuf && (length > rxi) ) { |
---|
605 | /* Copy word to user buffer */ |
---|
606 | rx_word = (tmp >> rxshift); |
---|
607 | |
---|
608 | DBG("SPICTRL: Receiving 0x%x (0x%x, %d)\n", rx_word, tmp, rxshift); |
---|
609 | |
---|
610 | if ( bits_per_char <= 8 ) { |
---|
611 | *((unsigned char *)rxbuf + rxi) = rx_word; |
---|
612 | } else if ( bits_per_char <= 16 ) { |
---|
613 | *((unsigned short *)rxbuf + rxi) = rx_word; |
---|
614 | } else { |
---|
615 | *((unsigned int *)rxbuf + rxi) = rx_word; |
---|
616 | } |
---|
617 | |
---|
618 | } |
---|
619 | rxi++; |
---|
620 | } |
---|
621 | } |
---|
622 | |
---|
623 | return len; |
---|
624 | } |
---|
625 | |
---|
626 | |
---|
627 | STATIC rtems_status_code spictrl_libi2c_init(rtems_libi2c_bus_t *bushdl) |
---|
628 | { |
---|
629 | struct spictrl_priv *priv = (struct spictrl_priv *)bushdl; |
---|
630 | |
---|
631 | DBG("SPICTRL: spictrl_libi2c_init\n"); |
---|
632 | |
---|
633 | /* Disable SPICTTRL, Select Master mode */ |
---|
634 | priv->regs->mode = SPICTRL_MODE_MS; |
---|
635 | |
---|
636 | /* Mask all Interrupts */ |
---|
637 | priv->regs->mask = 0; |
---|
638 | |
---|
639 | /* Select no slave */ |
---|
640 | priv->regs->slvsel = 0xffffffff; |
---|
641 | |
---|
642 | /* Clear all events */ |
---|
643 | priv->regs->event = 0xffffffff; |
---|
644 | |
---|
645 | return 0; |
---|
646 | } |
---|
647 | |
---|
648 | /* Nothing to be done in start */ |
---|
649 | STATIC rtems_status_code spictrl_libi2c_send_start(rtems_libi2c_bus_t *bushdl) |
---|
650 | { |
---|
651 | DBG("SPICTRL: spictrl_libi2c_send_start\n"); |
---|
652 | |
---|
653 | return 0; |
---|
654 | } |
---|
655 | |
---|
656 | /* Inactivate all chip selects, indicates "End of command" */ |
---|
657 | STATIC rtems_status_code spictrl_libi2c_send_stop(rtems_libi2c_bus_t *bushdl) |
---|
658 | { |
---|
659 | struct spictrl_priv *priv = (struct spictrl_priv *)bushdl; |
---|
660 | |
---|
661 | priv->regs->slvsel = 0xffffffff; |
---|
662 | |
---|
663 | if ( priv->slvSelFunc ) { |
---|
664 | /* unslect all */ |
---|
665 | return priv->slvSelFunc(priv->regs, -1, 0); |
---|
666 | } |
---|
667 | |
---|
668 | DBG("SPICTRL: spictrl_libi2c_send_stop\n"); |
---|
669 | return 0; |
---|
670 | } |
---|
671 | |
---|
672 | /* Select Slave address by selecting apropriate chip select */ |
---|
673 | STATIC rtems_status_code spictrl_libi2c_send_addr(rtems_libi2c_bus_t *bushdl, |
---|
674 | uint32_t addr, int rw) |
---|
675 | { |
---|
676 | struct spictrl_priv *priv = (struct spictrl_priv *)bushdl; |
---|
677 | |
---|
678 | DBG("SPICTRL: spictrl_libi2c_send_addr, %d\n", addr); |
---|
679 | |
---|
680 | if ( priv->slvSelFunc ) { |
---|
681 | /* Let user set spi select using for example GPIO */ |
---|
682 | return priv->slvSelFunc(priv->regs, addr, 1); |
---|
683 | } else if ( priv->regs->capability & SPICTRL_CAP_SSEN ) { |
---|
684 | int slaves; |
---|
685 | |
---|
686 | /* Maximum number of slaves the core support */ |
---|
687 | slaves = (priv->regs->capability & SPICTRL_CAP_SSSZ) >> SPICTRL_CAP_SSSZ_BIT; |
---|
688 | |
---|
689 | if ( addr > slaves ) |
---|
690 | return -1; |
---|
691 | |
---|
692 | if ( (priv->regs->capability & SPICTRL_CAP_ASELA) && |
---|
693 | (priv->periodic_cfg.period_flags & SPICTRL_PERIOD_FLAGS_ASEL) ) { |
---|
694 | /* When automatic slave select is supported by hardware and |
---|
695 | * enabled by configuration the SPI address is determined by |
---|
696 | * the automatic slave select register and the "idle" slave |
---|
697 | * select register is set by configuration. |
---|
698 | */ |
---|
699 | priv->regs->am_slvsel = ~(1<<(addr-1)); |
---|
700 | priv->regs->slvsel = priv->periodic_cfg.period_slvsel; |
---|
701 | /* Enable automatic slave select */ |
---|
702 | priv->regs->mode |= SPICTRL_MODE_ASEL; |
---|
703 | } else { |
---|
704 | /* Normal mode */ |
---|
705 | priv->regs->slvsel = ~(1<<(addr-1)); |
---|
706 | } |
---|
707 | } |
---|
708 | |
---|
709 | return 0; |
---|
710 | } |
---|
711 | |
---|
712 | /* Read a number of bytes */ |
---|
713 | STATIC int spictrl_libi2c_read_bytes(rtems_libi2c_bus_t *bushdl, |
---|
714 | unsigned char *bytes, int nbytes) |
---|
715 | { |
---|
716 | struct spictrl_priv *priv = (struct spictrl_priv *)bushdl; |
---|
717 | int ret; |
---|
718 | |
---|
719 | DBG("SPICTRL: spictrl_libi2c_read_bytes %d\n", nbytes); |
---|
720 | ret = spictrl_read_write(priv, bytes, NULL, nbytes); |
---|
721 | if ( ret < 0 ) { |
---|
722 | printf("SPICTRL: Error Reading\n"); |
---|
723 | } |
---|
724 | #ifdef DEBUG |
---|
725 | else { |
---|
726 | int i; |
---|
727 | for(i=0; i<nbytes; i+=16) { |
---|
728 | DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ", |
---|
729 | bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]); |
---|
730 | DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", |
---|
731 | bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]); |
---|
732 | } |
---|
733 | } |
---|
734 | #endif |
---|
735 | return ret; |
---|
736 | } |
---|
737 | |
---|
738 | /* Write a number of bytes */ |
---|
739 | STATIC int spictrl_libi2c_write_bytes(rtems_libi2c_bus_t *bushdl, |
---|
740 | unsigned char *bytes, int nbytes) |
---|
741 | { |
---|
742 | struct spictrl_priv *priv = (struct spictrl_priv *)bushdl; |
---|
743 | |
---|
744 | #ifdef DEBUG |
---|
745 | int i; |
---|
746 | DBG("SPICTRL: spictrl_libi2c_write_bytes: %d\n", nbytes); |
---|
747 | |
---|
748 | for(i=0; i<nbytes; i+=16) { |
---|
749 | DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ", |
---|
750 | bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]); |
---|
751 | DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", |
---|
752 | bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]); |
---|
753 | } |
---|
754 | #endif |
---|
755 | |
---|
756 | return spictrl_read_write(priv, NULL, bytes, nbytes); |
---|
757 | } |
---|
758 | |
---|
759 | /* Configure the interface and do simultaneous READ/WRITE operations */ |
---|
760 | STATIC int spictrl_libi2c_ioctl( |
---|
761 | rtems_libi2c_bus_t * bushdl, |
---|
762 | int cmd, |
---|
763 | void *buffer) |
---|
764 | { |
---|
765 | struct spictrl_priv *priv = (struct spictrl_priv *)bushdl; |
---|
766 | int ret; |
---|
767 | |
---|
768 | DBG("SPICTRL: spictrl_libi2c_ioctl(%d, 0x%x)\n", cmd, (unsigned int)buffer); |
---|
769 | |
---|
770 | switch (cmd) { |
---|
771 | case RTEMS_LIBI2C_IOCTL_SET_TFRMODE: |
---|
772 | { |
---|
773 | rtems_libi2c_tfr_mode_t *trf_mode = buffer; |
---|
774 | unsigned int mode; |
---|
775 | |
---|
776 | /* Must disable core to write new values */ |
---|
777 | priv->regs->mode &= ~SPICTRL_MODE_EN; |
---|
778 | |
---|
779 | /* Change bit frequency */ |
---|
780 | if ( spictrl_set_freq(priv, trf_mode->baudrate) ) { |
---|
781 | /* Unable to set such a low frequency. */ |
---|
782 | return -1; |
---|
783 | } |
---|
784 | |
---|
785 | /* Set Clock Polarity, Clock Phase, Reverse mode and Word Length */ |
---|
786 | mode = (priv->regs->mode & |
---|
787 | ~(SPICTRL_MODE_CPOL|SPICTRL_MODE_CPHA|SPICTRL_MODE_REV|SPICTRL_MODE_LEN)); |
---|
788 | if ( trf_mode->clock_inv ) |
---|
789 | mode |= SPICTRL_MODE_CPOL; |
---|
790 | if ( trf_mode->clock_phs ) |
---|
791 | mode |= SPICTRL_MODE_CPHA; |
---|
792 | if ( trf_mode->lsb_first == 0 ) |
---|
793 | mode |= SPICTRL_MODE_REV; /* Set Reverse mode (MSB first) */ |
---|
794 | |
---|
795 | if ( (trf_mode->bits_per_char < 4) || |
---|
796 | ((trf_mode->bits_per_char > 16) && (trf_mode->bits_per_char != 32)) ) |
---|
797 | return -1; |
---|
798 | if ( trf_mode->bits_per_char == 32 ) { |
---|
799 | priv->txshift = 0; |
---|
800 | priv->rxshift = 0; |
---|
801 | } else { |
---|
802 | mode |= (trf_mode->bits_per_char-1) << SPICTRL_MODE_LEN_BIT; |
---|
803 | if ( trf_mode->lsb_first == 0 ) { |
---|
804 | /* REV bit 1 */ |
---|
805 | priv->txshift = 32 - trf_mode->bits_per_char; |
---|
806 | priv->rxshift = 16; |
---|
807 | } else { |
---|
808 | /* REV bit 0 */ |
---|
809 | priv->txshift = 0; |
---|
810 | priv->rxshift = 16 - trf_mode->bits_per_char; |
---|
811 | } |
---|
812 | } |
---|
813 | |
---|
814 | priv->bits_per_char = trf_mode->bits_per_char; |
---|
815 | priv->lsb_first = trf_mode->lsb_first; |
---|
816 | priv->idle_char = trf_mode->idle_char; |
---|
817 | |
---|
818 | /* Update hardware */ |
---|
819 | priv->regs->mode = mode; |
---|
820 | |
---|
821 | return 0; |
---|
822 | } |
---|
823 | |
---|
824 | case RTEMS_LIBI2C_IOCTL_READ_WRITE: |
---|
825 | { |
---|
826 | rtems_libi2c_read_write_t *arg = buffer; |
---|
827 | |
---|
828 | DBG("SPICTRL: IOCTL READ/WRITE, RX: 0x%x, TX: 0x%x, len: %d\n", arg->rd_buf, arg->wr_buf, arg->byte_cnt); |
---|
829 | #ifdef DEBUG |
---|
830 | /* Printf out what is going to be transmitted */ |
---|
831 | if ( arg->wr_buf ) { |
---|
832 | unsigned char *bytes = (unsigned char *)arg->wr_buf; |
---|
833 | int i; |
---|
834 | for(i=0; i<arg->byte_cnt; i+=16) { |
---|
835 | DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ", |
---|
836 | bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]); |
---|
837 | DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", |
---|
838 | bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]); |
---|
839 | } |
---|
840 | } |
---|
841 | #endif |
---|
842 | |
---|
843 | ret = spictrl_read_write(priv, arg->rd_buf, (unsigned char *)arg->wr_buf, |
---|
844 | arg->byte_cnt); |
---|
845 | #ifdef DEBUG |
---|
846 | /* Printf out what was read */ |
---|
847 | if ( arg->rd_buf ) { |
---|
848 | unsigned char *bytes = (unsigned char *)arg->rd_buf; |
---|
849 | int i; |
---|
850 | for(i=0; i<arg->byte_cnt; i+=16) { |
---|
851 | DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ", |
---|
852 | bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]); |
---|
853 | DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", |
---|
854 | bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]); |
---|
855 | } |
---|
856 | } |
---|
857 | #endif |
---|
858 | return ret; |
---|
859 | } |
---|
860 | |
---|
861 | /* Enable Periodic mode */ |
---|
862 | case SPICTRL_IOCTL_CONFIG: |
---|
863 | { |
---|
864 | struct spictrl_ioctl_config *cfg; |
---|
865 | |
---|
866 | DBG("SPICTRL: Configuring Periodic mode\n"); |
---|
867 | |
---|
868 | if ( priv->periodic_started ) { |
---|
869 | DBG("SPICTRL: Periodic mode already started, too late to configure\n"); |
---|
870 | return -1; |
---|
871 | } |
---|
872 | |
---|
873 | cfg = buffer; |
---|
874 | if ( cfg == NULL ) { |
---|
875 | memset(&priv->periodic_cfg, 0, sizeof(priv->periodic_cfg)); |
---|
876 | } else { |
---|
877 | priv->periodic_cfg = *cfg; |
---|
878 | } |
---|
879 | cfg = &priv->periodic_cfg; |
---|
880 | if ( cfg->periodic_mode ) { |
---|
881 | /* Enable Automated Periodic mode */ |
---|
882 | priv->regs->mode |= SPICTRL_MODE_AMEN; |
---|
883 | |
---|
884 | /* Check that hardware has support for periodic mode */ |
---|
885 | if ( (priv->regs->mode & SPICTRL_MODE_AMEN) == 0 ) { |
---|
886 | priv->periodic_cfg.periodic_mode = 0; |
---|
887 | DBG("SPICTRL: Periodic mode not supported by hardware\n"); |
---|
888 | return -1; |
---|
889 | } |
---|
890 | } else { |
---|
891 | /* Disable Periodic mode */ |
---|
892 | priv->regs->mode &= ~SPICTRL_MODE_AMEN; |
---|
893 | } |
---|
894 | priv->periodic_started = 0; |
---|
895 | |
---|
896 | /* Set clockgap and TAC */ |
---|
897 | priv->regs->mode = (priv->regs->mode & ~(SPICTRL_MODE_CG|SPICTRL_MODE_TAC)) | |
---|
898 | (cfg->clock_gap << SPICTRL_MODE_CG_BIT) | |
---|
899 | (cfg->flags & SPICTRL_MODE_TAC); |
---|
900 | return 0; |
---|
901 | } |
---|
902 | case SPICTRL_IOCTL_PERIOD_START: |
---|
903 | { |
---|
904 | if ( !priv->periodic_cfg.periodic_mode || priv->periodic_started ) { |
---|
905 | return -1; |
---|
906 | } |
---|
907 | if ( spictrl_start_periodic(priv) == 0 ) { |
---|
908 | priv->periodic_started = 1; |
---|
909 | return 0; |
---|
910 | } else |
---|
911 | return -1; |
---|
912 | } |
---|
913 | case SPICTRL_IOCTL_PERIOD_STOP: |
---|
914 | { |
---|
915 | if ( !priv->periodic_cfg.periodic_mode || !priv->periodic_started ) { |
---|
916 | return -1; |
---|
917 | } |
---|
918 | spictrl_stop_periodic(priv); |
---|
919 | priv->periodic_started = 0; |
---|
920 | return 0; |
---|
921 | } |
---|
922 | case SPICTRL_IOCTL_STATUS: |
---|
923 | { |
---|
924 | if ( !buffer ) |
---|
925 | return 0; |
---|
926 | *(unsigned int *)buffer = spictrl_status(priv); |
---|
927 | return 0; |
---|
928 | } |
---|
929 | |
---|
930 | case SPICTRL_IOCTL_PERIOD_WRITE: |
---|
931 | { |
---|
932 | if ( !priv->periodic_cfg.periodic_mode || !buffer ) { |
---|
933 | return -1; |
---|
934 | } |
---|
935 | if ( spictrl_write_periodic(priv, (struct spictrl_period_io *) |
---|
936 | buffer) == 0 ) { |
---|
937 | return 0; |
---|
938 | } else |
---|
939 | return -1; |
---|
940 | } |
---|
941 | |
---|
942 | case SPICTRL_IOCTL_PERIOD_READ: |
---|
943 | { |
---|
944 | if ( !priv->periodic_cfg.periodic_mode || !buffer ) { |
---|
945 | return -1; |
---|
946 | } |
---|
947 | if ( spictrl_read_periodic(priv, (struct spictrl_period_io *) |
---|
948 | buffer) == 0 ) { |
---|
949 | return 0; |
---|
950 | } else |
---|
951 | return -1; |
---|
952 | } |
---|
953 | |
---|
954 | case SPICTRL_IOCTL_REGS: |
---|
955 | { |
---|
956 | /* Copy Register Base Address to user space */ |
---|
957 | if ( !buffer ) { |
---|
958 | return -1; |
---|
959 | } |
---|
960 | *(struct spictrl_regs **)buffer = priv->regs; |
---|
961 | return 0; |
---|
962 | } |
---|
963 | |
---|
964 | default: |
---|
965 | /* Unknown IOCTL */ |
---|
966 | return -1; |
---|
967 | } |
---|
968 | |
---|
969 | return 0; |
---|
970 | } |
---|
971 | |
---|
972 | STATIC rtems_libi2c_bus_ops_t spictrl_libi2c_ops = |
---|
973 | { |
---|
974 | .init = spictrl_libi2c_init, |
---|
975 | .send_start = spictrl_libi2c_send_start, |
---|
976 | .send_stop = spictrl_libi2c_send_stop, |
---|
977 | .send_addr = spictrl_libi2c_send_addr, |
---|
978 | .read_bytes = spictrl_libi2c_read_bytes, |
---|
979 | .write_bytes = spictrl_libi2c_write_bytes, |
---|
980 | .ioctl = spictrl_libi2c_ioctl |
---|
981 | }; |
---|
982 | |
---|
983 | int spictrl_device_init(struct spictrl_priv *priv) |
---|
984 | { |
---|
985 | struct amba_dev_info *ambadev; |
---|
986 | struct ambapp_core *pnpinfo; |
---|
987 | union drvmgr_key_value *value; |
---|
988 | |
---|
989 | /* Get device information from AMBA PnP information */ |
---|
990 | ambadev = (struct amba_dev_info *)priv->dev->businfo; |
---|
991 | if ( ambadev == NULL ) { |
---|
992 | return -1; |
---|
993 | } |
---|
994 | pnpinfo = &ambadev->info; |
---|
995 | priv->irq = pnpinfo->irq; |
---|
996 | priv->regs = (struct spictrl_regs *)pnpinfo->apb_slv->start; |
---|
997 | priv->fdepth = (priv->regs->capability & SPICTRL_CAP_FDEPTH) >> SPICTRL_CAP_FDEPTH_BIT; |
---|
998 | |
---|
999 | DBG("SPCTRL: 0x%x irq %d, FIFO: %d\n", (unsigned int)priv->regs, priv->irq, priv->fdepth); |
---|
1000 | |
---|
1001 | /* Mask all Interrupts */ |
---|
1002 | priv->regs->mask = 0; |
---|
1003 | |
---|
1004 | /* Disable SPICTTRL */ |
---|
1005 | priv->regs->mode = 0; |
---|
1006 | |
---|
1007 | /* Get custom */ |
---|
1008 | value = drvmgr_dev_key_get(priv->dev, "slvSelFunc", KEY_TYPE_POINTER); |
---|
1009 | if ( value ) { |
---|
1010 | priv->slvSelFunc = value->ptr; |
---|
1011 | } |
---|
1012 | |
---|
1013 | /* Prepare I2C layer */ |
---|
1014 | priv->i2clib_desc.ops = &spictrl_libi2c_ops; |
---|
1015 | priv->i2clib_desc.size = sizeof(spictrl_libi2c_ops); |
---|
1016 | return 0; |
---|
1017 | } |
---|