2 * I2C Driver for Atmel ATSHA204 over I2C
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
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.
17 #include <atsha204a-i2c.h>
19 #include <u-boot/crc.h>
21 #define ATSHA204A_TWLO 60
22 #define ATSHA204A_TRANSACTION_TIMEOUT 100000
23 #define ATSHA204A_TRANSACTION_RETRY 5
24 #define ATSHA204A_EXECTIME 5000
26 DECLARE_GLOBAL_DATA_PTR;
29 * The ATSHA204A uses an (to me) unknown CRC-16 algorithm.
30 * The Reveng CRC-16 catalogue does not contain it.
32 * Because in Atmel's documentation only a primitive implementation
33 * can be found, I have implemented this one with lookup table.
37 * This is the code that computes the table below:
40 * for (i = 0; i < 256; ++i) {
42 * for (j = 0; j < 8; ++j) {
43 * c = (c << 1) | ((i >> j) & 1);
45 * bitreverse_table[i] = c;
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,
85 * This is the code that computes the table below:
88 * for (i = 0; i < 256; ++i) {
90 * for (j = 0; j < 8; ++j) {
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,
134 static inline u16 crc16_byte(u16 crc, const u8 data)
136 u16 t = crc16_table[((crc >> 8) ^ bitreverse_table[data]) & 0xff];
137 return ((crc << 8) ^ t);
140 static u16 atsha204a_crc16(const u8 *buffer, size_t len)
145 crc = crc16_byte(crc, *buffer++);
147 return cpu_to_le16(crc);
150 static int atsha204a_send(struct udevice *dev, const u8 *buf, u8 len)
152 fdt_addr_t *priv = dev_get_priv(dev);
156 msg.flags = I2C_M_STOP;
158 msg.buf = (u8 *) buf;
160 return dm_i2c_xfer(dev, &msg, 1);
163 static int atsha204a_recv(struct udevice *dev, u8 *buf, u8 len)
165 fdt_addr_t *priv = dev_get_priv(dev);
169 msg.flags = I2C_M_RD | I2C_M_STOP;
171 msg.buf = (u8 *) buf;
173 return dm_i2c_xfer(dev, &msg, 1);
176 static int atsha204a_recv_resp(struct udevice *dev,
177 struct atsha204a_resp *resp)
180 u16 resp_crc, computed_crc;
183 res = atsha204a_recv(dev, p, 4);
187 if (resp->length > 4) {
188 if (resp->length > sizeof(*resp))
191 res = atsha204a_recv(dev, p + 4, resp->length - 4);
196 resp_crc = (u16) p[resp->length - 2]
197 | (((u16) p[resp->length - 1]) << 8);
198 computed_crc = atsha204a_crc16(p, resp->length - 2);
200 if (resp_crc != computed_crc) {
201 debug("Invalid checksum in ATSHA204A response\n");
208 int atsha204a_wakeup(struct udevice *dev)
211 struct atsha204a_resp resp;
214 debug("Waking up ATSHA204A\n");
216 for (try = 1; try <= 10; ++try) {
217 debug("Try %i... ", try);
220 res = atsha204a_send(dev, req, 4);
222 debug("failed on I2C send, trying again\n");
226 udelay(ATSHA204A_TWLO);
228 res = atsha204a_recv_resp(dev, &resp);
230 debug("failed on receiving response, ending\n");
234 if (resp.code != ATSHA204A_STATUS_AFTER_WAKE) {
235 debug ("failed (responce code = %02x), ending\n",
247 int atsha204a_idle(struct udevice *dev)
250 u8 req = ATSHA204A_FUNC_IDLE;
252 res = atsha204a_send(dev, &req, 1);
254 debug("Failed putting ATSHA204A idle\n");
258 int atsha204a_sleep(struct udevice *dev)
261 u8 req = ATSHA204A_FUNC_IDLE;
263 res = atsha204a_send(dev, &req, 1);
265 debug("Failed putting ATSHA204A to sleep\n");
269 static int atsha204a_transaction(struct udevice *dev, struct atsha204a_req *req,
270 struct atsha204a_resp *resp)
272 int res, timeout = ATSHA204A_TRANSACTION_TIMEOUT;
274 res = atsha204a_send(dev, (u8 *) req, req->length + 1);
276 debug("ATSHA204A transaction send failed\n");
281 res = atsha204a_recv_resp(dev, resp);
282 if (!res || res == -EMSGSIZE || res == -EBADMSG)
285 debug("ATSHA204A transaction polling for response "
286 "(timeout = %d)\n", timeout);
288 udelay(ATSHA204A_EXECTIME);
289 timeout -= ATSHA204A_EXECTIME;
290 } while (timeout > 0);
293 debug("ATSHA204A transaction timed out\n");
300 static void atsha204a_req_crc32(struct atsha204a_req *req)
304 u16 *crc_ptr = (u16 *) &p[req->length - 1];
306 /* The buffer to crc16 starts at byte 1, not 0 */
307 computed_crc = atsha204a_crc16(p + 1, req->length - 2);
309 *crc_ptr = cpu_to_le16(computed_crc);
312 int atsha204a_read(struct udevice *dev, enum atsha204a_zone zone, bool read32,
313 u16 addr, u8 *buffer)
315 int res, retry = ATSHA204A_TRANSACTION_RETRY;
316 struct atsha204a_req req;
317 struct atsha204a_resp resp;
319 req.function = ATSHA204A_FUNC_COMMAND;
321 req.command = ATSHA204A_CMD_READ;
323 req.param1 = (u8) zone;
327 req.param2 = cpu_to_le16(addr);
329 atsha204a_req_crc32(&req);
332 res = atsha204a_transaction(dev, &req, &resp);
336 debug("ATSHA204A read retry (%d)\n", retry);
338 atsha204a_wakeup(dev);
339 } while (retry >= 0);
342 debug("ATSHA204A read failed\n");
346 if (resp.length != (read32 ? 32 : 4) + 3) {
347 debug("ATSHA204A read bad response length (%d)\n",
352 memcpy(buffer, ((u8 *) &resp) + 1, read32 ? 32 : 4);
357 int atsha204a_get_random(struct udevice *dev, u8 *buffer, size_t max)
360 struct atsha204a_req req;
361 struct atsha204a_resp resp;
363 req.function = ATSHA204A_FUNC_COMMAND;
365 req.command = ATSHA204A_CMD_RANDOM;
370 /* We do not have to compute the checksum dynamically */
374 res = atsha204a_transaction(dev, &req, &resp);
376 debug("ATSHA204A random transaction failed\n");
380 memcpy(buffer, ((u8 *) &resp) + 1, max >= 32 ? 32 : max);
384 static int atsha204a_ofdata_to_platdata(struct udevice *dev)
386 fdt_addr_t *priv = dev_get_priv(dev);
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");
399 static const struct udevice_id atsha204a_ids[] = {
400 { .compatible = "atmel,atsha204a" },
404 U_BOOT_DRIVER(atsha204) = {
407 .of_match = atsha204a_ids,
408 .ofdata_to_platdata = atsha204a_ofdata_to_platdata,
409 .priv_auto_alloc_size = sizeof(fdt_addr_t),