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