source: rtems/c/src/libchip/i2c/spi-memdrv.c @ 517bf08

4.115
Last change on this file since 517bf08 was 0527367c, checked in by Ralf Corsepius <ralf.corsepius@…>, on 11/06/11 at 12:40:21

2011-11-06 Ralf Corsépius <ralf.corsepius@…>

PR 1945/cpukit

  • libchip/i2c/spi-memdrv.c: Replace rtems_off64_t with off_t.
  • Property mode set to 100644
File size: 14.9 KB
Line 
1/*===============================================================*\
2| Project: SPI driver for spi memory devices                      |
3+-----------------------------------------------------------------+
4|                    Copyright (c) 2008                           |
5|                    Embedded Brains GmbH                         |
6|                    Obere Lagerstr. 30                           |
7|                    D-82178 Puchheim                             |
8|                    Germany                                      |
9|                    rtems@embedded-brains.de                     |
10+-----------------------------------------------------------------+
11| The license and distribution terms for this file may be         |
12| found in the file LICENSE in this distribution or at            |
13|                                                                 |
14| http://www.rtems.com/license/LICENSE.                           |
15|                                                                 |
16+-----------------------------------------------------------------+
17\*===============================================================*/
18/*
19 * FIXME: currently, this driver only supports read/write accesses
20 * erase accesses are to be completed
21 */
22
23
24#include <rtems.h>
25#include <rtems/libi2c.h>
26
27#include <libchip/spi-memdrv.h>
28#include <rtems/libio.h>
29
30#define SPI_MEM_CMD_WREN  0x06
31#define SPI_MEM_CMD_WRDIS 0x04
32#define SPI_MEM_CMD_RDID  0x9F
33#define SPI_MEM_CMD_RDSR  0x05
34#define SPI_MEM_CMD_WRSR  0x01
35#define SPI_MEM_CMD_READ  0x03
36#define SPI_MEM_CMD_PP    0x02  /* page program                       */
37#define SPI_MEM_CMD_SE    0xD8  /* sector erase                       */
38#define SPI_MEM_CMD_BE    0xC7  /* bulk erase                         */
39#define SPI_MEM_CMD_DP    0xB9  /* deep power down                    */
40#define SPI_MEM_CMD_RES   0xAB  /* release from deep power down       */
41
42/*=========================================================================*\
43| Function:                                                                 |
44\*-------------------------------------------------------------------------*/
45rtems_status_code spi_memdrv_minor2param_ptr
46(
47/*-------------------------------------------------------------------------*\
48| Purpose:                                                                  |
49|   translate given minor device number to param pointer                    |
50+---------------------------------------------------------------------------+
51| Input Parameters:                                                         |
52\*-------------------------------------------------------------------------*/
53 rtems_device_minor_number minor,                /* minor number of device */
54 spi_memdrv_param_t **param_ptr                  /* ptr to param ptr       */
55)
56/*-------------------------------------------------------------------------*\
57| Return Value:                                                             |
58|    o = ok or error code                                                   |
59\*=========================================================================*/
60{
61  rtems_status_code   rc = RTEMS_SUCCESSFUL;
62  spi_memdrv_t *drv_ptr;
63
64  if (rc == RTEMS_SUCCESSFUL) {
65    rc = -rtems_libi2c_ioctl(minor,
66                             RTEMS_LIBI2C_IOCTL_GET_DRV_T,
67                             &drv_ptr);
68  }
69  if ((rc == RTEMS_SUCCESSFUL) &&
70      (drv_ptr->libi2c_drv_entry.size != sizeof(spi_memdrv_t))) {
71    rc = RTEMS_INVALID_SIZE;
72  }
73  if (rc == RTEMS_SUCCESSFUL) {
74    *param_ptr = &(drv_ptr->spi_memdrv_param);
75  }
76  return rc;
77}
78
79/*=========================================================================*\
80| Function:                                                                 |
81\*-------------------------------------------------------------------------*/
82rtems_status_code spi_memdrv_wait_ms
83(
84/*-------------------------------------------------------------------------*\
85| Purpose:                                                                  |
86|   wait a certain interval given in ms                                     |
87+---------------------------------------------------------------------------+
88| Input Parameters:                                                         |
89\*-------------------------------------------------------------------------*/
90 int ms                                  /* time to wait in milliseconds   */
91)
92/*-------------------------------------------------------------------------*\
93| Return Value:                                                             |
94|    o = ok or error code                                                   |
95\*=========================================================================*/
96{
97  rtems_status_code          rc = RTEMS_SUCCESSFUL;
98  rtems_interval ticks_per_second;
99
100  rc = rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND,&ticks_per_second);
101  if (rc == RTEMS_SUCCESSFUL) {
102    rc = rtems_task_wake_after(ticks_per_second * ms / 1000);
103  }
104  return rc;
105}
106
107/*=========================================================================*\
108| Function:                                                                 |
109\*-------------------------------------------------------------------------*/
110rtems_status_code spi_memdrv_write
111(
112/*-------------------------------------------------------------------------*\
113| Purpose:                                                                  |
114|   write a block of data to flash                                          |
115+---------------------------------------------------------------------------+
116| Input Parameters:                                                         |
117\*-------------------------------------------------------------------------*/
118 rtems_device_major_number major,        /* major device number            */
119 rtems_device_minor_number minor,        /* minor device number            */
120 void                      *arg          /* ptr to write argument struct   */
121)
122/*-------------------------------------------------------------------------*\
123| Return Value:                                                             |
124|    o = ok or error code                                                   |
125\*=========================================================================*/
126{
127  rtems_status_code          rc = RTEMS_SUCCESSFUL;
128  rtems_libio_rw_args_t *rwargs = arg;
129  off_t                     off = rwargs->offset;
130  int                       cnt = rwargs->count;
131  unsigned char            *buf = (unsigned char *)rwargs->buffer;
132  int                bytes_sent = 0;
133  int                  curr_cnt;
134  unsigned char       cmdbuf[4];
135  int                   ret_cnt = 0;
136  int                  cmd_size;
137  spi_memdrv_param_t  *mem_param_ptr;
138  rtems_libi2c_tfr_mode_t tfr_mode = {
139    .baudrate =      20000000, /* maximum bits per second                   */
140    .bits_per_char = 8,        /* how many bits per byte/word/longword?     */
141    .lsb_first =     FALSE,    /* FALSE: send MSB first                     */
142    .clock_inv =     FALSE,    /* FALSE: non-inverted clock (high active)   */
143    .clock_phs =     FALSE     /* FALSE: clock starts in middle of data tfr */
144  } ;
145
146  /*
147   * get mem parameters
148   */
149  if (rc == RTEMS_SUCCESSFUL) {
150    rc = spi_memdrv_minor2param_ptr(minor,&mem_param_ptr);
151  }
152  /*
153   * check arguments
154   */
155  if (rc == RTEMS_SUCCESSFUL) {
156    if ((cnt <= 0)                      ||
157        (cnt > mem_param_ptr->mem_size) ||
158        (off > (mem_param_ptr->mem_size-cnt))) {
159      rc = RTEMS_INVALID_SIZE;
160    }
161    else if (buf == NULL) {
162      rc = RTEMS_INVALID_ADDRESS;
163    }
164  }
165  while ((rc == RTEMS_SUCCESSFUL) &&
166         (cnt > bytes_sent)) {
167    curr_cnt = cnt - bytes_sent;
168    if ((mem_param_ptr->page_size > 0) &&
169        (off              / mem_param_ptr->page_size) !=
170        ((off+curr_cnt+1) / mem_param_ptr->page_size)) {
171      curr_cnt = mem_param_ptr->page_size - (off % mem_param_ptr->page_size);
172    }
173    /*
174     * select device, set transfer mode, address device
175     */
176    if (rc == RTEMS_SUCCESSFUL) {
177      rc = rtems_libi2c_send_start(minor);
178    }
179    /*
180     * set transfer mode
181     */
182    if (rc == RTEMS_SUCCESSFUL) {
183      tfr_mode.baudrate = mem_param_ptr->baudrate;
184      rc = -rtems_libi2c_ioctl(minor,
185                               RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
186                               &tfr_mode);
187    }
188
189    /*
190     * address device
191     */
192    if (rc == RTEMS_SUCCESSFUL) {
193      rc = rtems_libi2c_send_addr(minor,TRUE);
194    }
195
196    /*
197     * send write_enable command
198     */
199    if (rc == RTEMS_SUCCESSFUL) {
200      cmdbuf[0] = SPI_MEM_CMD_WREN;
201      ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,1);
202      if (ret_cnt < 0) {
203        rc = -ret_cnt;
204      }
205    }
206    /*
207     * terminate transfer
208     */
209    if (rc == RTEMS_SUCCESSFUL) {
210      rc = rtems_libi2c_send_stop(minor);
211    }
212    /*
213     * select device, set transfer mode
214     */
215    if (rc == RTEMS_SUCCESSFUL) {
216      rc = rtems_libi2c_send_start(minor);
217    }
218
219    /*
220     * address device
221     */
222    if (rc == RTEMS_SUCCESSFUL) {
223      rc = rtems_libi2c_send_addr(minor,TRUE);
224    }
225
226    /*
227     * set transfer mode
228     */
229    if (rc == RTEMS_SUCCESSFUL) {
230      rc = -rtems_libi2c_ioctl(minor,
231                               RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
232                               &tfr_mode);
233    }
234    /*
235     * send "page program" command and address
236     */
237    if (rc == RTEMS_SUCCESSFUL) {
238      cmdbuf[0] = SPI_MEM_CMD_PP;
239      if (mem_param_ptr->mem_size > 0x10000 /* 256*256 */) {
240        cmdbuf[1] = (off >> 16) & 0xff;
241        cmdbuf[2] = (off >>  8) & 0xff;
242        cmdbuf[3] = (off >>  0) & 0xff;
243        cmd_size  = 4;
244      }
245      else if (mem_param_ptr->mem_size > 256) {
246        cmdbuf[1] = (off >>  8) & 0xff;
247        cmdbuf[2] = (off >>  0) & 0xff;
248        cmd_size  = 3;
249      }
250      else {
251        cmdbuf[1] = (off >>  0) & 0xff;
252        cmd_size  = 1;
253      }
254
255      ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,cmd_size);
256      if (ret_cnt < 0) {
257        rc = -ret_cnt;
258      }
259    }
260    /*
261     * send write data
262     */
263    if (rc == RTEMS_SUCCESSFUL) {
264      ret_cnt = rtems_libi2c_write_bytes(minor,buf,curr_cnt);
265      if (ret_cnt < 0) {
266        rc = -ret_cnt;
267      }
268    }
269    /*
270     * terminate transfer
271     */
272    if (rc == RTEMS_SUCCESSFUL) {
273      rc = rtems_libi2c_send_stop(minor);
274    }
275    /*
276     * wait proper time for data to store: 5ms
277     * FIXME: select proper interval or poll, until device is finished
278     */
279    if (rc == RTEMS_SUCCESSFUL) {
280      rc = spi_memdrv_wait_ms(5);
281    }
282    /*
283     * adjust bytecount to be sent and pointers
284     */
285    bytes_sent += curr_cnt;
286    off        += curr_cnt;
287    buf        += curr_cnt;
288  }
289  rwargs->bytes_moved = bytes_sent;
290  return rc;
291}
292
293/*=========================================================================*\
294| Function:                                                                 |
295\*-------------------------------------------------------------------------*/
296rtems_status_code spi_memdrv_read
297(
298/*-------------------------------------------------------------------------*\
299| Purpose:                                                                  |
300|   read a block of data from flash                                         |
301+---------------------------------------------------------------------------+
302| Input Parameters:                                                         |
303\*-------------------------------------------------------------------------*/
304 rtems_device_major_number major,        /* major device number            */
305 rtems_device_minor_number minor,        /* minor device number            */
306 void                      *arg          /* ptr to read argument struct    */
307)
308/*-------------------------------------------------------------------------*\
309| Return Value:                                                             |
310|    o = ok or error code                                                   |
311\*=========================================================================*/
312{
313  rtems_status_code rc = RTEMS_SUCCESSFUL;
314  rtems_libio_rw_args_t *rwargs = arg;
315  off_t                     off = rwargs->offset;
316  int                       cnt = rwargs->count;
317  unsigned char            *buf = (unsigned char *)rwargs->buffer;
318  unsigned char         cmdbuf[4];
319  int                   ret_cnt = 0;
320  int                  cmd_size;
321  spi_memdrv_param_t  *mem_param_ptr;
322  rtems_libi2c_tfr_mode_t tfr_mode = {
323    .baudrate =      20000000, /* maximum bits per second                   */
324    .bits_per_char = 8,        /* how many bits per byte/word/longword?     */
325    .lsb_first =     FALSE,    /* FALSE: send MSB first                     */
326    .clock_inv =     FALSE,    /* FALSE: non-inverted clock (high active)   */
327    .clock_phs =     FALSE     /* FALSE: clock starts in middle of data tfr */
328  };
329
330  /*
331   * get mem parameters
332   */
333  if (rc == RTEMS_SUCCESSFUL) {
334    rc = spi_memdrv_minor2param_ptr(minor,&mem_param_ptr);
335  }
336  /*
337   * check arguments
338   */
339  if (rc == RTEMS_SUCCESSFUL) {
340    if ((cnt <= 0)                      ||
341        (cnt > mem_param_ptr->mem_size) ||
342        (off > (mem_param_ptr->mem_size-cnt))) {
343      rc = RTEMS_INVALID_SIZE;
344    }
345    else if (buf == NULL) {
346      rc = RTEMS_INVALID_ADDRESS;
347    }
348  }
349  /*
350   * select device, set transfer mode, address device
351   */
352  if (rc == RTEMS_SUCCESSFUL) {
353    rc = rtems_libi2c_send_start(minor);
354  }
355  /*
356   * set transfer mode
357   */
358  if (rc == RTEMS_SUCCESSFUL) {
359    tfr_mode.baudrate = mem_param_ptr->baudrate;
360    rc = -rtems_libi2c_ioctl(minor,
361                             RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
362                             &tfr_mode);
363  }
364  /*
365   * address device
366   */
367  if (rc == RTEMS_SUCCESSFUL) {
368    rc = rtems_libi2c_send_addr(minor,TRUE);
369  }
370
371  if (off >= mem_param_ptr->mem_size) {
372    /*
373     * HACK: beyond size of memory array? then read status register instead
374     */
375    /*
376     * send read status register command
377     */
378    if (rc == RTEMS_SUCCESSFUL) {
379      cmdbuf[0] = SPI_MEM_CMD_RDSR;
380      ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,1);
381      if (ret_cnt < 0) {
382        rc = -ret_cnt;
383      }
384    }
385  }
386  else {
387    /*
388     * send read command and address
389     */
390    if (rc == RTEMS_SUCCESSFUL) {
391      cmdbuf[0] = SPI_MEM_CMD_READ;
392      if (mem_param_ptr->mem_size > 0x10000 /* 256*256 */) {
393        cmdbuf[1] = (off >> 16) & 0xff;
394        cmdbuf[2] = (off >>  8) & 0xff;
395        cmdbuf[3] = (off >>  0) & 0xff;
396        cmd_size  = 4;
397      }
398      else if (mem_param_ptr->mem_size > 256) {
399        cmdbuf[1] = (off >>  8) & 0xff;
400        cmdbuf[2] = (off >>  0) & 0xff;
401        cmd_size  = 3;
402      }
403      else {
404        cmdbuf[1] = (off >>  0) & 0xff;
405        cmd_size  = 1;
406      }
407      ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,cmd_size);
408      if (ret_cnt < 0) {
409        rc = -ret_cnt;
410      }
411    }
412  }
413  /*
414   * fetch read data
415   */
416  if (rc == RTEMS_SUCCESSFUL) {
417    ret_cnt = rtems_libi2c_read_bytes (minor,buf,cnt);
418    if (ret_cnt < 0) {
419      rc = -ret_cnt;
420    }
421  }
422
423  /*
424   * terminate transfer
425   */
426  if (rc == RTEMS_SUCCESSFUL) {
427    rc = rtems_libi2c_send_stop(minor);
428  }
429  rwargs->bytes_moved = (rc == RTEMS_SUCCESSFUL) ? ret_cnt : 0;
430
431  return rc;
432}
433
434/*
435 * driver operation tables
436 */
437rtems_driver_address_table spi_memdrv_rw_ops = {
438  .read_entry =  spi_memdrv_read,
439  .write_entry = spi_memdrv_write
440};
441
442rtems_driver_address_table spi_memdrv_ro_ops = {
443  .read_entry =  spi_memdrv_read,
444};
445
Note: See TracBrowser for help on using the repository browser.