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 #define ATSHA204A_TWLO 60
20 #define ATSHA204A_TRANSACTION_TIMEOUT 100000
21 #define ATSHA204A_TRANSACTION_RETRY 5
22 #define ATSHA204A_EXECTIME 5000
24 DECLARE_GLOBAL_DATA_PTR;
27 * The ATSHA204A uses an (to me) unknown CRC-16 algorithm.
28 * The Reveng CRC-16 catalogue does not contain it.
30 * Because in Atmel's documentation only a primitive implementation
31 * can be found, I have implemented this one with lookup table.
35 * This is the code that computes the table below:
38 * for (i = 0; i < 256; ++i) {
40 * for (j = 0; j < 8; ++j) {
41 * c = (c << 1) | ((i >> j) & 1);
43 * bitreverse_table[i] = c;
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,
83 * This is the code that computes the table below:
86 * for (i = 0; i < 256; ++i) {
88 * for (j = 0; j < 8; ++j) {
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,
132 static inline u16 crc16_byte(u16 crc, const u8 data)
134 u16 t = crc16_table[((crc >> 8) ^ bitreverse_table[data]) & 0xff];
135 return ((crc << 8) ^ t);
138 static u16 atsha204a_crc16(const u8 *buffer, size_t len)
143 crc = crc16_byte(crc, *buffer++);
145 return cpu_to_le16(crc);
148 static int atsha204a_send(struct udevice *dev, const u8 *buf, u8 len)
150 fdt_addr_t *priv = dev_get_priv(dev);
154 msg.flags = I2C_M_STOP;
156 msg.buf = (u8 *) buf;
158 return dm_i2c_xfer(dev, &msg, 1);
161 static int atsha204a_recv(struct udevice *dev, u8 *buf, u8 len)
163 fdt_addr_t *priv = dev_get_priv(dev);
167 msg.flags = I2C_M_RD | I2C_M_STOP;
169 msg.buf = (u8 *) buf;
171 return dm_i2c_xfer(dev, &msg, 1);
174 static int atsha204a_recv_resp(struct udevice *dev,
175 struct atsha204a_resp *resp)
178 u16 resp_crc, computed_crc;
181 res = atsha204a_recv(dev, p, 4);
185 if (resp->length > 4) {
186 if (resp->length > sizeof(*resp))
189 res = atsha204a_recv(dev, p + 4, resp->length - 4);
194 resp_crc = (u16) p[resp->length - 2]
195 | (((u16) p[resp->length - 1]) << 8);
196 computed_crc = atsha204a_crc16(p, resp->length - 2);
198 if (resp_crc != computed_crc) {
199 debug("Invalid checksum in ATSHA204A response\n");
206 int atsha204a_wakeup(struct udevice *dev)
209 struct atsha204a_resp resp;
212 debug("Waking up ATSHA204A\n");
214 for (try = 1; try <= 10; ++try) {
215 debug("Try %i... ", try);
218 res = atsha204a_send(dev, req, 4);
220 debug("failed on I2C send, trying again\n");
224 udelay(ATSHA204A_TWLO);
226 res = atsha204a_recv_resp(dev, &resp);
228 debug("failed on receiving response, ending\n");
232 if (resp.code != ATSHA204A_STATUS_AFTER_WAKE) {
233 debug ("failed (responce code = %02x), ending\n",
245 int atsha204a_idle(struct udevice *dev)
248 u8 req = ATSHA204A_FUNC_IDLE;
250 res = atsha204a_send(dev, &req, 1);
252 debug("Failed putting ATSHA204A idle\n");
256 int atsha204a_sleep(struct udevice *dev)
259 u8 req = ATSHA204A_FUNC_IDLE;
261 res = atsha204a_send(dev, &req, 1);
263 debug("Failed putting ATSHA204A to sleep\n");
267 static int atsha204a_transaction(struct udevice *dev, struct atsha204a_req *req,
268 struct atsha204a_resp *resp)
270 int res, timeout = ATSHA204A_TRANSACTION_TIMEOUT;
272 res = atsha204a_send(dev, (u8 *) req, req->length + 1);
274 debug("ATSHA204A transaction send failed\n");
279 res = atsha204a_recv_resp(dev, resp);
280 if (!res || res == -EMSGSIZE || res == -EBADMSG)
283 debug("ATSHA204A transaction polling for response "
284 "(timeout = %d)\n", timeout);
286 udelay(ATSHA204A_EXECTIME);
287 timeout -= ATSHA204A_EXECTIME;
288 } while (timeout > 0);
291 debug("ATSHA204A transaction timed out\n");
298 static void atsha204a_req_crc32(struct atsha204a_req *req)
302 u16 *crc_ptr = (u16 *) &p[req->length - 1];
304 /* The buffer to crc16 starts at byte 1, not 0 */
305 computed_crc = atsha204a_crc16(p + 1, req->length - 2);
307 *crc_ptr = cpu_to_le16(computed_crc);
310 int atsha204a_read(struct udevice *dev, enum atsha204a_zone zone, bool read32,
311 u16 addr, u8 *buffer)
313 int res, retry = ATSHA204A_TRANSACTION_RETRY;
314 struct atsha204a_req req;
315 struct atsha204a_resp resp;
317 req.function = ATSHA204A_FUNC_COMMAND;
319 req.command = ATSHA204A_CMD_READ;
321 req.param1 = (u8) zone;
325 req.param2 = cpu_to_le16(addr);
327 atsha204a_req_crc32(&req);
330 res = atsha204a_transaction(dev, &req, &resp);
334 debug("ATSHA204A read retry (%d)\n", retry);
336 atsha204a_wakeup(dev);
337 } while (retry >= 0);
340 debug("ATSHA204A read failed\n");
344 if (resp.length != (read32 ? 32 : 4) + 3) {
345 debug("ATSHA204A read bad response length (%d)\n",
350 memcpy(buffer, ((u8 *) &resp) + 1, read32 ? 32 : 4);
355 int atsha204a_get_random(struct udevice *dev, u8 *buffer, size_t max)
358 struct atsha204a_req req;
359 struct atsha204a_resp resp;
361 req.function = ATSHA204A_FUNC_COMMAND;
363 req.command = ATSHA204A_CMD_RANDOM;
368 /* We do not have to compute the checksum dynamically */
372 res = atsha204a_transaction(dev, &req, &resp);
374 debug("ATSHA204A random transaction failed\n");
378 memcpy(buffer, ((u8 *) &resp) + 1, max >= 32 ? 32 : max);
382 static int atsha204a_ofdata_to_platdata(struct udevice *dev)
384 fdt_addr_t *priv = dev_get_priv(dev);
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");
397 static const struct udevice_id atsha204a_ids[] = {
398 { .compatible = "atmel,atsha204a" },
402 U_BOOT_DRIVER(atsha204) = {
405 .of_match = atsha204a_ids,
406 .ofdata_to_platdata = atsha204a_ofdata_to_platdata,
407 .priv_auto_alloc_size = sizeof(fdt_addr_t),