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");
104 * The device ignores any levels or transitions on the SCL pin
105 * when the device is idle, asleep or during waking up.
106 * Don't check for error when waking up the device.
109 atsha204a_send(dev
, req
, 4);
111 udelay(ATSHA204A_TWLO_US
+ ATSHA204A_TWHI_US
);
113 res
= atsha204a_recv_resp(dev
, &resp
);
115 debug("failed on receiving response, ending\n");
119 if (resp
.code
!= ATSHA204A_STATUS_AFTER_WAKE
) {
120 debug("failed (response code = %02x), ending\n", resp
.code
);
128 int atsha204a_idle(struct udevice
*dev
)
131 u8 req
= ATSHA204A_FUNC_IDLE
;
133 res
= atsha204a_send(dev
, &req
, 1);
135 debug("Failed putting ATSHA204A idle\n");
139 int atsha204a_sleep(struct udevice
*dev
)
142 u8 req
= ATSHA204A_FUNC_IDLE
;
144 res
= atsha204a_send(dev
, &req
, 1);
146 debug("Failed putting ATSHA204A to sleep\n");
150 static int atsha204a_transaction(struct udevice
*dev
, struct atsha204a_req
*req
,
151 struct atsha204a_resp
*resp
)
153 int res
, timeout
= ATSHA204A_TRANSACTION_TIMEOUT
;
155 res
= atsha204a_send(dev
, (u8
*) req
, req
->length
+ 1);
157 debug("ATSHA204A transaction send failed\n");
162 udelay(ATSHA204A_EXECTIME
);
163 res
= atsha204a_recv_resp(dev
, resp
);
164 if (!res
|| res
== -EMSGSIZE
|| res
== -EBADMSG
)
167 debug("ATSHA204A transaction polling for response "
168 "(timeout = %d)\n", timeout
);
170 timeout
-= ATSHA204A_EXECTIME
;
171 } while (timeout
> 0);
174 debug("ATSHA204A transaction timed out\n");
181 static void atsha204a_req_crc32(struct atsha204a_req
*req
)
185 u16
*crc_ptr
= (u16
*) &p
[req
->length
- 1];
187 /* The buffer to crc16 starts at byte 1, not 0 */
188 computed_crc
= atsha204a_crc16(p
+ 1, req
->length
- 2);
190 *crc_ptr
= cpu_to_le16(computed_crc
);
193 int atsha204a_read(struct udevice
*dev
, enum atsha204a_zone zone
, bool read32
,
194 u16 addr
, u8
*buffer
)
196 int res
, retry
= ATSHA204A_TRANSACTION_RETRY
;
197 struct atsha204a_req req
;
198 struct atsha204a_resp resp
;
200 req
.function
= ATSHA204A_FUNC_COMMAND
;
202 req
.command
= ATSHA204A_CMD_READ
;
204 req
.param1
= (u8
) zone
;
208 req
.param2
= cpu_to_le16(addr
);
210 atsha204a_req_crc32(&req
);
213 res
= atsha204a_transaction(dev
, &req
, &resp
);
217 debug("ATSHA204A read retry (%d)\n", retry
);
219 atsha204a_wakeup(dev
);
220 } while (retry
>= 0);
223 debug("ATSHA204A read failed\n");
227 if (resp
.length
!= (read32
? 32 : 4) + 3) {
228 debug("ATSHA204A read bad response length (%d)\n",
233 memcpy(buffer
, ((u8
*) &resp
) + 1, read32
? 32 : 4);
238 int atsha204a_get_random(struct udevice
*dev
, u8
*buffer
, size_t max
)
241 struct atsha204a_req req
;
242 struct atsha204a_resp resp
;
244 req
.function
= ATSHA204A_FUNC_COMMAND
;
246 req
.command
= ATSHA204A_CMD_RANDOM
;
251 /* We do not have to compute the checksum dynamically */
255 res
= atsha204a_transaction(dev
, &req
, &resp
);
257 debug("ATSHA204A random transaction failed\n");
261 memcpy(buffer
, ((u8
*) &resp
) + 1, max
>= 32 ? 32 : max
);
265 static int atsha204a_of_to_plat(struct udevice
*dev
)
267 fdt_addr_t
*priv
= dev_get_priv(dev
);
270 addr
= dev_read_addr(dev
);
271 if (addr
== FDT_ADDR_T_NONE
) {
272 debug("Can't get ATSHA204A I2C base address\n");
280 static const struct udevice_id atsha204a_ids
[] = {
281 { .compatible
= "atmel,atsha204" },
282 { .compatible
= "atmel,atsha204a" },
286 U_BOOT_DRIVER(atsha204
) = {
289 .of_match
= atsha204a_ids
,
290 .of_to_plat
= atsha204a_of_to_plat
,
291 .priv_auto
= sizeof(fdt_addr_t
),