18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Microchip / Atmel ECC (I2C) driver. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2017, Microchip Technology Inc. 68c2ecf20Sopenharmony_ci * Author: Tudor Ambarus <tudor.ambarus@microchip.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/bitrev.h> 108c2ecf20Sopenharmony_ci#include <linux/crc16.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <linux/err.h> 148c2ecf20Sopenharmony_ci#include <linux/errno.h> 158c2ecf20Sopenharmony_ci#include <linux/i2c.h> 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 228c2ecf20Sopenharmony_ci#include "atmel-i2c.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic const struct { 258c2ecf20Sopenharmony_ci u8 value; 268c2ecf20Sopenharmony_ci const char *error_text; 278c2ecf20Sopenharmony_ci} error_list[] = { 288c2ecf20Sopenharmony_ci { 0x01, "CheckMac or Verify miscompare" }, 298c2ecf20Sopenharmony_ci { 0x03, "Parse Error" }, 308c2ecf20Sopenharmony_ci { 0x05, "ECC Fault" }, 318c2ecf20Sopenharmony_ci { 0x0F, "Execution Error" }, 328c2ecf20Sopenharmony_ci { 0xEE, "Watchdog about to expire" }, 338c2ecf20Sopenharmony_ci { 0xFF, "CRC or other communication error" }, 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/** 378c2ecf20Sopenharmony_ci * atmel_i2c_checksum() - Generate 16-bit CRC as required by ATMEL ECC. 388c2ecf20Sopenharmony_ci * CRC16 verification of the count, opcode, param1, param2 and data bytes. 398c2ecf20Sopenharmony_ci * The checksum is saved in little-endian format in the least significant 408c2ecf20Sopenharmony_ci * two bytes of the command. CRC polynomial is 0x8005 and the initial register 418c2ecf20Sopenharmony_ci * value should be zero. 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * @cmd : structure used for communicating with the device. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_cistatic void atmel_i2c_checksum(struct atmel_i2c_cmd *cmd) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci u8 *data = &cmd->count; 488c2ecf20Sopenharmony_ci size_t len = cmd->count - CRC_SIZE; 498c2ecf20Sopenharmony_ci __le16 *__crc16 = (__le16 *)(data + len); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci *__crc16 = cpu_to_le16(bitrev16(crc16(0, data, len))); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_civoid atmel_i2c_init_read_cmd(struct atmel_i2c_cmd *cmd) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci cmd->word_addr = COMMAND; 578c2ecf20Sopenharmony_ci cmd->opcode = OPCODE_READ; 588c2ecf20Sopenharmony_ci /* 598c2ecf20Sopenharmony_ci * Read the word from Configuration zone that contains the lock bytes 608c2ecf20Sopenharmony_ci * (UserExtra, Selector, LockValue, LockConfig). 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ci cmd->param1 = CONFIG_ZONE; 638c2ecf20Sopenharmony_ci cmd->param2 = cpu_to_le16(DEVICE_LOCK_ADDR); 648c2ecf20Sopenharmony_ci cmd->count = READ_COUNT; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci atmel_i2c_checksum(cmd); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci cmd->msecs = MAX_EXEC_TIME_READ; 698c2ecf20Sopenharmony_ci cmd->rxsize = READ_RSP_SIZE; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atmel_i2c_init_read_cmd); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_civoid atmel_i2c_init_random_cmd(struct atmel_i2c_cmd *cmd) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci cmd->word_addr = COMMAND; 768c2ecf20Sopenharmony_ci cmd->opcode = OPCODE_RANDOM; 778c2ecf20Sopenharmony_ci cmd->param1 = 0; 788c2ecf20Sopenharmony_ci cmd->param2 = 0; 798c2ecf20Sopenharmony_ci cmd->count = RANDOM_COUNT; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci atmel_i2c_checksum(cmd); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci cmd->msecs = MAX_EXEC_TIME_RANDOM; 848c2ecf20Sopenharmony_ci cmd->rxsize = RANDOM_RSP_SIZE; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atmel_i2c_init_random_cmd); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_civoid atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci cmd->word_addr = COMMAND; 918c2ecf20Sopenharmony_ci cmd->count = GENKEY_COUNT; 928c2ecf20Sopenharmony_ci cmd->opcode = OPCODE_GENKEY; 938c2ecf20Sopenharmony_ci cmd->param1 = GENKEY_MODE_PRIVATE; 948c2ecf20Sopenharmony_ci /* a random private key will be generated and stored in slot keyID */ 958c2ecf20Sopenharmony_ci cmd->param2 = cpu_to_le16(keyid); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci atmel_i2c_checksum(cmd); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci cmd->msecs = MAX_EXEC_TIME_GENKEY; 1008c2ecf20Sopenharmony_ci cmd->rxsize = GENKEY_RSP_SIZE; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atmel_i2c_init_genkey_cmd); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ciint atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd, 1058c2ecf20Sopenharmony_ci struct scatterlist *pubkey) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci size_t copied; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci cmd->word_addr = COMMAND; 1108c2ecf20Sopenharmony_ci cmd->count = ECDH_COUNT; 1118c2ecf20Sopenharmony_ci cmd->opcode = OPCODE_ECDH; 1128c2ecf20Sopenharmony_ci cmd->param1 = ECDH_PREFIX_MODE; 1138c2ecf20Sopenharmony_ci /* private key slot */ 1148c2ecf20Sopenharmony_ci cmd->param2 = cpu_to_le16(DATA_SLOT_2); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* 1178c2ecf20Sopenharmony_ci * The device only supports NIST P256 ECC keys. The public key size will 1188c2ecf20Sopenharmony_ci * always be the same. Use a macro for the key size to avoid unnecessary 1198c2ecf20Sopenharmony_ci * computations. 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_ci copied = sg_copy_to_buffer(pubkey, 1228c2ecf20Sopenharmony_ci sg_nents_for_len(pubkey, 1238c2ecf20Sopenharmony_ci ATMEL_ECC_PUBKEY_SIZE), 1248c2ecf20Sopenharmony_ci cmd->data, ATMEL_ECC_PUBKEY_SIZE); 1258c2ecf20Sopenharmony_ci if (copied != ATMEL_ECC_PUBKEY_SIZE) 1268c2ecf20Sopenharmony_ci return -EINVAL; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci atmel_i2c_checksum(cmd); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci cmd->msecs = MAX_EXEC_TIME_ECDH; 1318c2ecf20Sopenharmony_ci cmd->rxsize = ECDH_RSP_SIZE; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return 0; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atmel_i2c_init_ecdh_cmd); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* 1388c2ecf20Sopenharmony_ci * After wake and after execution of a command, there will be error, status, or 1398c2ecf20Sopenharmony_ci * result bytes in the device's output register that can be retrieved by the 1408c2ecf20Sopenharmony_ci * system. When the length of that group is four bytes, the codes returned are 1418c2ecf20Sopenharmony_ci * detailed in error_list. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_cistatic int atmel_i2c_status(struct device *dev, u8 *status) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci size_t err_list_len = ARRAY_SIZE(error_list); 1468c2ecf20Sopenharmony_ci int i; 1478c2ecf20Sopenharmony_ci u8 err_id = status[1]; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (*status != STATUS_SIZE) 1508c2ecf20Sopenharmony_ci return 0; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (err_id == STATUS_WAKE_SUCCESSFUL || err_id == STATUS_NOERR) 1538c2ecf20Sopenharmony_ci return 0; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci for (i = 0; i < err_list_len; i++) 1568c2ecf20Sopenharmony_ci if (error_list[i].value == err_id) 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* if err_id is not in the error_list then ignore it */ 1608c2ecf20Sopenharmony_ci if (i != err_list_len) { 1618c2ecf20Sopenharmony_ci dev_err(dev, "%02x: %s:\n", err_id, error_list[i].error_text); 1628c2ecf20Sopenharmony_ci return err_id; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return 0; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int atmel_i2c_wakeup(struct i2c_client *client) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); 1718c2ecf20Sopenharmony_ci u8 status[STATUS_RSP_SIZE]; 1728c2ecf20Sopenharmony_ci int ret; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* 1758c2ecf20Sopenharmony_ci * The device ignores any levels or transitions on the SCL pin when the 1768c2ecf20Sopenharmony_ci * device is idle, asleep or during waking up. Don't check for error 1778c2ecf20Sopenharmony_ci * when waking up the device. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci i2c_transfer_buffer_flags(client, i2c_priv->wake_token, 1808c2ecf20Sopenharmony_ci i2c_priv->wake_token_sz, I2C_M_IGNORE_NAK); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* 1838c2ecf20Sopenharmony_ci * Wait to wake the device. Typical execution times for ecdh and genkey 1848c2ecf20Sopenharmony_ci * are around tens of milliseconds. Delta is chosen to 50 microseconds. 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_ci usleep_range(TWHI_MIN, TWHI_MAX); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci ret = i2c_master_recv(client, status, STATUS_SIZE); 1898c2ecf20Sopenharmony_ci if (ret < 0) 1908c2ecf20Sopenharmony_ci return ret; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return atmel_i2c_status(&client->dev, status); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int atmel_i2c_sleep(struct i2c_client *client) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci u8 sleep = SLEEP_TOKEN; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return i2c_master_send(client, &sleep, 1); 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/* 2038c2ecf20Sopenharmony_ci * atmel_i2c_send_receive() - send a command to the device and receive its 2048c2ecf20Sopenharmony_ci * response. 2058c2ecf20Sopenharmony_ci * @client: i2c client device 2068c2ecf20Sopenharmony_ci * @cmd : structure used to communicate with the device 2078c2ecf20Sopenharmony_ci * 2088c2ecf20Sopenharmony_ci * After the device receives a Wake token, a watchdog counter starts within the 2098c2ecf20Sopenharmony_ci * device. After the watchdog timer expires, the device enters sleep mode 2108c2ecf20Sopenharmony_ci * regardless of whether some I/O transmission or command execution is in 2118c2ecf20Sopenharmony_ci * progress. If a command is attempted when insufficient time remains prior to 2128c2ecf20Sopenharmony_ci * watchdog timer execution, the device will return the watchdog timeout error 2138c2ecf20Sopenharmony_ci * code without attempting to execute the command. There is no way to reset the 2148c2ecf20Sopenharmony_ci * counter other than to put the device into sleep or idle mode and then 2158c2ecf20Sopenharmony_ci * wake it up again. 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_ciint atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); 2208c2ecf20Sopenharmony_ci int ret; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci mutex_lock(&i2c_priv->lock); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci ret = atmel_i2c_wakeup(client); 2258c2ecf20Sopenharmony_ci if (ret) 2268c2ecf20Sopenharmony_ci goto err; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* send the command */ 2298c2ecf20Sopenharmony_ci ret = i2c_master_send(client, (u8 *)cmd, cmd->count + WORD_ADDR_SIZE); 2308c2ecf20Sopenharmony_ci if (ret < 0) 2318c2ecf20Sopenharmony_ci goto err; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* delay the appropriate amount of time for command to execute */ 2348c2ecf20Sopenharmony_ci msleep(cmd->msecs); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* receive the response */ 2378c2ecf20Sopenharmony_ci ret = i2c_master_recv(client, cmd->data, cmd->rxsize); 2388c2ecf20Sopenharmony_ci if (ret < 0) 2398c2ecf20Sopenharmony_ci goto err; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* put the device into low-power mode */ 2428c2ecf20Sopenharmony_ci ret = atmel_i2c_sleep(client); 2438c2ecf20Sopenharmony_ci if (ret < 0) 2448c2ecf20Sopenharmony_ci goto err; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci mutex_unlock(&i2c_priv->lock); 2478c2ecf20Sopenharmony_ci return atmel_i2c_status(&client->dev, cmd->data); 2488c2ecf20Sopenharmony_cierr: 2498c2ecf20Sopenharmony_ci mutex_unlock(&i2c_priv->lock); 2508c2ecf20Sopenharmony_ci return ret; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atmel_i2c_send_receive); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic void atmel_i2c_work_handler(struct work_struct *work) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct atmel_i2c_work_data *work_data = 2578c2ecf20Sopenharmony_ci container_of(work, struct atmel_i2c_work_data, work); 2588c2ecf20Sopenharmony_ci struct atmel_i2c_cmd *cmd = &work_data->cmd; 2598c2ecf20Sopenharmony_ci struct i2c_client *client = work_data->client; 2608c2ecf20Sopenharmony_ci int status; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci status = atmel_i2c_send_receive(client, cmd); 2638c2ecf20Sopenharmony_ci work_data->cbk(work_data, work_data->areq, status); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_civoid atmel_i2c_enqueue(struct atmel_i2c_work_data *work_data, 2678c2ecf20Sopenharmony_ci void (*cbk)(struct atmel_i2c_work_data *work_data, 2688c2ecf20Sopenharmony_ci void *areq, int status), 2698c2ecf20Sopenharmony_ci void *areq) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci work_data->cbk = (void *)cbk; 2728c2ecf20Sopenharmony_ci work_data->areq = areq; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci INIT_WORK(&work_data->work, atmel_i2c_work_handler); 2758c2ecf20Sopenharmony_ci schedule_work(&work_data->work); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atmel_i2c_enqueue); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic inline size_t atmel_i2c_wake_token_sz(u32 bus_clk_rate) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci u32 no_of_bits = DIV_ROUND_UP(TWLO_USEC * bus_clk_rate, USEC_PER_SEC); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* return the size of the wake_token in bytes */ 2848c2ecf20Sopenharmony_ci return DIV_ROUND_UP(no_of_bits, 8); 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic int device_sanity_check(struct i2c_client *client) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct atmel_i2c_cmd *cmd; 2908c2ecf20Sopenharmony_ci int ret; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); 2938c2ecf20Sopenharmony_ci if (!cmd) 2948c2ecf20Sopenharmony_ci return -ENOMEM; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci atmel_i2c_init_read_cmd(cmd); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci ret = atmel_i2c_send_receive(client, cmd); 2998c2ecf20Sopenharmony_ci if (ret) 3008c2ecf20Sopenharmony_ci goto free_cmd; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* 3038c2ecf20Sopenharmony_ci * It is vital that the Configuration, Data and OTP zones be locked 3048c2ecf20Sopenharmony_ci * prior to release into the field of the system containing the device. 3058c2ecf20Sopenharmony_ci * Failure to lock these zones may permit modification of any secret 3068c2ecf20Sopenharmony_ci * keys and may lead to other security problems. 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_ci if (cmd->data[LOCK_CONFIG_IDX] || cmd->data[LOCK_VALUE_IDX]) { 3098c2ecf20Sopenharmony_ci dev_err(&client->dev, "Configuration or Data and OTP zones are unlocked!\n"); 3108c2ecf20Sopenharmony_ci ret = -ENOTSUPP; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* fall through */ 3148c2ecf20Sopenharmony_cifree_cmd: 3158c2ecf20Sopenharmony_ci kfree(cmd); 3168c2ecf20Sopenharmony_ci return ret; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ciint atmel_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci struct atmel_i2c_client_priv *i2c_priv; 3228c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 3238c2ecf20Sopenharmony_ci int ret; 3248c2ecf20Sopenharmony_ci u32 bus_clk_rate; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 3278c2ecf20Sopenharmony_ci dev_err(dev, "I2C_FUNC_I2C not supported\n"); 3288c2ecf20Sopenharmony_ci return -ENODEV; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci bus_clk_rate = i2c_acpi_find_bus_speed(&client->adapter->dev); 3328c2ecf20Sopenharmony_ci if (!bus_clk_rate) { 3338c2ecf20Sopenharmony_ci ret = device_property_read_u32(&client->adapter->dev, 3348c2ecf20Sopenharmony_ci "clock-frequency", &bus_clk_rate); 3358c2ecf20Sopenharmony_ci if (ret) { 3368c2ecf20Sopenharmony_ci dev_err(dev, "failed to read clock-frequency property\n"); 3378c2ecf20Sopenharmony_ci return ret; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (bus_clk_rate > 1000000L) { 3428c2ecf20Sopenharmony_ci dev_err(dev, "%d exceeds maximum supported clock frequency (1MHz)\n", 3438c2ecf20Sopenharmony_ci bus_clk_rate); 3448c2ecf20Sopenharmony_ci return -EINVAL; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci i2c_priv = devm_kmalloc(dev, sizeof(*i2c_priv), GFP_KERNEL); 3488c2ecf20Sopenharmony_ci if (!i2c_priv) 3498c2ecf20Sopenharmony_ci return -ENOMEM; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci i2c_priv->client = client; 3528c2ecf20Sopenharmony_ci mutex_init(&i2c_priv->lock); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* 3558c2ecf20Sopenharmony_ci * WAKE_TOKEN_MAX_SIZE was calculated for the maximum bus_clk_rate - 3568c2ecf20Sopenharmony_ci * 1MHz. The previous bus_clk_rate check ensures us that wake_token_sz 3578c2ecf20Sopenharmony_ci * will always be smaller than or equal to WAKE_TOKEN_MAX_SIZE. 3588c2ecf20Sopenharmony_ci */ 3598c2ecf20Sopenharmony_ci i2c_priv->wake_token_sz = atmel_i2c_wake_token_sz(bus_clk_rate); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci memset(i2c_priv->wake_token, 0, sizeof(i2c_priv->wake_token)); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci atomic_set(&i2c_priv->tfm_count, 0); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci i2c_set_clientdata(client, i2c_priv); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci ret = device_sanity_check(client); 3688c2ecf20Sopenharmony_ci if (ret) 3698c2ecf20Sopenharmony_ci return ret; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci return 0; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atmel_i2c_probe); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ciMODULE_AUTHOR("Tudor Ambarus <tudor.ambarus@microchip.com>"); 3768c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Microchip / Atmel ECC (I2C) driver"); 3778c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 378