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