]> git.sur5r.net Git - u-boot/blob - drivers/misc/atsha204a-i2c.c
Merge git://git.denx.de/u-boot-sh
[u-boot] / drivers / misc / atsha204a-i2c.c
1 /*
2  * I2C Driver for Atmel ATSHA204 over I2C
3  *
4  * Copyright (C) 2014 Josh Datko, Cryptotronix, jbd@cryptotronix.com
5  *               2016 Tomas Hlavacek, CZ.NIC, tmshlvck@gmail.com
6  *               2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
7  *
8  * This program is free software; you can redistribute  it and/or modify it
9  * under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <common.h>
14 #include <dm.h>
15 #include <i2c.h>
16 #include <errno.h>
17 #include <atsha204a-i2c.h>
18
19 #define ATSHA204A_TWLO                  60
20 #define ATSHA204A_TRANSACTION_TIMEOUT   100000
21 #define ATSHA204A_TRANSACTION_RETRY     5
22 #define ATSHA204A_EXECTIME              5000
23
24 DECLARE_GLOBAL_DATA_PTR;
25
26 /*
27  * The ATSHA204A uses an (to me) unknown CRC-16 algorithm.
28  * The Reveng CRC-16 catalogue does not contain it.
29  *
30  * Because in Atmel's documentation only a primitive implementation
31  * can be found, I have implemented this one with lookup table.
32  */
33
34 /*
35  * This is the code that computes the table below:
36  *
37  * int i, j;
38  * for (i = 0; i < 256; ++i) {
39  *      u8 c = 0;
40  *      for (j = 0; j < 8; ++j) {
41  *              c = (c << 1) | ((i >> j) & 1);
42  *      }
43  *      bitreverse_table[i] = c;
44  * }
45  */
46
47 static u8 const bitreverse_table[256] = {
48         0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
49         0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
50         0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
51         0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
52         0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
53         0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
54         0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
55         0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
56         0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
57         0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
58         0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
59         0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
60         0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
61         0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
62         0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
63         0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
64         0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
65         0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
66         0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
67         0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
68         0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
69         0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
70         0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
71         0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
72         0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
73         0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
74         0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
75         0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
76         0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
77         0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
78         0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
79         0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
80 };
81
82 /*
83  * This is the code that computes the table below:
84  *
85  * int i, j;
86  * for (i = 0; i < 256; ++i) {
87  *      u16 c = i << 8;
88  *      for (j = 0; j < 8; ++j) {
89  *              int b = c >> 15;
90  *              c <<= 1;
91  *              if (b)
92  *                      c ^= 0x8005;
93  *      }
94  *      crc16_table[i] = c;
95  * }
96  */
97 static u16 const crc16_table[256] = {
98         0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
99         0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
100         0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
101         0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
102         0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
103         0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
104         0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
105         0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
106         0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
107         0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
108         0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
109         0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
110         0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
111         0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
112         0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
113         0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
114         0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
115         0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
116         0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
117         0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
118         0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
119         0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
120         0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
121         0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
122         0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
123         0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
124         0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
125         0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
126         0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
127         0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
128         0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
129         0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202,
130 };
131
132 static inline u16 crc16_byte(u16 crc, const u8 data)
133 {
134         u16 t = crc16_table[((crc >> 8) ^ bitreverse_table[data]) & 0xff];
135         return ((crc << 8) ^ t);
136 }
137
138 static u16 atsha204a_crc16(const u8 *buffer, size_t len)
139 {
140         u16 crc = 0;
141
142         while (len--)
143                 crc = crc16_byte(crc, *buffer++);
144
145         return cpu_to_le16(crc);
146 }
147
148 static int atsha204a_send(struct udevice *dev, const u8 *buf, u8 len)
149 {
150         fdt_addr_t *priv = dev_get_priv(dev);
151         struct i2c_msg msg;
152
153         msg.addr = *priv;
154         msg.flags = I2C_M_STOP;
155         msg.len = len;
156         msg.buf = (u8 *) buf;
157
158         return dm_i2c_xfer(dev, &msg, 1);
159 }
160
161 static int atsha204a_recv(struct udevice *dev, u8 *buf, u8 len)
162 {
163         fdt_addr_t *priv = dev_get_priv(dev);
164         struct i2c_msg msg;
165
166         msg.addr = *priv;
167         msg.flags = I2C_M_RD | I2C_M_STOP;
168         msg.len = len;
169         msg.buf = (u8 *) buf;
170
171         return dm_i2c_xfer(dev, &msg, 1);
172 }
173
174 static int atsha204a_recv_resp(struct udevice *dev,
175                                struct atsha204a_resp *resp)
176 {
177         int res;
178         u16 resp_crc, computed_crc;
179         u8 *p = (u8 *) resp;
180
181         res = atsha204a_recv(dev, p, 4);
182         if (res)
183                 return res;
184
185         if (resp->length > 4) {
186                 if (resp->length > sizeof(*resp))
187                         return -EMSGSIZE;
188
189                 res = atsha204a_recv(dev, p + 4, resp->length - 4);
190                 if (res)
191                         return res;
192         }
193
194         resp_crc = (u16) p[resp->length - 2]
195                    | (((u16) p[resp->length - 1]) << 8);
196         computed_crc = atsha204a_crc16(p, resp->length - 2);
197
198         if (resp_crc != computed_crc) {
199                 debug("Invalid checksum in ATSHA204A response\n");
200                 return -EBADMSG;
201         }
202
203         return 0;
204 }
205
206 int atsha204a_wakeup(struct udevice *dev)
207 {
208         u8 req[4];
209         struct atsha204a_resp resp;
210         int try, res;
211
212         debug("Waking up ATSHA204A\n");
213
214         for (try = 1; try <= 10; ++try) {
215                 debug("Try %i... ", try);
216
217                 memset(req, 0, 4);
218                 res = atsha204a_send(dev, req, 4);
219                 if (res) {
220                         debug("failed on I2C send, trying again\n");
221                         continue;
222                 }
223
224                 udelay(ATSHA204A_TWLO);
225
226                 res = atsha204a_recv_resp(dev, &resp);
227                 if (res) {
228                         debug("failed on receiving response, ending\n");
229                         return res;
230                 }
231
232                 if (resp.code != ATSHA204A_STATUS_AFTER_WAKE) {
233                         debug ("failed (responce code = %02x), ending\n",
234                                resp.code);
235                         return -EBADMSG;
236                 }
237
238                 debug("success\n");
239                 break;
240         }
241
242         return 0;
243 }
244
245 int atsha204a_idle(struct udevice *dev)
246 {
247         int res;
248         u8 req = ATSHA204A_FUNC_IDLE;
249
250         res = atsha204a_send(dev, &req, 1);
251         if (res)
252                 debug("Failed putting ATSHA204A idle\n");
253         return res;
254 }
255
256 int atsha204a_sleep(struct udevice *dev)
257 {
258         int res;
259         u8 req = ATSHA204A_FUNC_IDLE;
260
261         res = atsha204a_send(dev, &req, 1);
262         if (res)
263                 debug("Failed putting ATSHA204A to sleep\n");
264         return res;
265 }
266
267 static int atsha204a_transaction(struct udevice *dev, struct atsha204a_req *req,
268                                 struct atsha204a_resp *resp)
269 {
270         int res, timeout = ATSHA204A_TRANSACTION_TIMEOUT;
271
272         res = atsha204a_send(dev, (u8 *) req, req->length + 1);
273         if (res) {
274                 debug("ATSHA204A transaction send failed\n");
275                 return -EBUSY;
276         }
277
278         do {
279                 res = atsha204a_recv_resp(dev, resp);
280                 if (!res || res == -EMSGSIZE || res == -EBADMSG)
281                         break;
282
283                 debug("ATSHA204A transaction polling for response "
284                       "(timeout = %d)\n", timeout);
285
286                 udelay(ATSHA204A_EXECTIME);
287                 timeout -= ATSHA204A_EXECTIME;
288         } while (timeout > 0);
289
290         if (timeout <= 0) {
291                 debug("ATSHA204A transaction timed out\n");
292                 return -ETIMEDOUT;
293         }
294
295         return res;
296 }
297
298 static void atsha204a_req_crc32(struct atsha204a_req *req)
299 {
300         u8 *p = (u8 *) req;
301         u16 computed_crc;
302         u16 *crc_ptr = (u16 *) &p[req->length - 1];
303
304         /* The buffer to crc16 starts at byte 1, not 0 */
305         computed_crc = atsha204a_crc16(p + 1, req->length - 2);
306
307         *crc_ptr = cpu_to_le16(computed_crc);
308 }
309
310 int atsha204a_read(struct udevice *dev, enum atsha204a_zone zone, bool read32,
311                   u16 addr, u8 *buffer)
312 {
313         int res, retry = ATSHA204A_TRANSACTION_RETRY;
314         struct atsha204a_req req;
315         struct atsha204a_resp resp;
316
317         req.function = ATSHA204A_FUNC_COMMAND;
318         req.length = 7;
319         req.command = ATSHA204A_CMD_READ;
320
321         req.param1 = (u8) zone;
322         if (read32)
323                 req.param1 |= 0x80;
324
325         req.param2 = cpu_to_le16(addr);
326
327         atsha204a_req_crc32(&req);
328
329         do {
330                 res = atsha204a_transaction(dev, &req, &resp);
331                 if (!res)
332                         break;
333
334                 debug("ATSHA204A read retry (%d)\n", retry);
335                 retry--;
336                 atsha204a_wakeup(dev);
337         } while (retry >= 0);
338         
339         if (res) {
340                 debug("ATSHA204A read failed\n");
341                 return res;
342         }
343
344         if (resp.length != (read32 ? 32 : 4) + 3) {
345                 debug("ATSHA204A read bad response length (%d)\n",
346                       resp.length);
347                 return -EBADMSG;
348         }
349
350         memcpy(buffer, ((u8 *) &resp) + 1, read32 ? 32 : 4);
351
352         return 0;
353 }
354
355 int atsha204a_get_random(struct udevice *dev, u8 *buffer, size_t max)
356 {
357         int res;
358         struct atsha204a_req req;
359         struct atsha204a_resp resp;
360
361         req.function = ATSHA204A_FUNC_COMMAND;
362         req.length = 7;
363         req.command = ATSHA204A_CMD_RANDOM;
364
365         req.param1 = 1;
366         req.param2 = 0;
367
368         /* We do not have to compute the checksum dynamically */
369         req.data[0] = 0x27;
370         req.data[1] = 0x47;
371
372         res = atsha204a_transaction(dev, &req, &resp);
373         if (res) {
374                 debug("ATSHA204A random transaction failed\n");
375                 return res;
376         }
377
378         memcpy(buffer, ((u8 *) &resp) + 1, max >= 32 ? 32 : max);
379         return 0;
380 }
381
382 static int atsha204a_ofdata_to_platdata(struct udevice *dev)
383 {
384         fdt_addr_t *priv = dev_get_priv(dev);
385         fdt_addr_t addr;
386
387         addr = fdtdec_get_addr(gd->fdt_blob, dev_of_offset(dev), "reg");
388         if (addr == FDT_ADDR_T_NONE) {
389                 debug("Can't get ATSHA204A I2C base address\n");
390                 return -ENXIO;
391         }
392
393         *priv = addr;
394         return 0;
395 }
396
397 static const struct udevice_id atsha204a_ids[] = {
398         { .compatible = "atmel,atsha204a" },
399         { }
400 };
401
402 U_BOOT_DRIVER(atsha204) = {
403         .name                   = "atsha204",
404         .id                     = UCLASS_MISC,
405         .of_match               = atsha204a_ids,
406         .ofdata_to_platdata     = atsha204a_ofdata_to_platdata,
407         .priv_auto_alloc_size   = sizeof(fdt_addr_t),
408 };