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 BehĂșn, CZ.NIC, kabel@kernel.org
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 <asm/global_data.h>
20 #include <linux/delay.h>
21 #include <linux/bitrev.h>
22 #include <u-boot/crc.h>
24 #define ATSHA204A_TWLO_US 60
25 #define ATSHA204A_TWHI_US 2500
26 #define ATSHA204A_TRANSACTION_TIMEOUT 100000
27 #define ATSHA204A_TRANSACTION_RETRY 5
28 #define ATSHA204A_EXECTIME 5000
30 DECLARE_GLOBAL_DATA_PTR
;
32 static inline u16
atsha204a_crc16(const u8
*buffer
, size_t len
)
34 return bitrev16(crc16(0, buffer
, len
));
37 static int atsha204a_send(struct udevice
*dev
, const u8
*buf
, u8 len
)
39 fdt_addr_t
*priv
= dev_get_priv(dev
);
43 msg
.flags
= I2C_M_STOP
;
47 return dm_i2c_xfer(dev
, &msg
, 1);
50 static int atsha204a_recv(struct udevice
*dev
, u8
*buf
, u8 len
)
52 fdt_addr_t
*priv
= dev_get_priv(dev
);
56 msg
.flags
= I2C_M_RD
| I2C_M_STOP
;
60 return dm_i2c_xfer(dev
, &msg
, 1);
63 static int atsha204a_recv_resp(struct udevice
*dev
,
64 struct atsha204a_resp
*resp
)
67 u16 resp_crc
, computed_crc
;
70 res
= atsha204a_recv(dev
, p
, 4);
74 if (resp
->length
> 4) {
75 if (resp
->length
> sizeof(*resp
))
78 res
= atsha204a_recv(dev
, p
+ 4, resp
->length
- 4);
83 resp_crc
= (u16
) p
[resp
->length
- 2]
84 | (((u16
) p
[resp
->length
- 1]) << 8);
85 computed_crc
= atsha204a_crc16(p
, resp
->length
- 2);
87 if (resp_crc
!= computed_crc
) {
88 debug("Invalid checksum in ATSHA204A response\n");
95 int atsha204a_wakeup(struct udevice
*dev
)
98 struct atsha204a_resp resp
;
101 debug("Waking up ATSHA204A\n");
103 for (try = 1; try <= 10; ++try) {
104 debug("Try %i... ", try);
107 res
= atsha204a_send(dev
, req
, 4);
109 debug("failed on I2C send, trying again\n");
113 udelay(ATSHA204A_TWLO_US
+ ATSHA204A_TWHI_US
);
115 res
= atsha204a_recv_resp(dev
, &resp
);
117 debug("failed on receiving response, ending\n");
121 if (resp
.code
!= ATSHA204A_STATUS_AFTER_WAKE
) {
122 debug ("failed (responce code = %02x), ending\n",
134 int atsha204a_idle(struct udevice
*dev
)
137 u8 req
= ATSHA204A_FUNC_IDLE
;
139 res
= atsha204a_send(dev
, &req
, 1);
141 debug("Failed putting ATSHA204A idle\n");
145 int atsha204a_sleep(struct udevice
*dev
)
148 u8 req
= ATSHA204A_FUNC_IDLE
;
150 res
= atsha204a_send(dev
, &req
, 1);
152 debug("Failed putting ATSHA204A to sleep\n");
156 static int atsha204a_transaction(struct udevice
*dev
, struct atsha204a_req
*req
,
157 struct atsha204a_resp
*resp
)
159 int res
, timeout
= ATSHA204A_TRANSACTION_TIMEOUT
;
161 res
= atsha204a_send(dev
, (u8
*) req
, req
->length
+ 1);
163 debug("ATSHA204A transaction send failed\n");
168 udelay(ATSHA204A_EXECTIME
);
169 res
= atsha204a_recv_resp(dev
, resp
);
170 if (!res
|| res
== -EMSGSIZE
|| res
== -EBADMSG
)
173 debug("ATSHA204A transaction polling for response "
174 "(timeout = %d)\n", timeout
);
176 timeout
-= ATSHA204A_EXECTIME
;
177 } while (timeout
> 0);
180 debug("ATSHA204A transaction timed out\n");
187 static void atsha204a_req_crc32(struct atsha204a_req
*req
)
191 u16
*crc_ptr
= (u16
*) &p
[req
->length
- 1];
193 /* The buffer to crc16 starts at byte 1, not 0 */
194 computed_crc
= atsha204a_crc16(p
+ 1, req
->length
- 2);
196 *crc_ptr
= cpu_to_le16(computed_crc
);
199 int atsha204a_read(struct udevice
*dev
, enum atsha204a_zone zone
, bool read32
,
200 u16 addr
, u8
*buffer
)
202 int res
, retry
= ATSHA204A_TRANSACTION_RETRY
;
203 struct atsha204a_req req
;
204 struct atsha204a_resp resp
;
206 req
.function
= ATSHA204A_FUNC_COMMAND
;
208 req
.command
= ATSHA204A_CMD_READ
;
210 req
.param1
= (u8
) zone
;
214 req
.param2
= cpu_to_le16(addr
);
216 atsha204a_req_crc32(&req
);
219 res
= atsha204a_transaction(dev
, &req
, &resp
);
223 debug("ATSHA204A read retry (%d)\n", retry
);
225 atsha204a_wakeup(dev
);
226 } while (retry
>= 0);
229 debug("ATSHA204A read failed\n");
233 if (resp
.length
!= (read32
? 32 : 4) + 3) {
234 debug("ATSHA204A read bad response length (%d)\n",
239 memcpy(buffer
, ((u8
*) &resp
) + 1, read32
? 32 : 4);
244 int atsha204a_get_random(struct udevice
*dev
, u8
*buffer
, size_t max
)
247 struct atsha204a_req req
;
248 struct atsha204a_resp resp
;
250 req
.function
= ATSHA204A_FUNC_COMMAND
;
252 req
.command
= ATSHA204A_CMD_RANDOM
;
257 /* We do not have to compute the checksum dynamically */
261 res
= atsha204a_transaction(dev
, &req
, &resp
);
263 debug("ATSHA204A random transaction failed\n");
267 memcpy(buffer
, ((u8
*) &resp
) + 1, max
>= 32 ? 32 : max
);
271 static int atsha204a_of_to_plat(struct udevice
*dev
)
273 fdt_addr_t
*priv
= dev_get_priv(dev
);
276 addr
= dev_read_addr(dev
);
277 if (addr
== FDT_ADDR_T_NONE
) {
278 debug("Can't get ATSHA204A I2C base address\n");
286 static const struct udevice_id atsha204a_ids
[] = {
287 { .compatible
= "atmel,atsha204" },
288 { .compatible
= "atmel,atsha204a" },
292 U_BOOT_DRIVER(atsha204
) = {
295 .of_match
= atsha204a_ids
,
296 .of_to_plat
= atsha204a_of_to_plat
,
297 .priv_auto
= sizeof(fdt_addr_t
),