|  | /* | 
|  | * Copyright (c) 2021 IoT.bzh | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #define DT_DRV_COMPAT renesas_rcar_i2c | 
|  |  | 
|  | #include <errno.h> | 
|  | #include <zephyr/device.h> | 
|  | #include <zephyr/devicetree.h> | 
|  | #include <soc.h> | 
|  | #include <zephyr/drivers/i2c.h> | 
|  | #include <zephyr/drivers/clock_control.h> | 
|  | #include <zephyr/drivers/clock_control/renesas_cpg_mssr.h> | 
|  |  | 
|  | #include <zephyr/logging/log.h> | 
|  | LOG_MODULE_REGISTER(i2c_rcar); | 
|  |  | 
|  | #include "i2c-priv.h" | 
|  |  | 
|  | typedef void (*init_func_t)(const struct device *dev); | 
|  |  | 
|  | struct i2c_rcar_cfg { | 
|  | uint32_t reg_addr; | 
|  | init_func_t init_func; | 
|  | const struct device *clock_dev; | 
|  | struct rcar_cpg_clk mod_clk; | 
|  | uint32_t bitrate; | 
|  | }; | 
|  |  | 
|  | struct i2c_rcar_data { | 
|  | uint8_t status_mask; | 
|  | struct k_sem int_sem; | 
|  | }; | 
|  |  | 
|  | /* Registers */ | 
|  | #define RCAR_I2C_ICSCR          0x00    /* Slave Control Register */ | 
|  | #define RCAR_I2C_ICMCR          0x04    /* Master Control Register */ | 
|  | #define RCAR_I2C_ICSIER         0x10    /* Slave IRQ Enable */ | 
|  | #define RCAR_I2C_ICMIER         0x14    /* Master IRQ Enable */ | 
|  | #define RCAR_I2C_ICSSR          0x08    /* Slave Status */ | 
|  | #define RCAR_I2C_ICMSR          0x0c    /* Master Status */ | 
|  | #define RCAR_I2C_ICCCR          0x18    /* Clock Control Register */ | 
|  | #define RCAR_I2C_ICSAR          0x1c    /* Slave Address Register */ | 
|  | #define RCAR_I2C_ICMAR          0x20    /* Master Address Register */ | 
|  | #define RCAR_I2C_ICRXD_ICTXD    0x24    /* Receive Transmit Data Register */ | 
|  | #define RCAR_I2C_ICFBSCR        0x38    /* First Bit Setup Cycle (Gen3).*/ | 
|  | #define RCAR_I2C_ICFBSCR_TCYC17 0x0f    /* 17*Tcyc */ | 
|  |  | 
|  | #define RCAR_I2C_ICMCR_MDBS     BIT(7)  /* Master Data Buffer Select */ | 
|  | #define RCAR_I2C_ICMCR_FSCL     BIT(6)  /* Forced SCL */ | 
|  | #define RCAR_I2C_ICMCR_FSDA     BIT(5)  /* Forced SDA */ | 
|  | #define RCAR_I2C_ICMCR_OBPC     BIT(4)  /* Override Bus Pin Control */ | 
|  | #define RCAR_I2C_ICMCR_MIE      BIT(3)  /* Master Interface Enable */ | 
|  | #define RCAR_I2C_ICMCR_TSBE     BIT(2)  /* Start Byte Transmission Enable */ | 
|  | #define RCAR_I2C_ICMCR_FSB      BIT(1)  /* Forced Stop onto the Bus */ | 
|  | #define RCAR_I2C_ICMCR_ESG      BIT(0)  /* Enable Start Generation */ | 
|  | #define RCAR_I2C_ICMCR_MASTER   (RCAR_I2C_ICMCR_MDBS | RCAR_I2C_ICMCR_MIE) | 
|  |  | 
|  | /* Bits to manage ICMIER and ICMSR registers */ | 
|  | #define RCAR_I2C_MNR            BIT(6)  /* Master Nack Received */ | 
|  | #define RCAR_I2C_MAL            BIT(5)  /* Master Arbitration lost */ | 
|  | #define RCAR_I2C_MST            BIT(4)  /* Master Stop Transmitted */ | 
|  | #define RCAR_I2C_MDE            BIT(3)  /* Master Data Empty */ | 
|  | #define RCAR_I2C_MDT            BIT(2)  /* Master Data Transmitted */ | 
|  | #define RCAR_I2C_MDR            BIT(1)  /* Master Data Received */ | 
|  | #define RCAR_I2C_MAT            BIT(0)  /* Master Address Transmitted */ | 
|  |  | 
|  | /* Recommended bitrate settings from official documentation */ | 
|  | #define RCAR_I2C_ICCCR_CDF_100_KHZ  6 | 
|  | #define RCAR_I2C_ICCCR_CDF_400_KHZ  6 | 
|  | #define RCAR_I2C_ICCCR_SCGD_100_KHZ 21 | 
|  | #define RCAR_I2C_ICCCR_SCGD_400_KHZ 3 | 
|  |  | 
|  | #define MAX_WAIT_US 100 | 
|  |  | 
|  | static uint32_t i2c_rcar_read(const struct i2c_rcar_cfg *config, | 
|  | uint32_t offs) | 
|  | { | 
|  | return sys_read32(config->reg_addr + offs); | 
|  | } | 
|  |  | 
|  | static void i2c_rcar_write(const struct i2c_rcar_cfg *config, | 
|  | uint32_t offs, uint32_t value) | 
|  | { | 
|  | sys_write32(value, config->reg_addr + offs); | 
|  | } | 
|  |  | 
|  | static void i2c_rcar_isr(const struct device *dev) | 
|  | { | 
|  | const struct i2c_rcar_cfg *config = dev->config; | 
|  | struct i2c_rcar_data *data = dev->data; | 
|  |  | 
|  | if (((i2c_rcar_read(config, RCAR_I2C_ICMSR)) & data->status_mask) == | 
|  | data->status_mask) { | 
|  | k_sem_give(&data->int_sem); | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMIER, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | static int i2c_rcar_wait_for_state(const struct device *dev, uint8_t mask) | 
|  | { | 
|  | const struct i2c_rcar_cfg *config = dev->config; | 
|  | struct i2c_rcar_data *data = dev->data; | 
|  |  | 
|  | data->status_mask = mask; | 
|  |  | 
|  | /* Reset interrupts semaphore */ | 
|  | k_sem_reset(&data->int_sem); | 
|  |  | 
|  | /* Enable interrupts */ | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMIER, mask); | 
|  |  | 
|  | /* Wait for the interrupts */ | 
|  | return k_sem_take(&data->int_sem, K_USEC(MAX_WAIT_US)); | 
|  | } | 
|  |  | 
|  | static int i2c_rcar_finish(const struct device *dev) | 
|  | { | 
|  | const struct i2c_rcar_cfg *config = dev->config; | 
|  | int ret; | 
|  |  | 
|  | /* Enable STOP generation */ | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMCR, RCAR_I2C_ICMCR_MASTER | RCAR_I2C_ICMCR_FSB); | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMSR, 0); | 
|  |  | 
|  | /* Wait for STOP to be transmitted */ | 
|  | ret = i2c_rcar_wait_for_state(dev, RCAR_I2C_MST); | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMSR, 0); | 
|  |  | 
|  | /* Disable STOP generation */ | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMCR, RCAR_I2C_ICMCR_MASTER); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int i2c_rcar_set_addr(const struct device *dev, | 
|  | uint8_t chip, uint8_t read) | 
|  | { | 
|  | const struct i2c_rcar_cfg *config = dev->config; | 
|  |  | 
|  | /* Set slave address & transfer mode */ | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMAR, (chip << 1) | read); | 
|  | /* Reset */ | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMCR, RCAR_I2C_ICMCR_MASTER | RCAR_I2C_ICMCR_ESG); | 
|  | /* Clear Status */ | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMSR, 0); | 
|  |  | 
|  | /* Wait for address & transfer mode to be transmitted */ | 
|  | if (read != 0) { | 
|  | return i2c_rcar_wait_for_state(dev, RCAR_I2C_MAT | RCAR_I2C_MDR); | 
|  | } else { | 
|  | return i2c_rcar_wait_for_state(dev, RCAR_I2C_MAT | RCAR_I2C_MDE); | 
|  | } | 
|  | } | 
|  |  | 
|  | static int i2c_rcar_transfer_msg(const struct device *dev, struct i2c_msg *msg) | 
|  | { | 
|  | const struct i2c_rcar_cfg *config = dev->config; | 
|  | uint32_t i, reg; | 
|  | int ret = 0; | 
|  |  | 
|  | if ((msg->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) { | 
|  | /* Reading as master */ | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMCR, RCAR_I2C_ICMCR_MASTER); | 
|  |  | 
|  | for (i = 0; i < msg->len; i++) { | 
|  | if (msg->len - 1 == i) { | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMCR, RCAR_I2C_ICMCR_MASTER | | 
|  | RCAR_I2C_ICMCR_FSB); | 
|  | } | 
|  |  | 
|  | /* Start data reception */ | 
|  | reg = i2c_rcar_read(config, RCAR_I2C_ICMSR); | 
|  | reg &= ~RCAR_I2C_MDR; | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMSR, reg); | 
|  |  | 
|  | /* Wait for data to be received */ | 
|  | ret = i2c_rcar_wait_for_state(dev, RCAR_I2C_MDR); | 
|  | if (ret != 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | msg->buf[i] = i2c_rcar_read(config, RCAR_I2C_ICRXD_ICTXD) & 0xff; | 
|  | } | 
|  | } else { | 
|  | /* Writing as master */ | 
|  | for (i = 0; i < msg->len; i++) { | 
|  | i2c_rcar_write(config, RCAR_I2C_ICRXD_ICTXD, msg->buf[i]); | 
|  |  | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMCR, RCAR_I2C_ICMCR_MASTER); | 
|  |  | 
|  | /* Start data transmission */ | 
|  | reg = i2c_rcar_read(config, RCAR_I2C_ICMSR); | 
|  | reg &= ~RCAR_I2C_MDE; | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMSR, reg); | 
|  |  | 
|  | /* Wait for all data to be transmitted */ | 
|  | ret = i2c_rcar_wait_for_state(dev, RCAR_I2C_MDE); | 
|  | if (ret != 0) { | 
|  | return ret; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int i2c_rcar_transfer(const struct device *dev, | 
|  | struct i2c_msg *msgs, uint8_t num_msgs, | 
|  | uint16_t addr) | 
|  | { | 
|  | const struct i2c_rcar_cfg *config = dev->config; | 
|  | uint16_t timeout = 0; | 
|  | int ret; | 
|  |  | 
|  | if (!num_msgs) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Wait for the bus to be available */ | 
|  | while ((i2c_rcar_read(config, RCAR_I2C_ICMCR) & RCAR_I2C_ICMCR_FSDA) && (timeout < 10)) { | 
|  | k_busy_wait(USEC_PER_MSEC); | 
|  | timeout++; | 
|  | } | 
|  | if (timeout == 10) { | 
|  | return -EIO; | 
|  | } | 
|  |  | 
|  | do { | 
|  | /* We are not supporting 10-bit addressing */ | 
|  | if ((msgs->flags & I2C_MSG_ADDR_10_BITS) == I2C_MSG_ADDR_10_BITS) { | 
|  | return -ENOTSUP; | 
|  | } | 
|  |  | 
|  | /* Send slave address */ | 
|  | if (i2c_rcar_set_addr(dev, addr, !!(msgs->flags & I2C_MSG_READ))) { | 
|  | return -EIO; /* No ACK received */ | 
|  | } | 
|  |  | 
|  | /* Transfer data */ | 
|  | if (msgs->len) { | 
|  | ret = i2c_rcar_transfer_msg(dev, msgs); | 
|  | if (ret != 0) { | 
|  | return ret; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Finish the transfer */ | 
|  | if ((msgs->flags & I2C_MSG_STOP) == I2C_MSG_STOP) { | 
|  | ret = i2c_rcar_finish(dev); | 
|  | if (ret != 0) { | 
|  | return ret; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Next message */ | 
|  | msgs++; | 
|  | num_msgs--; | 
|  | } while (num_msgs); | 
|  |  | 
|  | /* Complete without error */ | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int i2c_rcar_configure(const struct device *dev, uint32_t dev_config) | 
|  | { | 
|  | const struct i2c_rcar_cfg *config = dev->config; | 
|  | uint8_t cdf, scgd; | 
|  |  | 
|  | /* We only support Master mode */ | 
|  | if ((dev_config & I2C_MODE_CONTROLLER) != I2C_MODE_CONTROLLER) { | 
|  | return -ENOTSUP; | 
|  | } | 
|  |  | 
|  | /* We are not supporting 10-bit addressing */ | 
|  | if ((dev_config & I2C_ADDR_10_BITS) == I2C_ADDR_10_BITS) { | 
|  | return -ENOTSUP; | 
|  | } | 
|  |  | 
|  | switch (I2C_SPEED_GET(dev_config)) { | 
|  | case I2C_SPEED_STANDARD: | 
|  | /* Use recommended value for 100 kHz bus */ | 
|  | cdf = RCAR_I2C_ICCCR_CDF_100_KHZ; | 
|  | scgd = RCAR_I2C_ICCCR_SCGD_100_KHZ; | 
|  | break; | 
|  | case I2C_SPEED_FAST: | 
|  | /* Use recommended value for 400 kHz bus */ | 
|  | cdf = RCAR_I2C_ICCCR_CDF_400_KHZ; | 
|  | scgd = RCAR_I2C_ICCCR_SCGD_400_KHZ; | 
|  | break; | 
|  | default: | 
|  | return -ENOTSUP; | 
|  | } | 
|  |  | 
|  | /* Setting ICCCR to recommended value */ | 
|  | i2c_rcar_write(config, RCAR_I2C_ICCCR, (scgd << 3) | cdf); | 
|  |  | 
|  | /* Reset slave mode */ | 
|  | i2c_rcar_write(config, RCAR_I2C_ICSIER, 0); | 
|  | i2c_rcar_write(config, RCAR_I2C_ICSAR, 0); | 
|  | i2c_rcar_write(config, RCAR_I2C_ICSCR, 0); | 
|  | i2c_rcar_write(config, RCAR_I2C_ICSSR, 0); | 
|  |  | 
|  | /* Reset master mode */ | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMIER, 0); | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMCR, 0); | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMSR, 0); | 
|  | i2c_rcar_write(config, RCAR_I2C_ICMAR, 0); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int i2c_rcar_init(const struct device *dev) | 
|  | { | 
|  | const struct i2c_rcar_cfg *config = dev->config; | 
|  | struct i2c_rcar_data *data = dev->data; | 
|  | uint32_t bitrate_cfg; | 
|  | int ret; | 
|  |  | 
|  | k_sem_init(&data->int_sem, 0, 1); | 
|  |  | 
|  | ret = clock_control_on(config->clock_dev, | 
|  | (clock_control_subsys_t *)&config->mod_clk); | 
|  |  | 
|  | if (ret != 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | bitrate_cfg = i2c_map_dt_bitrate(config->bitrate); | 
|  |  | 
|  | ret = i2c_rcar_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg); | 
|  | if (ret != 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | config->init_func(dev); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static const struct i2c_driver_api i2c_rcar_driver_api = { | 
|  | .configure = i2c_rcar_configure, | 
|  | .transfer = i2c_rcar_transfer, | 
|  | }; | 
|  |  | 
|  | /* Device Instantiation */ | 
|  | #define I2C_RCAR_INIT(n)						       \ | 
|  | static void i2c_rcar_##n##_init(const struct device *dev);	       \ | 
|  | static const struct i2c_rcar_cfg i2c_rcar_cfg_##n = {		       \ | 
|  | .reg_addr = DT_INST_REG_ADDR(n),			       \ | 
|  | .init_func = i2c_rcar_##n##_init,			       \ | 
|  | .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)),	       \ | 
|  | .bitrate = DT_INST_PROP(n, clock_frequency),		       \ | 
|  | .mod_clk.module =					       \ | 
|  | DT_INST_CLOCKS_CELL_BY_IDX(n, 0, module),	       \ | 
|  | .mod_clk.domain =					       \ | 
|  | DT_INST_CLOCKS_CELL_BY_IDX(n, 0, domain),	       \ | 
|  | };								       \ | 
|  | \ | 
|  | static struct i2c_rcar_data i2c_rcar_data_##n;			       \ | 
|  | \ | 
|  | I2C_DEVICE_DT_INST_DEFINE(n,					       \ | 
|  | i2c_rcar_init,				       \ | 
|  | NULL,					       \ | 
|  | &i2c_rcar_data_##n,			       \ | 
|  | &i2c_rcar_cfg_##n,			       \ | 
|  | POST_KERNEL, CONFIG_I2C_INIT_PRIORITY,	       \ | 
|  | &i2c_rcar_driver_api			       \ | 
|  | );					       \ | 
|  | static void i2c_rcar_##n##_init(const struct device *dev)	       \ | 
|  | {								       \ | 
|  | IRQ_CONNECT(DT_INST_IRQN(n),				       \ | 
|  | 0,						       \ | 
|  | i2c_rcar_isr,				       \ | 
|  | DEVICE_DT_INST_GET(n), 0);			       \ | 
|  | \ | 
|  | irq_enable(DT_INST_IRQN(n));				       \ | 
|  | } | 
|  |  | 
|  | DT_INST_FOREACH_STATUS_OKAY(I2C_RCAR_INIT) |