i2c-dln2.c (6165B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Driver for the Diolan DLN-2 USB-I2C adapter 4 * 5 * Copyright (c) 2014 Intel Corporation 6 * 7 * Derived from: 8 * i2c-diolan-u2c.c 9 * Copyright (c) 2010-2011 Ericsson AB 10 */ 11 12#include <linux/kernel.h> 13#include <linux/module.h> 14#include <linux/types.h> 15#include <linux/slab.h> 16#include <linux/i2c.h> 17#include <linux/platform_device.h> 18#include <linux/mfd/dln2.h> 19#include <linux/acpi.h> 20 21#define DLN2_I2C_MODULE_ID 0x03 22#define DLN2_I2C_CMD(cmd) DLN2_CMD(cmd, DLN2_I2C_MODULE_ID) 23 24/* I2C commands */ 25#define DLN2_I2C_GET_PORT_COUNT DLN2_I2C_CMD(0x00) 26#define DLN2_I2C_ENABLE DLN2_I2C_CMD(0x01) 27#define DLN2_I2C_DISABLE DLN2_I2C_CMD(0x02) 28#define DLN2_I2C_IS_ENABLED DLN2_I2C_CMD(0x03) 29#define DLN2_I2C_WRITE DLN2_I2C_CMD(0x06) 30#define DLN2_I2C_READ DLN2_I2C_CMD(0x07) 31#define DLN2_I2C_SCAN_DEVICES DLN2_I2C_CMD(0x08) 32#define DLN2_I2C_PULLUP_ENABLE DLN2_I2C_CMD(0x09) 33#define DLN2_I2C_PULLUP_DISABLE DLN2_I2C_CMD(0x0A) 34#define DLN2_I2C_PULLUP_IS_ENABLED DLN2_I2C_CMD(0x0B) 35#define DLN2_I2C_TRANSFER DLN2_I2C_CMD(0x0C) 36#define DLN2_I2C_SET_MAX_REPLY_COUNT DLN2_I2C_CMD(0x0D) 37#define DLN2_I2C_GET_MAX_REPLY_COUNT DLN2_I2C_CMD(0x0E) 38 39#define DLN2_I2C_MAX_XFER_SIZE 256 40#define DLN2_I2C_BUF_SIZE (DLN2_I2C_MAX_XFER_SIZE + 16) 41 42struct dln2_i2c { 43 struct platform_device *pdev; 44 struct i2c_adapter adapter; 45 u8 port; 46 /* 47 * Buffer to hold the packet for read or write transfers. One is enough 48 * since we can't have multiple transfers in parallel on the i2c bus. 49 */ 50 void *buf; 51}; 52 53static int dln2_i2c_enable(struct dln2_i2c *dln2, bool enable) 54{ 55 u16 cmd; 56 struct { 57 u8 port; 58 } tx; 59 60 tx.port = dln2->port; 61 62 if (enable) 63 cmd = DLN2_I2C_ENABLE; 64 else 65 cmd = DLN2_I2C_DISABLE; 66 67 return dln2_transfer_tx(dln2->pdev, cmd, &tx, sizeof(tx)); 68} 69 70static int dln2_i2c_write(struct dln2_i2c *dln2, u8 addr, 71 u8 *data, u16 data_len) 72{ 73 int ret; 74 struct { 75 u8 port; 76 u8 addr; 77 u8 mem_addr_len; 78 __le32 mem_addr; 79 __le16 buf_len; 80 u8 buf[DLN2_I2C_MAX_XFER_SIZE]; 81 } __packed *tx = dln2->buf; 82 unsigned len; 83 84 BUILD_BUG_ON(sizeof(*tx) > DLN2_I2C_BUF_SIZE); 85 86 tx->port = dln2->port; 87 tx->addr = addr; 88 tx->mem_addr_len = 0; 89 tx->mem_addr = 0; 90 tx->buf_len = cpu_to_le16(data_len); 91 memcpy(tx->buf, data, data_len); 92 93 len = sizeof(*tx) + data_len - DLN2_I2C_MAX_XFER_SIZE; 94 ret = dln2_transfer_tx(dln2->pdev, DLN2_I2C_WRITE, tx, len); 95 if (ret < 0) 96 return ret; 97 98 return data_len; 99} 100 101static int dln2_i2c_read(struct dln2_i2c *dln2, u16 addr, u8 *data, 102 u16 data_len) 103{ 104 int ret; 105 struct { 106 u8 port; 107 u8 addr; 108 u8 mem_addr_len; 109 __le32 mem_addr; 110 __le16 buf_len; 111 } __packed tx; 112 struct { 113 __le16 buf_len; 114 u8 buf[DLN2_I2C_MAX_XFER_SIZE]; 115 } __packed *rx = dln2->buf; 116 unsigned rx_len = sizeof(*rx); 117 118 BUILD_BUG_ON(sizeof(*rx) > DLN2_I2C_BUF_SIZE); 119 120 tx.port = dln2->port; 121 tx.addr = addr; 122 tx.mem_addr_len = 0; 123 tx.mem_addr = 0; 124 tx.buf_len = cpu_to_le16(data_len); 125 126 ret = dln2_transfer(dln2->pdev, DLN2_I2C_READ, &tx, sizeof(tx), 127 rx, &rx_len); 128 if (ret < 0) 129 return ret; 130 if (rx_len < sizeof(rx->buf_len) + data_len) 131 return -EPROTO; 132 if (le16_to_cpu(rx->buf_len) != data_len) 133 return -EPROTO; 134 135 memcpy(data, rx->buf, data_len); 136 137 return data_len; 138} 139 140static int dln2_i2c_xfer(struct i2c_adapter *adapter, 141 struct i2c_msg *msgs, int num) 142{ 143 struct dln2_i2c *dln2 = i2c_get_adapdata(adapter); 144 struct i2c_msg *pmsg; 145 int i; 146 147 for (i = 0; i < num; i++) { 148 int ret; 149 150 pmsg = &msgs[i]; 151 152 if (pmsg->flags & I2C_M_RD) { 153 ret = dln2_i2c_read(dln2, pmsg->addr, pmsg->buf, 154 pmsg->len); 155 if (ret < 0) 156 return ret; 157 158 pmsg->len = ret; 159 } else { 160 ret = dln2_i2c_write(dln2, pmsg->addr, pmsg->buf, 161 pmsg->len); 162 if (ret != pmsg->len) 163 return -EPROTO; 164 } 165 } 166 167 return num; 168} 169 170static u32 dln2_i2c_func(struct i2c_adapter *a) 171{ 172 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | 173 I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | 174 I2C_FUNC_SMBUS_I2C_BLOCK; 175} 176 177static const struct i2c_algorithm dln2_i2c_usb_algorithm = { 178 .master_xfer = dln2_i2c_xfer, 179 .functionality = dln2_i2c_func, 180}; 181 182static const struct i2c_adapter_quirks dln2_i2c_quirks = { 183 .max_read_len = DLN2_I2C_MAX_XFER_SIZE, 184 .max_write_len = DLN2_I2C_MAX_XFER_SIZE, 185}; 186 187static int dln2_i2c_probe(struct platform_device *pdev) 188{ 189 int ret; 190 struct dln2_i2c *dln2; 191 struct device *dev = &pdev->dev; 192 struct dln2_platform_data *pdata = dev_get_platdata(&pdev->dev); 193 194 dln2 = devm_kzalloc(dev, sizeof(*dln2), GFP_KERNEL); 195 if (!dln2) 196 return -ENOMEM; 197 198 dln2->buf = devm_kmalloc(dev, DLN2_I2C_BUF_SIZE, GFP_KERNEL); 199 if (!dln2->buf) 200 return -ENOMEM; 201 202 dln2->pdev = pdev; 203 dln2->port = pdata->port; 204 205 /* setup i2c adapter description */ 206 dln2->adapter.owner = THIS_MODULE; 207 dln2->adapter.class = I2C_CLASS_HWMON; 208 dln2->adapter.algo = &dln2_i2c_usb_algorithm; 209 dln2->adapter.quirks = &dln2_i2c_quirks; 210 dln2->adapter.dev.parent = dev; 211 ACPI_COMPANION_SET(&dln2->adapter.dev, ACPI_COMPANION(&pdev->dev)); 212 dln2->adapter.dev.of_node = dev->of_node; 213 i2c_set_adapdata(&dln2->adapter, dln2); 214 snprintf(dln2->adapter.name, sizeof(dln2->adapter.name), "%s-%s-%d", 215 "dln2-i2c", dev_name(pdev->dev.parent), dln2->port); 216 217 platform_set_drvdata(pdev, dln2); 218 219 /* initialize the i2c interface */ 220 ret = dln2_i2c_enable(dln2, true); 221 if (ret < 0) { 222 dev_err(dev, "failed to initialize adapter: %d\n", ret); 223 return ret; 224 } 225 226 /* and finally attach to i2c layer */ 227 ret = i2c_add_adapter(&dln2->adapter); 228 if (ret < 0) 229 goto out_disable; 230 231 return 0; 232 233out_disable: 234 dln2_i2c_enable(dln2, false); 235 236 return ret; 237} 238 239static int dln2_i2c_remove(struct platform_device *pdev) 240{ 241 struct dln2_i2c *dln2 = platform_get_drvdata(pdev); 242 243 i2c_del_adapter(&dln2->adapter); 244 dln2_i2c_enable(dln2, false); 245 246 return 0; 247} 248 249static struct platform_driver dln2_i2c_driver = { 250 .driver.name = "dln2-i2c", 251 .probe = dln2_i2c_probe, 252 .remove = dln2_i2c_remove, 253}; 254 255module_platform_driver(dln2_i2c_driver); 256 257MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>"); 258MODULE_DESCRIPTION("Driver for the Diolan DLN2 I2C master interface"); 259MODULE_LICENSE("GPL v2"); 260MODULE_ALIAS("platform:dln2-i2c");