staticconststruct {
u8 value; constchar *error_text;
} error_list[] = {
{ 0x01, "CheckMac or Verify miscompare" },
{ 0x03, "Parse Error" },
{ 0x05, "ECC Fault" },
{ 0x0F, "Execution Error" },
{ 0xEE, "Watchdog about to expire" },
{ 0xFF, "CRC or other communication error" },
};
/** * atmel_i2c_checksum() - Generate 16-bit CRC as required by ATMEL ECC. * CRC16 verification of the count, opcode, param1, param2 and data bytes. * The checksum is saved in little-endian format in the least significant * two bytes of the command. CRC polynomial is 0x8005 and the initial register * value should be zero. * * @cmd : structure used for communicating with the device.
*/ staticvoid atmel_i2c_checksum(struct atmel_i2c_cmd *cmd)
{
u8 *data = &cmd->count;
size_t len = cmd->count - CRC_SIZE;
__le16 *__crc16 = (__le16 *)(data + len);
int atmel_i2c_init_read_otp_cmd(struct atmel_i2c_cmd *cmd, u16 addr)
{ if (addr < 0 || addr > OTP_ZONE_SIZE) return -1;
cmd->word_addr = COMMAND;
cmd->opcode = OPCODE_READ; /* * Read the word from OTP zone that may contain e.g. serial * numbers or similar if persistently pre-initialized and locked
*/
cmd->param1 = OTP_ZONE;
cmd->param2 = cpu_to_le16(addr);
cmd->count = READ_COUNT;
/* * The device only supports NIST P256 ECC keys. The public key size will * always be the same. Use a macro for the key size to avoid unnecessary * computations.
*/
copied = sg_copy_to_buffer(pubkey,
sg_nents_for_len(pubkey,
ATMEL_ECC_PUBKEY_SIZE),
cmd->data, ATMEL_ECC_PUBKEY_SIZE); if (copied != ATMEL_ECC_PUBKEY_SIZE) return -EINVAL;
/* * After wake and after execution of a command, there will be error, status, or * result bytes in the device's output register that can be retrieved by the * system. When the length of that group is four bytes, the codes returned are * detailed in error_list.
*/ staticint atmel_i2c_status(struct device *dev, u8 *status)
{
size_t err_list_len = ARRAY_SIZE(error_list); int i;
u8 err_id = status[1];
if (*status != STATUS_SIZE) return 0;
if (err_id == STATUS_WAKE_SUCCESSFUL || err_id == STATUS_NOERR) return 0;
for (i = 0; i < err_list_len; i++) if (error_list[i].value == err_id) break;
/* if err_id is not in the error_list then ignore it */ if (i != err_list_len) {
dev_err(dev, "%02x: %s:\n", err_id, error_list[i].error_text); return err_id;
}
/* * The device ignores any levels or transitions on the SCL pin when the * device is idle, asleep or during waking up. Don't check for error * when waking up the device.
*/
i2c_transfer_buffer_flags(client, i2c_priv->wake_token,
i2c_priv->wake_token_sz, I2C_M_IGNORE_NAK);
/* * Wait to wake the device. Typical execution times for ecdh and genkey * are around tens of milliseconds. Delta is chosen to 50 microseconds.
*/
usleep_range(TWHI_MIN, TWHI_MAX);
ret = i2c_master_recv(client, status, STATUS_SIZE); if (ret < 0) return ret;
/* * atmel_i2c_send_receive() - send a command to the device and receive its * response. * @client: i2c client device * @cmd : structure used to communicate with the device * * After the device receives a Wake token, a watchdog counter starts within the * device. After the watchdog timer expires, the device enters sleep mode * regardless of whether some I/O transmission or command execution is in * progress. If a command is attempted when insufficient time remains prior to * watchdog timer execution, the device will return the watchdog timeout error * code without attempting to execute the command. There is no way to reset the * counter other than to put the device into sleep or idle mode and then * wake it up again.
*/ int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd)
{ struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); int ret;
mutex_lock(&i2c_priv->lock);
ret = atmel_i2c_wakeup(client); if (ret) goto err;
/* send the command */
ret = i2c_master_send(client, (u8 *)cmd, cmd->count + WORD_ADDR_SIZE); if (ret < 0) goto err;
/* delay the appropriate amount of time for command to execute */
msleep(cmd->msecs);
/* receive the response */
ret = i2c_master_recv(client, cmd->data, cmd->rxsize); if (ret < 0) goto err;
/* put the device into low-power mode */
ret = atmel_i2c_sleep(client); if (ret < 0) goto err;
/* return the size of the wake_token in bytes */ return DIV_ROUND_UP(no_of_bits, 8);
}
staticint device_sanity_check(struct i2c_client *client)
{ struct atmel_i2c_cmd *cmd; int ret;
cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) return -ENOMEM;
atmel_i2c_init_read_config_cmd(cmd);
ret = atmel_i2c_send_receive(client, cmd); if (ret) goto free_cmd;
/* * It is vital that the Configuration, Data and OTP zones be locked * prior to release into the field of the system containing the device. * Failure to lock these zones may permit modification of any secret * keys and may lead to other security problems.
*/ if (cmd->data[LOCK_CONFIG_IDX] || cmd->data[LOCK_VALUE_IDX]) {
dev_err(&client->dev, "Configuration or Data and OTP zones are unlocked!\n");
ret = -ENOTSUPP;
}
/* fall through */
free_cmd:
kfree(cmd); return ret;
}
int atmel_i2c_probe(struct i2c_client *client)
{ struct atmel_i2c_client_priv *i2c_priv; struct device *dev = &client->dev; int ret;
u32 bus_clk_rate;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(dev, "I2C_FUNC_I2C not supported\n"); return -ENODEV;
}
bus_clk_rate = i2c_acpi_find_bus_speed(&client->adapter->dev); if (!bus_clk_rate) {
ret = device_property_read_u32(&client->adapter->dev, "clock-frequency", &bus_clk_rate); if (ret) {
dev_err(dev, "failed to read clock-frequency property\n"); return ret;
}
}
if (bus_clk_rate > 1000000L) {
dev_err(dev, "%u exceeds maximum supported clock frequency (1MHz)\n",
bus_clk_rate); return -EINVAL;
}
i2c_priv = devm_kmalloc(dev, sizeof(*i2c_priv), GFP_KERNEL); if (!i2c_priv) return -ENOMEM;
/* * WAKE_TOKEN_MAX_SIZE was calculated for the maximum bus_clk_rate - * 1MHz. The previous bus_clk_rate check ensures us that wake_token_sz * will always be smaller than or equal to WAKE_TOKEN_MAX_SIZE.
*/
i2c_priv->wake_token_sz = atmel_i2c_wake_token_sz(bus_clk_rate);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.