]> git.gag.com Git - fw/altos/blob - src/drivers/ao_mr25.c
altos/telelco-v2.0: Also sample temp and v_ref with ADC
[fw/altos] / src / drivers / ao_mr25.c
1 /*
2  * Copyright © 2010 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include "ao.h"
20
21 /* Total bytes of available storage */
22 __pdata uint32_t        ao_storage_total;
23
24 /* Block size - device is erased in these units. At least 256 bytes */
25 __pdata uint32_t        ao_storage_block;
26
27 /* Byte offset of config block. Will be ao_storage_block bytes long */
28 __pdata uint32_t        ao_storage_config;
29
30 /* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */
31 __pdata uint16_t        ao_storage_unit;
32
33 /*
34  * MRAM is entirely random access; no erase operations are required,
35  * nor are reads or writes restricted to a particular alignment.
36  */
37
38 #define MR25_WREN       0x06    /* Write Enable */
39 #define MR25_WRDI       0x04    /* Write Disable */
40 #define MR25_RDSR       0x05    /* Read Status Register */
41 #define MR25_WRSR       0x01    /* Write Status Register */
42 #define MR25_READ       0x03    /* Read Data Bytes */
43 #define MR25_WRITE      0x02    /* Write Data Bytes */
44
45 /*
46  * Status register bits
47  */
48
49 #define MR25_STATUS_SRWD        (1 << 7)        /* Status register write disable */
50 #define MR25_STATUS_BP_MASK     (3 << 2)        /* Block protect bits */
51 #define MR25_STATUS_BP_SHIFT    (2)
52 #define MR25_STATUS_WEL         (1 << 1)        /* Write enable latch */
53
54 static __xdata uint8_t ao_mr25_mutex;
55
56 /*
57  * This little array is abused to send and receive data. A particular
58  * caution -- the read and write addresses are written into the last
59  * three bytes of the array by ao_mr25_set_page_address and then the
60  * first byte is used by ao_mr25_write_enable, neither of which touch
61  * those last three bytes.
62  */
63
64 static __xdata uint8_t  ao_mr25_instruction[4];
65
66 #define MR25_SELECT()           ao_spi_get_mask(AO_MR25_SPI_CS_PORT,(1 << AO_MR25_SPI_CS_PIN),AO_MR25_SPI_BUS, AO_SPI_SPEED_FAST)
67 #define MR25_DESELECT()         ao_spi_put_mask(AO_MR25_SPI_CS_PORT,(1 << AO_MR25_SPI_CS_PIN),AO_MR25_SPI_BUS)
68
69 /*
70  * Set the write enable latch so that page program and sector
71  * erase commands will work. Also mark the chip as busy writing
72  * so that future operations will block until the WIP bit goes off
73  */
74 static void
75 ao_mr25_write_enable(void)
76 {
77         MR25_SELECT();
78         ao_mr25_instruction[0] = MR25_WREN;
79         ao_spi_send(&ao_mr25_instruction, 1, AO_MR25_SPI_BUS);
80         MR25_DESELECT();
81 }
82
83
84 static void
85 ao_mr25_set_address(uint32_t pos)
86 {
87         ao_mr25_instruction[1] = pos >> 16;
88         ao_mr25_instruction[2] = pos >> 8;
89         ao_mr25_instruction[3] = pos;
90 }
91
92 /*
93  * Erase the specified sector (no-op for MRAM)
94  */
95 uint8_t
96 ao_storage_erase(uint32_t pos) __reentrant
97 {
98         if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total)
99                 return 0;
100         return 1;
101 }
102
103 /*
104  * Write to flash
105  */
106 uint8_t
107 ao_storage_device_write(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
108 {
109         if (pos >= ao_storage_total || pos + len > ao_storage_total)
110                 return 0;
111
112         ao_mutex_get(&ao_mr25_mutex);
113
114         ao_mr25_set_address(pos);
115         ao_mr25_write_enable();
116
117         ao_mr25_instruction[0] = MR25_WRITE;
118         MR25_SELECT();
119         ao_spi_send(ao_mr25_instruction, 4, AO_MR25_SPI_BUS);
120         ao_spi_send(d, len, AO_MR25_SPI_BUS);
121         MR25_DESELECT();
122
123         ao_mutex_put(&ao_mr25_mutex);
124         return 1;
125 }
126
127 /*
128  * Read from flash
129  */
130 uint8_t
131 ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
132 {
133         if (pos >= ao_storage_total || pos + len > ao_storage_total)
134                 return 0;
135         ao_mutex_get(&ao_mr25_mutex);
136
137         ao_mr25_set_address(pos);
138
139         ao_mr25_instruction[0] = MR25_READ;
140         MR25_SELECT();
141         ao_spi_send(ao_mr25_instruction, 4, AO_MR25_SPI_BUS);
142         ao_spi_recv(d, len, AO_MR25_SPI_BUS);
143         MR25_DESELECT();
144
145         ao_mutex_put(&ao_mr25_mutex);
146         return 1;
147 }
148
149 void
150 ao_storage_flush(void) __reentrant
151 {
152 }
153
154 void
155 ao_storage_setup(void)
156 {
157 }
158
159 void
160 ao_storage_device_info(void) __reentrant
161 {
162         printf ("Detected chips 1 size %d\n", ao_storage_total >> 8);
163 }
164
165 void
166 ao_storage_device_init(void)
167 {
168         ao_storage_total = 512 * 1024;  /* 4Mb */
169         ao_storage_block = 256;
170         ao_storage_config = ao_storage_total - ao_storage_block;
171         ao_storage_unit = 256;
172         ao_spi_init_cs (AO_MR25_SPI_CS_PORT, (1 << AO_MR25_SPI_CS_PIN));
173 }