27 #include "../switchtec_priv.h"
33 #include <sys/types.h>
35 #include <sys/ioctl.h>
37 #include <sys/sysmacros.h>
46 #include <linux/i2c.h>
47 #include <linux/i2c-dev.h>
50 struct switchtec_dev dev;
56 #define CMD_GET_CAP 0xE0
57 #define CMD_GAS_WRITE 0xEA
58 #define CMD_GET_WRITE_STATUS 0xE2
59 #define CMD_GAS_WRITE_WITH_STATUS 0xE8
60 #define CMD_GAS_READ 0xE9
62 #define MAX_RETRY_COUNT 100
63 #define MAX_STATUS_GET_RETRY 50
64 #define PEC_BYTE_COUNT 1
65 #define TWI_ENHANCED_MODE 0x80
66 #define GAS_TWI_MRPC_ERR 0x20
67 #define DATA_TAIL_BYTE_COUNT 2
69 #define to_switchtec_i2c(d) \
70 ((struct switchtec_i2c *) \
71 ((char *)d - offsetof(struct switchtec_i2c, dev)))
82 static uint8_t i2c_msg_pec(
struct i2c_msg *msg, uint8_t byte_count,
83 uint8_t oldchksum,
bool init)
86 uint8_t addr = (msg->addr << 1) | msg->flags;
87 uint8_t pec = crc8(&addr, 1, oldchksum, init);
88 return crc8(msg->buf, byte_count, pec,
false);
91 static int dev_to_sysfs_path(
struct switchtec_i2c *idev,
const char *suffix,
92 char *buf,
size_t buflen)
97 ret = fstat(idev->fd, &stat);
101 snprintf(buf, buflen,
102 "/sys/dev/char/%d:%d/%s",
103 major(stat.st_rdev), minor(stat.st_rdev), suffix);
108 static int check_i2c_device_supported(
struct switchtec_i2c *idev)
113 ret = ioctl(idev->fd, I2C_FUNCS, &funcs);
117 if (!(funcs & I2C_FUNC_I2C)) {
128 char syspath[PATH_MAX];
130 ret = dev_to_sysfs_path(idev,
"device/i2c-dev", syspath,
135 ret = access(syspath, F_OK);
139 return check_i2c_device_supported(idev);
142 static int i2c_set_addr(
struct switchtec_i2c *idev,
int i2c_addr)
144 idev->i2c_addr = i2c_addr;
146 return ioctl(idev->fd, I2C_SLAVE, i2c_addr);
149 static int i2c_set_timeout(
struct switchtec_i2c *idev,
int time)
151 return ioctl(idev->fd, I2C_TIMEOUT, time);
155 #define __force __attribute__((force))
160 static void i2c_close(
struct switchtec_dev *dev)
165 munmap((
void __force *)dev->gas_map, dev->gas_map_size);
171 static int map_gas(
struct switchtec_dev *dev)
174 dev->gas_map_size = 4 << 20;
185 addr = mmap(NULL, dev->gas_map_size, PROT_NONE,
186 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
187 if (addr == MAP_FAILED)
190 dev->gas_map = (
gasptr_t __force)addr;
197 static gasptr_t i2c_gas_map(
struct switchtec_dev *dev,
int writeable,
201 *map_size = dev->gas_map_size;
206 static uint8_t i2c_gas_cap_get(
struct switchtec_dev *dev)
211 struct i2c_msg msgs[2];
212 struct i2c_rdwr_ioctl_data rwdata = {
217 uint8_t command_code = CMD_GET_CAP;
219 uint8_t msg_0_pec, pec;
220 uint8_t retry_count = 0;
222 msgs[0].addr = msgs[1].addr = idev->i2c_addr;
225 msgs[0].buf = &command_code;
227 msgs[1].flags = I2C_M_RD;
229 msgs[1].buf = rx_buf;
232 ret = ioctl(idev->fd, I2C_RDWR, &rwdata);
236 msg_0_pec = i2c_msg_pec(&msgs[0], msgs[0].len, 0,
true);
237 pec = i2c_msg_pec(&msgs[1], msgs[1].len - PEC_BYTE_COUNT,
239 if (rx_buf[1] == pec)
243 }
while(retry_count < MAX_RETRY_COUNT);
246 if (retry_count == MAX_RETRY_COUNT)
249 return (rx_buf[0] & TWI_ENHANCED_MODE);
259 #define I2C_MAX_WRITE 24
264 #define I2C_MAX_READ 24
266 static uint8_t i2c_gas_data_write(
struct switchtec_dev *dev,
void __gas *dest,
267 const void *src,
size_t n, uint8_t tag)
273 struct i2c_rdwr_ioctl_data wdata = {
279 uint8_t command_code;
284 } __attribute__((packed)) *i2c_data;
286 uint32_t gas_addr = (uint32_t)(dest - (
void __gas *)dev->gas_map);
287 assert(n <= I2C_MAX_WRITE);
290 i2c_data = malloc(
sizeof(*i2c_data) + n + PEC_BYTE_COUNT);
292 i2c_data->command_code = CMD_GAS_WRITE;
293 i2c_data->byte_count = (
sizeof(i2c_data->tag)
294 +
sizeof(i2c_data->offset)
298 gas_addr = htobe32(gas_addr);
299 i2c_data->offset = gas_addr;
300 memcpy(&i2c_data->data, src, n);
301 msg.addr = idev->i2c_addr;
303 msg.len =
sizeof(*i2c_data) + n + PEC_BYTE_COUNT;
304 msg.buf = (uint8_t *)i2c_data;
306 i2c_data->data[n] = i2c_msg_pec(&msg, msg.len - PEC_BYTE_COUNT, 0,
309 ret = ioctl(idev->fd, I2C_RDWR, &wdata);
321 static uint8_t i2c_gas_write_status_get(
struct switchtec_dev *dev,
326 struct i2c_msg msgs[2];
327 struct i2c_rdwr_ioctl_data rwdata = {
332 uint8_t command_code = CMD_GET_WRITE_STATUS;
335 uint8_t msg_0_pec, pec;
336 uint8_t retry_count = 0;
338 msgs[0].addr = msgs[1].addr = idev->i2c_addr;
341 msgs[0].buf = &command_code;
343 msgs[1].flags = I2C_M_RD;
345 msgs[1].buf = rx_buf;
348 ret = ioctl(idev->fd, I2C_RDWR, &rwdata);
356 msg_0_pec = i2c_msg_pec(&msgs[0], msgs[0].len, 0,
true);
357 pec = i2c_msg_pec(&msgs[1], msgs[1].len - PEC_BYTE_COUNT,
359 if (rx_buf[0] == tag && rx_buf[2] == pec &&
360 (rx_buf[1] == 0 || rx_buf[1] == GAS_TWI_MRPC_ERR))
366 }
while(retry_count < MAX_STATUS_GET_RETRY);
371 static void i2c_gas_write(
struct switchtec_dev *dev,
void __gas *dest,
372 const void *src,
size_t n)
377 uint8_t retry_count = 0;
381 i2c_gas_data_write(dev, dest, src, n, tag);
382 status = i2c_gas_write_status_get(dev, tag);
383 if (status == 0 || status == GAS_TWI_MRPC_ERR)
389 }
while (retry_count < MAX_RETRY_COUNT);
391 if (retry_count == MAX_RETRY_COUNT)
395 static void i2c_gas_write_no_retry(
struct switchtec_dev *dev,
void __gas *dest,
396 const void *src,
size_t n)
401 uint8_t retry_count = 0;
404 i2c_gas_data_write(dev, dest, src, n, tag);
406 status = i2c_gas_write_status_get(dev, tag);
407 if (status == 0 || status == GAS_TWI_MRPC_ERR)
413 }
while (retry_count < MAX_RETRY_COUNT);
418 static void i2c_memcpy_to_gas(
struct switchtec_dev *dev,
void __gas *dest,
419 const void *src,
size_t n)
424 cnt = n > I2C_MAX_WRITE ? I2C_MAX_WRITE : n;
425 i2c_gas_write(dev, dest, src, cnt);
433 static uint8_t i2c_gas_data_read(
struct switchtec_dev *dev,
void *dest,
434 const void __gas *src,
size_t n)
437 int pec_index, status_index;
438 uint8_t msg_0_pec, pec;
439 uint8_t retry_count = 0;
442 uint32_t gas_addr = (uint32_t)(src - (
void __gas *)dev->gas_map);
445 struct i2c_msg msgs[2];
446 struct i2c_rdwr_ioctl_data rwdata = {
452 uint8_t command_code;
456 } __attribute__((packed)) *read_command;
461 uint8_t data_and_tail[];
464 read_command = malloc(
sizeof(*read_command));
465 read_response = malloc(
sizeof(*read_response) + n \
466 + DATA_TAIL_BYTE_COUNT);
468 msgs[0].addr = msgs[1].addr = idev->i2c_addr;
470 msgs[0].len =
sizeof(*read_command);
472 read_command->command_code = CMD_GAS_READ;
473 read_command->byte_count =
sizeof(read_command->offset) \
474 +
sizeof(read_command->data_length);
475 gas_addr = htobe32(gas_addr);
476 read_command->offset = gas_addr;
477 read_command->data_length = n;
478 msgs[0].buf = (uint8_t *)read_command;
480 msgs[1].flags = I2C_M_RD;
481 msgs[1].len =
sizeof(read_response->byte_count) + n + \
482 DATA_TAIL_BYTE_COUNT;
483 msgs[1].buf = (uint8_t *)read_response;
486 ret = ioctl(idev->fd, I2C_RDWR, &rwdata);
490 msg_0_pec = i2c_msg_pec(&msgs[0], msgs[0].len, 0,
true);
491 pec = i2c_msg_pec(&msgs[1], msgs[1].len - PEC_BYTE_COUNT, \
493 pec_index = msgs[1].len -
sizeof(read_response->byte_count) \
495 if (read_response->data_and_tail[ pec_index ] == pec)
499 }
while(retry_count < MAX_RETRY_COUNT);
501 if (retry_count == MAX_RETRY_COUNT)
504 memcpy(dest, read_response->data_and_tail, n);
505 status_index = msgs[1].len -
sizeof(read_response->byte_count) \
506 - DATA_TAIL_BYTE_COUNT;
507 status = read_response->data_and_tail[ status_index ];
519 static void i2c_gas_read(
struct switchtec_dev *dev,
void *dest,
520 const void __gas *src,
size_t n)
523 uint8_t retry_count = 0;
526 status = i2c_gas_data_read(dev, dest, src, n);
527 if (status == 0 || status == GAS_TWI_MRPC_ERR)
530 }
while(retry_count < MAX_RETRY_COUNT);
532 if (retry_count == MAX_RETRY_COUNT)
536 static void i2c_memcpy_from_gas(
struct switchtec_dev *dev,
void *dest,
537 const void __gas *src,
size_t n)
542 cnt = n > I2C_MAX_READ ? I2C_MAX_READ : n;
543 i2c_gas_read(dev, dest, src, cnt);
551 static ssize_t i2c_write_from_gas(
struct switchtec_dev *dev,
int fd,
552 const void __gas *src,
size_t n)
559 i2c_memcpy_from_gas(dev, buf, src, n);
561 ret = write(fd, buf, n);
569 static inline uint8_t le8toh(uint8_t x) {
return x; }
571 #define create_gas_read(type, suffix) \
572 static type i2c_gas_read ## suffix(struct switchtec_dev *dev, \
576 i2c_memcpy_from_gas(dev, &ret, addr, sizeof(ret)); \
577 return le##suffix##toh(ret); \
580 create_gas_read(uint8_t, 8);
581 create_gas_read(uint16_t, 16);
582 create_gas_read(uint32_t, 32);
583 create_gas_read(uint64_t, 64);
585 static void i2c_gas_write8(
struct switchtec_dev *dev, uint8_t val,
588 i2c_gas_write(dev, addr, &val,
sizeof(uint8_t));
591 static void i2c_gas_write16(
struct switchtec_dev *dev, uint16_t val,
592 uint16_t __gas *addr)
595 i2c_gas_write(dev, addr, &val,
sizeof(uint16_t));
598 static void i2c_gas_write32(
struct switchtec_dev *dev, uint32_t val,
599 uint32_t __gas *addr)
602 i2c_gas_write(dev, addr, &val,
sizeof(uint32_t));
605 static void i2c_gas_write32_no_retry(
struct switchtec_dev *dev, uint32_t val,
606 uint32_t __gas *addr)
609 i2c_gas_write_no_retry(dev, addr, &val,
sizeof(uint32_t));
612 static void i2c_gas_write64(
struct switchtec_dev *dev, uint64_t val,
613 uint64_t __gas *addr)
616 i2c_gas_write(dev, addr, &val,
sizeof(uint64_t));
619 static const struct switchtec_ops i2c_ops = {
621 .gas_map = i2c_gas_map,
624 .get_device_id = gasop_get_device_id,
625 .get_fw_version = gasop_get_fw_version,
626 .pff_to_port = gasop_pff_to_port,
627 .port_to_pff = gasop_port_to_pff,
628 .flash_part = gasop_flash_part,
629 .event_summary = gasop_event_summary,
630 .event_ctl = gasop_event_ctl,
631 .event_wait_for = gasop_event_wait_for,
633 .gas_read8 = i2c_gas_read8,
634 .gas_read16 = i2c_gas_read16,
635 .gas_read32 = i2c_gas_read32,
636 .gas_read64 = i2c_gas_read64,
637 .gas_write8 = i2c_gas_write8,
638 .gas_write16 = i2c_gas_write16,
639 .gas_write32 = i2c_gas_write32,
640 .gas_write32_no_retry = i2c_gas_write32_no_retry,
641 .gas_write64 = i2c_gas_write64,
642 .memcpy_to_gas = i2c_memcpy_to_gas,
643 .memcpy_from_gas = i2c_memcpy_from_gas,
644 .write_from_gas = i2c_write_from_gas,
651 idev = malloc(
sizeof(*idev));
655 idev->fd = open(path, O_RDWR | O_CLOEXEC);
659 if (check_i2c_device(idev))
662 if (i2c_set_addr(idev, i2c_addr))
665 if (i2c_set_timeout(idev, 10))
668 if (i2c_gas_cap_get(&idev->dev) != TWI_ENHANCED_MODE)
671 if (map_gas(&idev->dev))
674 idev->dev.ops = &i2c_ops;
676 gasop_set_partition_info(&idev->dev);
687 struct switchtec_dev *switchtec_open_i2c_by_adapter(
int adapter,
int i2c_addr)
691 sprintf(path,
"/dev/i2c-%d", adapter);