source: rtems/bsps/shared/dev/i2c/spi-memdrv.c @ 29e7a069

Last change on this file since 29e7a069 was 29e7a069, checked in by Sebastian Huber <sebastian.huber@…>, on 08/01/20 at 12:30:10

dev/spi-memdrv: Fix use of uninit mem_param_ptr

  • Property mode set to 100644
File size: 14.8 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.org/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\*-------------------------------------------------------------------------*/
45static rtems_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\*-------------------------------------------------------------------------*/
82static rtems_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_interval   ticks_per_second;
98
99  ticks_per_second = rtems_clock_get_ticks_per_second();
100  (void) rtems_task_wake_after(ticks_per_second * ms / 1000);
101  return 0;
102}
103
104/*=========================================================================*\
105| Function:                                                                 |
106\*-------------------------------------------------------------------------*/
107rtems_status_code spi_memdrv_write
108(
109/*-------------------------------------------------------------------------*\
110| Purpose:                                                                  |
111|   write a block of data to flash                                          |
112+---------------------------------------------------------------------------+
113| Input Parameters:                                                         |
114\*-------------------------------------------------------------------------*/
115 rtems_device_major_number major,        /* major device number            */
116 rtems_device_minor_number minor,        /* minor device number            */
117 void                      *arg          /* ptr to write argument struct   */
118)
119/*-------------------------------------------------------------------------*\
120| Return Value:                                                             |
121|    o = ok or error code                                                   |
122\*=========================================================================*/
123{
124  rtems_status_code          rc = RTEMS_SUCCESSFUL;
125  rtems_libio_rw_args_t *rwargs = arg;
126  off_t                     off = rwargs->offset;
127  int                       cnt = rwargs->count;
128  unsigned char            *buf = (unsigned char *)rwargs->buffer;
129  int                bytes_sent = 0;
130  int                  curr_cnt;
131  unsigned char       cmdbuf[4];
132  int                   ret_cnt = 0;
133  int                  cmd_size;
134  spi_memdrv_param_t  *mem_param_ptr;
135  rtems_libi2c_tfr_mode_t tfr_mode = {
136    .baudrate =      20000000, /* maximum bits per second                   */
137    .bits_per_char = 8,        /* how many bits per byte/word/longword?     */
138    .lsb_first =     FALSE,    /* FALSE: send MSB first                     */
139    .clock_inv =     FALSE,    /* FALSE: non-inverted clock (high active)   */
140    .clock_phs =     FALSE     /* FALSE: clock starts in middle of data tfr */
141  } ;
142
143  /*
144   * get mem parameters
145   */
146  if (rc == RTEMS_SUCCESSFUL) {
147    rc = spi_memdrv_minor2param_ptr(minor,&mem_param_ptr);
148  }
149  /*
150   * check arguments
151   */
152  if (rc == RTEMS_SUCCESSFUL) {
153    if ((cnt <= 0)                      ||
154        (cnt > mem_param_ptr->mem_size) ||
155        (off > (mem_param_ptr->mem_size-cnt))) {
156      rc = RTEMS_INVALID_SIZE;
157    }
158    else if (buf == NULL) {
159      rc = RTEMS_INVALID_ADDRESS;
160    }
161  }
162  while ((rc == RTEMS_SUCCESSFUL) &&
163         (cnt > bytes_sent)) {
164    curr_cnt = cnt - bytes_sent;
165    if ((mem_param_ptr->page_size > 0) &&
166        (off              / mem_param_ptr->page_size) !=
167        ((off+curr_cnt+1) / mem_param_ptr->page_size)) {
168      curr_cnt = mem_param_ptr->page_size - (off % mem_param_ptr->page_size);
169    }
170    /*
171     * select device, set transfer mode, address device
172     */
173    if (rc == RTEMS_SUCCESSFUL) {
174      rc = rtems_libi2c_send_start(minor);
175    }
176    /*
177     * set transfer mode
178     */
179    if (rc == RTEMS_SUCCESSFUL) {
180      tfr_mode.baudrate = mem_param_ptr->baudrate;
181      rc = -rtems_libi2c_ioctl(minor,
182                               RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
183                               &tfr_mode);
184    }
185
186    /*
187     * address device
188     */
189    if (rc == RTEMS_SUCCESSFUL) {
190      rc = rtems_libi2c_send_addr(minor,TRUE);
191    }
192
193    /*
194     * send write_enable command
195     */
196    if (rc == RTEMS_SUCCESSFUL) {
197      cmdbuf[0] = SPI_MEM_CMD_WREN;
198      ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,1);
199      if (ret_cnt < 0) {
200        rc = -ret_cnt;
201      }
202    }
203    /*
204     * terminate transfer
205     */
206    if (rc == RTEMS_SUCCESSFUL) {
207      rc = rtems_libi2c_send_stop(minor);
208    }
209    /*
210     * select device, set transfer mode
211     */
212    if (rc == RTEMS_SUCCESSFUL) {
213      rc = rtems_libi2c_send_start(minor);
214    }
215
216    /*
217     * address device
218     */
219    if (rc == RTEMS_SUCCESSFUL) {
220      rc = rtems_libi2c_send_addr(minor,TRUE);
221    }
222
223    /*
224     * set transfer mode
225     */
226    if (rc == RTEMS_SUCCESSFUL) {
227      rc = -rtems_libi2c_ioctl(minor,
228                               RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
229                               &tfr_mode);
230    }
231    /*
232     * send "page program" command and address
233     */
234    if (rc == RTEMS_SUCCESSFUL) {
235      cmdbuf[0] = SPI_MEM_CMD_PP;
236      if (mem_param_ptr->mem_size > 0x10000 /* 256*256 */) {
237        cmdbuf[1] = (off >> 16) & 0xff;
238        cmdbuf[2] = (off >>  8) & 0xff;
239        cmdbuf[3] = (off >>  0) & 0xff;
240        cmd_size  = 4;
241      }
242      else if (mem_param_ptr->mem_size > 256) {
243        cmdbuf[1] = (off >>  8) & 0xff;
244        cmdbuf[2] = (off >>  0) & 0xff;
245        cmd_size  = 3;
246      }
247      else {
248        cmdbuf[1] = (off >>  0) & 0xff;
249        cmd_size  = 1;
250      }
251
252      ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,cmd_size);
253      if (ret_cnt < 0) {
254        rc = -ret_cnt;
255      }
256    }
257    /*
258     * send write data
259     */
260    if (rc == RTEMS_SUCCESSFUL) {
261      ret_cnt = rtems_libi2c_write_bytes(minor,buf,curr_cnt);
262      if (ret_cnt < 0) {
263        rc = -ret_cnt;
264      }
265    }
266    /*
267     * terminate transfer
268     */
269    if (rc == RTEMS_SUCCESSFUL) {
270      rc = rtems_libi2c_send_stop(minor);
271    }
272    /*
273     * wait proper time for data to store: 5ms
274     * FIXME: select proper interval or poll, until device is finished
275     */
276    if (rc == RTEMS_SUCCESSFUL) {
277      rc = spi_memdrv_wait_ms(5);
278    }
279    /*
280     * adjust bytecount to be sent and pointers
281     */
282    bytes_sent += curr_cnt;
283    off        += curr_cnt;
284    buf        += curr_cnt;
285  }
286  rwargs->bytes_moved = bytes_sent;
287  return rc;
288}
289
290/*=========================================================================*\
291| Function:                                                                 |
292\*-------------------------------------------------------------------------*/
293rtems_status_code spi_memdrv_read
294(
295/*-------------------------------------------------------------------------*\
296| Purpose:                                                                  |
297|   read a block of data from flash                                         |
298+---------------------------------------------------------------------------+
299| Input Parameters:                                                         |
300\*-------------------------------------------------------------------------*/
301 rtems_device_major_number major,        /* major device number            */
302 rtems_device_minor_number minor,        /* minor device number            */
303 void                      *arg          /* ptr to read argument struct    */
304)
305/*-------------------------------------------------------------------------*\
306| Return Value:                                                             |
307|    o = ok or error code                                                   |
308\*=========================================================================*/
309{
310  rtems_status_code rc = RTEMS_SUCCESSFUL;
311  rtems_libio_rw_args_t *rwargs = arg;
312  off_t                     off = rwargs->offset;
313  int                       cnt = rwargs->count;
314  unsigned char            *buf = (unsigned char *)rwargs->buffer;
315  unsigned char         cmdbuf[4];
316  int                   ret_cnt = 0;
317  int                  cmd_size;
318  spi_memdrv_param_t  *mem_param_ptr;
319  rtems_libi2c_tfr_mode_t tfr_mode = {
320    .baudrate =      20000000, /* maximum bits per second                   */
321    .bits_per_char = 8,        /* how many bits per byte/word/longword?     */
322    .lsb_first =     FALSE,    /* FALSE: send MSB first                     */
323    .clock_inv =     FALSE,    /* FALSE: non-inverted clock (high active)   */
324    .clock_phs =     FALSE     /* FALSE: clock starts in middle of data tfr */
325  };
326
327  /*
328   * get mem parameters
329   */
330  if (rc == RTEMS_SUCCESSFUL) {
331    rc = spi_memdrv_minor2param_ptr(minor,&mem_param_ptr);
332  }
333  /*
334   * check arguments
335   */
336  if (rc == RTEMS_SUCCESSFUL) {
337    if ((cnt <= 0)                      ||
338        (cnt > mem_param_ptr->mem_size) ||
339        (off > (mem_param_ptr->mem_size-cnt))) {
340      rc = RTEMS_INVALID_SIZE;
341    }
342    else if (buf == NULL) {
343      rc = RTEMS_INVALID_ADDRESS;
344    }
345  }
346  /*
347   * select device, set transfer mode, address device
348   */
349  if (rc == RTEMS_SUCCESSFUL) {
350    rc = rtems_libi2c_send_start(minor);
351  }
352  /*
353   * set transfer mode
354   */
355  if (rc == RTEMS_SUCCESSFUL) {
356    tfr_mode.baudrate = mem_param_ptr->baudrate;
357    rc = -rtems_libi2c_ioctl(minor,
358                             RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
359                             &tfr_mode);
360  }
361  /*
362   * address device
363   */
364  if (rc == RTEMS_SUCCESSFUL) {
365    rc = rtems_libi2c_send_addr(minor,TRUE);
366  }
367
368  if (rc == RTEMS_SUCCESSFUL) {
369    /*
370     * HACK: beyond size of memory array? then read status register instead
371     */
372    if (off >= mem_param_ptr->mem_size) {
373      /*
374       * send read status register command
375       */
376      cmdbuf[0] = SPI_MEM_CMD_RDSR;
377      ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,1);
378      if (ret_cnt < 0) {
379        rc = -ret_cnt;
380      }
381    } else {
382      /*
383       * send read command and address
384       */
385      cmdbuf[0] = SPI_MEM_CMD_READ;
386      if (mem_param_ptr->mem_size > 0x10000 /* 256*256 */) {
387        cmdbuf[1] = (off >> 16) & 0xff;
388        cmdbuf[2] = (off >>  8) & 0xff;
389        cmdbuf[3] = (off >>  0) & 0xff;
390        cmd_size  = 4;
391      }
392      else if (mem_param_ptr->mem_size > 256) {
393        cmdbuf[1] = (off >>  8) & 0xff;
394        cmdbuf[2] = (off >>  0) & 0xff;
395        cmd_size  = 3;
396      }
397      else {
398        cmdbuf[1] = (off >>  0) & 0xff;
399        cmd_size  = 1;
400      }
401      ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,cmd_size);
402      if (ret_cnt < 0) {
403        rc = -ret_cnt;
404      }
405    }
406  }
407  /*
408   * fetch read data
409   */
410  if (rc == RTEMS_SUCCESSFUL) {
411    ret_cnt = rtems_libi2c_read_bytes (minor,buf,cnt);
412    if (ret_cnt < 0) {
413      rc = -ret_cnt;
414    }
415  }
416
417  /*
418   * terminate transfer
419   */
420  if (rc == RTEMS_SUCCESSFUL) {
421    rc = rtems_libi2c_send_stop(minor);
422  }
423  rwargs->bytes_moved = (rc == RTEMS_SUCCESSFUL) ? ret_cnt : 0;
424
425  return rc;
426}
427
428/*
429 * driver operation tables
430 */
431rtems_driver_address_table spi_memdrv_rw_ops = {
432  .read_entry =  spi_memdrv_read,
433  .write_entry = spi_memdrv_write
434};
435
436rtems_driver_address_table spi_memdrv_ro_ops = {
437  .read_entry =  spi_memdrv_read,
438};
439
Note: See TracBrowser for help on using the repository browser.