// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include "i2c-slave.h" #define CREATE_TRACE_POINTS #include /** * i2c_slave_trace_log: FTRACE Logging. * @dev: Driver model device node for the i2c slave. * @fmt: ftrace log format. * * This function will add logs to ftrace * file. * * Return: None. */ void i2c_slave_trace_log(struct device *dev, const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, }; va_list args; va_start(args, fmt); vaf.va = &args; trace_i2c_slave_log_info(dev_name(dev), &vaf); va_end(args); } /** * dump_register - To dump the register value. * @i2c_slave: Pointer to Main Structure. * * This function will dump the all readable register * value to IPC log. * * Return: None. */ static void dump_register(struct i2c_slave *i2c_slave) { unsigned int temp; temp = readl_relaxed(i2c_slave->base + I2C_S_DEVICE_ADDR); I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "I2C_S_DEVICE_ADDR: 0x%x\n", temp); temp = readl_relaxed(i2c_slave->base + I2C_S_IRQ_STATUS); I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "I2C_S_IRQ_STATUS: 0x%x\n", temp); temp = readl_relaxed(i2c_slave->base + I2C_S_CONFIG); I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "I2C_S_CONFIG: 0x%x\n", temp); temp = readl_relaxed(i2c_slave->base + I2C_S_IRQ_EN); I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "I2C_S_IRQ_EN: 0x%x\n", temp); temp = readl_relaxed(i2c_slave->base + I2C_S_FIFOS_STATUS); I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "I2C_S_FIFOS_STATUS: 0x%x\n", temp); temp = readl_relaxed(i2c_slave->base + I2C_S_DEBUG_REG1); I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "I2C_S_DEBUG_REG1: 0x%x\n", temp); temp = readl_relaxed(i2c_slave->base + I2C_S_DEBUG_REG2); I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "I2C_S_DEBUG_REG2: 0x%x\n", temp); temp = readl_relaxed(i2c_slave->base + I2C_S_CLK_LOW_TIMEOUT); I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "I2C_S_CLK_LOW_TIMEOUT: 0x%x\n", temp); temp = readl_relaxed(i2c_slave->base + I2C_S_CLK_RELEASE_DELAY_CNT_VAL); I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "I2C_S_CLK_RELEASE_DELAY_CNT_VAL: 0x%x\n", temp); temp = readl_relaxed(i2c_slave->base + I2C_S_SDA_HOLD_CNT_VAL); I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "I2C_S_SDA_HOLD_CNT_VAL: 0x%x\n", temp); temp = readl_relaxed(i2c_slave->base + SMBALERT_STATUS_REG); I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "SMBALERT_STATUS_REG: 0x%x\n", temp); temp = readl_relaxed(i2c_slave->base + SMBALERT_PEC_REG); I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "SMBALERT_PEC_REG: 0x%x\n", temp); } /** * read_tx_fifo_byte_count: To read TX FIFO count. * @i2c_slave: Pointer to Main Structure. * * This function will read the number of bytes written * to the TX FIFO. * * Return: Number of bytes written to the TX FIFO. */ static unsigned int read_tx_fifo_byte_count(struct i2c_slave *i2c_slave) { unsigned int count = 0; count = readl_relaxed(i2c_slave->base + I2C_S_FIFOS_STATUS); return (count & 0xFFFF); } /** * read_rx_fifo_byte_count: To read RX FIFO count. * @i2c_slave: Pointer to Main Structure. * * This function will read the number of bytes written * to the RX FIFO. * * Return: Number of bytes written to the RX FIFO. */ static unsigned int read_rx_fifo_byte_count(struct i2c_slave *i2c_slave) { unsigned int count = 0; count = readl_relaxed(i2c_slave->base + I2C_S_FIFOS_STATUS); return ((count & 0xFFFF0000) >> 16); } /** * i2c_slave_write_fifo: This function will write data to TX FIFO. * @i2c_slave: Pointer to Main Structure. * * This function will write data to TX FIFO. * * Return: None. */ static void i2c_slave_write_fifo(struct i2c_slave *i2c_slave) { int i; if (i2c_slave->tx_count == 0) { I2C_SLAVE_ERR(i2c_slave->ipcl, false, i2c_slave->dev, "TX FIFO write count is zero\n"); return; } for (i = 0; i < i2c_slave->tx_count; i++) { I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "Data to Tx FIFO: 0x%x\n", i2c_slave->tx_msg_buf[i]); writel_relaxed(i2c_slave->tx_msg_buf[i], i2c_slave->base + I2C_S_TX_FIFO); } i2c_slave->tx_count = 0; } /** * i2c_slave_read_fifo: This function will read data to RX FIFO. * @i2c_slave: Pointer to Main Structure. * * This function will read data to RX FIFO. * * Return: None. */ static void i2c_slave_read_fifo(struct i2c_slave *i2c_slave) { unsigned int rx_data_count; int i; rx_data_count = read_rx_fifo_byte_count(i2c_slave); if (rx_data_count == 0) { I2C_SLAVE_ERR(i2c_slave->ipcl, false, i2c_slave->dev, "RX FIFO empty\n"); } else if (i2c_slave->rx_count >= I2C_SLAVE_MAX_MSG_SIZE) { I2C_SLAVE_ERR(i2c_slave->ipcl, false, i2c_slave->dev, "RX data buffer full\n"); } else { for (i = 0; i < rx_data_count && i2c_slave->rx_count < I2C_SLAVE_MAX_MSG_SIZE; i++) { i2c_slave->rx_msg_buf[i2c_slave->rx_count] = readl_relaxed(i2c_slave->base + I2C_S_RX_FIFO); I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "Data from RX_FIFO: 0x%x", i2c_slave->rx_msg_buf[i2c_slave->rx_count]); i2c_slave->rx_count++; } wake_up_interruptible(&i2c_slave->readq); } } /** * i2c_slave_write_bit: To SET the register bit. * @i2c_slave: Pointer to Main Structure. * @reg: offset of Register address. * @bit: bit to modify. * * This function will set the bit to given register. * * Return: None. */ static void i2c_slave_write_bit(struct i2c_slave *i2c_slave, int reg, int bit) { unsigned int temp; temp = readl_relaxed(i2c_slave->base + reg) | bit; writel_relaxed(temp, i2c_slave->base + reg); } /** * i2c_slave_send_ack: To send ACK to master. * @i2c_slave: Pointer to Main Structure. * * This function will send ACK to master. * * Return: None. */ static void i2c_slave_send_ack(struct i2c_slave *i2c_slave) { writel_relaxed(ACK_RESUME, i2c_slave->base + I2C_S_CONTROL); } /** * i2c_slave_send_nack: To send NACK to master. * @i2c_slave: Pointer to Main Structure. * * This function will send NACK to master. * * Return: None. */ static void i2c_slave_send_nack(struct i2c_slave *i2c_slave) { writel_relaxed(NACK, i2c_slave->base + I2C_S_CONTROL); } /** * i2c_slave_clear_irq: To clear IRQ bit * @i2c_slave: Pointer to Main Structure. * enum: enum to IRQ bit * * This function will clear the handled IRQ bit. * * Return: None. */ static void i2c_slave_clear_irq(struct i2c_slave *i2c_slave, enum i2c_slave_irq_status bit) { if (bit == ALL_IRQ) writel_relaxed(ALL_IRQ, i2c_slave->base + I2C_S_IRQ_CLR); else writel_relaxed(1 << bit, i2c_slave->base + I2C_S_IRQ_CLR); } /** * i2c_slave_enable_irq: To enable IRQ. * @i2c_slave: Pointer to Main Structure. * * This function will enable the IRQ. * * Return: None. */ static void i2c_slave_enable_irq(struct i2c_slave *i2c_slave) { writel_relaxed(ALL_IRQ, i2c_slave->base + I2C_S_IRQ_EN); } /** * i2c_slave_irq: I2C Slave IQR handler * @irq: IRQ number * @dev: Pointer to Dev Structure. * * This function will handle IRQ bits. * * return: IRQ_HANDLED for success. */ static irqreturn_t i2c_slave_irq(int irq, void *dev) { unsigned int irq_stat; struct i2c_slave *i2c_slave = dev; irq_stat = readl_relaxed(i2c_slave->base + I2C_S_IRQ_STATUS); I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "irq status: 0x%x\n", irq_stat); if (irq_stat & (1 << ERR_CONDITION)) { I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "%s\n", irq_log[ERR_CONDITION]); dump_register(i2c_slave); i2c_slave_write_bit(i2c_slave, I2C_S_SW_RESET_REG, SW_RESET); i2c_slave_clear_irq(i2c_slave, ALL_IRQ); i2c_slave_enable_irq(i2c_slave); i2c_slave_write_bit(i2c_slave, I2C_S_CONTROL, CLEAR_TX_FIFO | CLEAR_RX_FIFO); i2c_slave_write_bit(i2c_slave, I2C_S_CLK_LOW_TIMEOUT, TIMER_MODE); i2c_slave_write_bit(i2c_slave, I2C_S_CONFIG, CORE_EN); i2c_slave_send_nack(i2c_slave); } if (irq_stat & (1 << CLOCK_LOW_TIMEOUT)) { I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "%s\n", irq_log[CLOCK_LOW_TIMEOUT]); i2c_slave_clear_irq(i2c_slave, ALL_IRQ); } if (irq_stat & (1 << STOP_DETECTED)) { I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "%s\n", irq_log[STOP_DETECTED]); i2c_slave_clear_irq(i2c_slave, STOP_DETECTED); i2c_slave_read_fifo(i2c_slave); } if (irq_stat & (1 << RX_FIFO_FULL)) { I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "%s\n", irq_log[RX_FIFO_FULL]); i2c_slave_send_nack(i2c_slave); i2c_slave_clear_irq(i2c_slave, RX_FIFO_FULL); } if (irq_stat & (1 << STRCH_RD)) { I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "%s\n", irq_log[STRCH_RD]); i2c_slave->tx_count = read_tx_fifo_byte_count(i2c_slave); if (i2c_slave->tx_count > 0) { i2c_slave_send_ack(i2c_slave); } else { I2C_SLAVE_ERR(i2c_slave->ipcl, false, i2c_slave->dev, "TX FIFO empty\n"); i2c_slave_send_nack(i2c_slave); } i2c_slave_clear_irq(i2c_slave, STRCH_RD); } if (irq_stat & (1 << RX_DATA_AVAIL)) { I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "%s\n", irq_log[RX_DATA_AVAIL]); i2c_slave_clear_irq(i2c_slave, RX_DATA_AVAIL); } if (irq_stat & (1 << STRCH_WR)) { I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "%s\n", irq_log[STRCH_WR]); i2c_slave_clear_irq(i2c_slave, STRCH_WR); i2c_slave_send_ack(i2c_slave); } if (irq_stat & (1 << TX_FIFO_EMPTY)) { I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "%s\n", irq_log[TX_FIFO_EMPTY]); i2c_slave->tx_count = read_tx_fifo_byte_count(i2c_slave); i2c_slave_write_fifo(i2c_slave); i2c_slave_clear_irq(i2c_slave, TX_FIFO_EMPTY); } if (irq_stat & (1 << GCA_DETECTED)) { I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "%s\n", irq_log[GCA_DETECTED]); i2c_slave_send_nack(i2c_slave); i2c_slave_clear_irq(i2c_slave, GCA_DETECTED); } if (irq_stat & (1 << RESTART_DETECTED)) { I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "%s\n", irq_log[RESTART_DETECTED]); i2c_slave_send_ack(i2c_slave); i2c_slave_clear_irq(i2c_slave, RESTART_DETECTED); } if (irq_stat & (1 << SMBALERT_ARA_DONE)) { I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "%s\n", irq_log[SMBALERT_ARA_DONE]); i2c_slave_clear_irq(i2c_slave, SMBALERT_ARA_DONE); } if (irq_stat & (1 << SMBALERT_LOST_ARB)) { I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "%s\n", irq_log[SMBALERT_LOST_ARB]); i2c_slave_clear_irq(i2c_slave, SMBALERT_LOST_ARB); } return IRQ_HANDLED; } /** * i2c_slave_write: write data to fifo. * @i2c_slave: Pointer to Main Structure. * @buf: TX Data buffer. * @count: TX Data count. * * This function will write data to TX FIFO. * * Return: 0 for success, negative number for error condition. */ static int i2c_slave_write(struct i2c_slave *i2c_slave, uint8_t *buf, size_t count) { if (!buf) { I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "Invalid write buffer\n"); return -EINVAL; } if (!count) { I2C_SLAVE_ERR(i2c_slave->ipcl, false, i2c_slave->dev, "Write count is zero\n"); return -EINVAL; } i2c_slave->tx_msg_buf = buf; i2c_slave->tx_count = count; i2c_slave_write_fifo(i2c_slave); return 0; } /** * i2c_slave_read: read data from fifo. * @i2c_slave: Pointer to Main Structure. * @buf: RX Data buffer. * @count: RX Data count. * * This function will read data from RX FIFO. * * Return: 0 for success, negative number for error condition. */ static int i2c_slave_read(struct i2c_slave *i2c_slave, uint8_t *buf, size_t count) { int i; if (!buf) { I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "Invalid Read buffer\n"); return -EINVAL; } if (count == 0) { I2C_SLAVE_ERR(i2c_slave->ipcl, false, i2c_slave->dev, "Read count is zero\n"); return -EINVAL; } if (count <= I2C_SMBUS_BYTE_DATA && i2c_slave->rx_count < count) { I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "Data not available\n"); return -EINVAL; } if (count > I2C_SMBUS_BYTE_DATA) count = i2c_slave->rx_count; i2c_slave->rx_count -= count; for (i = 0; i < count; i++) buf[i] = i2c_slave->rx_msg_buf[i]; if (count <= I2C_SMBUS_BYTE_DATA) { for (i = 0; i < i2c_slave->rx_count; i++) i2c_slave->rx_msg_buf[i] = i2c_slave->rx_msg_buf[i + count]; } i2c_slave_read_fifo(i2c_slave); return count; } /** * i2c_slave_xfer: SMbus transfer function. * @adap: I2C driver adapter * @addr: Slave address * @flags: i2c client flag * @read_write: Read/Write flag * @command: SMbus command code * @protocol: Command type * @data: Pointer to client data * * Based on read_write flag, it will call read * write function. * * Return: 0 for success, Negative number for error condition. */ static int i2c_slave_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int protocol, union i2c_smbus_data *data) { struct i2c_slave *i2c_slave = i2c_get_adapdata(adap); u8 buf[I2C_SMBUS_BLOCK_MAX]; int ret = 0, count, i; /* Every open/close of i2c device node, i2c framework will set * slave address variable to 0 in i2c client structure and * client has to run IOCTL on every open/close opration. * So, to avoid slave address to be set to zero, added * check for non-zero slave address. */ if (addr && addr != i2c_slave->slave_addr) { i2c_slave->slave_addr = addr; writel_relaxed(addr, i2c_slave->base + I2C_S_DEVICE_ADDR); } if (read_write == I2C_SMBUS_READ) { switch (protocol) { case I2C_SMBUS_BYTE: case I2C_SMBUS_BYTE_DATA: count = i2c_slave_read(i2c_slave, buf, I2C_SLAVE_BYTE_DATA); if (count == I2C_SMBUS_BYTE) { data->byte = buf[0]; return 0; } ret = count; break; case I2C_SMBUS_WORD_DATA: count = i2c_slave_read(i2c_slave, buf, I2C_SLAVE_WORD_DATA); if (count == I2C_SMBUS_BYTE_DATA) { data->word = (buf[0] | (buf[1] << 8)); return 0; } ret = count; break; case I2C_SMBUS_BLOCK_DATA: count = i2c_slave_read(i2c_slave, buf, I2C_SMBUS_BLOCK_MAX); if (count > 0) { data->block[0] = count; for (i = 0; i < count; i++) data->block[i + 1] = buf[i]; return 0; } ret = count; break; default: break; } } else if (read_write == I2C_SMBUS_WRITE) { switch (protocol) { case I2C_SMBUS_BYTE: case I2C_SMBUS_BYTE_DATA: buf[0] = data->byte; ret = i2c_slave_write(i2c_slave, buf, I2C_SLAVE_BYTE_DATA); break; case I2C_SMBUS_WORD_DATA: buf[0] = (uint8_t)(data->word & 0xFF); buf[1] = (uint8_t)(data->word >> 8); ret = i2c_slave_write(i2c_slave, buf, I2C_SLAVE_WORD_DATA); break; case I2C_SMBUS_BLOCK_DATA: if (data->block[0] > I2C_SMBUS_BLOCK_MAX) data->block[0] = I2C_SMBUS_BLOCK_MAX; for (i = 0; i < data->block[0]; i++) buf[i] = data->block[i + 1]; ret = i2c_slave_write(i2c_slave, buf, data->block[0]); break; default: break; } } return ret; } /** * i2c_slave_enable_clk: Enable AHB & XO clock. * @i2c_slave: Pointer to Main Structure. * * This function will enable AHB and XO clock. * * Return: 0 for success, negative number for error condition. */ static int i2c_slave_enable_clk(struct i2c_slave *i2c_slave) { int ret = 0; i2c_slave->xo_clk = devm_clk_get(i2c_slave->dev, "sm_bus_xo_clk"); if (IS_ERR(i2c_slave->xo_clk)) { ret = PTR_ERR(i2c_slave->xo_clk); I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "Err getting XO clk %d\n", ret); return ret; } i2c_slave->ahb_clk = devm_clk_get(i2c_slave->dev, "sm_bus_ahb_clk"); if (IS_ERR(i2c_slave->ahb_clk)) { ret = PTR_ERR(i2c_slave->ahb_clk); I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "Err getting AHB clk %d\n", ret); return ret; } ret = clk_prepare_enable(i2c_slave->ahb_clk); if (ret) return ret; ret = clk_prepare_enable(i2c_slave->xo_clk); if (ret) goto err_on_xo; return 0; err_on_xo: clk_disable_unprepare(i2c_slave->ahb_clk); return ret; } /** * i2c_slave_icc_init: Enable ICB voting. * @i2c_slave: Pointer to Main Structure. * * This function will enable ICB voting for i2c slave. * * Return: 0 for success, negative number for error condition. */ static int i2c_slave_icc_init(struct i2c_slave *i2c_slave) { int ret = 0; i2c_slave->icc_path = devm_of_icc_get(i2c_slave->dev, "i2c-slave-config"); if (IS_ERR(i2c_slave->icc_path)) { I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "devm_of_icc_get failed: %d:\n", ret); return -EINVAL; } i2c_slave->bw = APPS_PROC_TO_I2C_SLAVE_VOTE; icc_set_bw(i2c_slave->icc_path, i2c_slave->bw, i2c_slave->bw); ret = icc_enable(i2c_slave->icc_path); if (ret) { I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "ICC enable failed err: %d\n", ret); devres_free(&i2c_slave->icc_path); return ret; } return 0; } /* * i2c_slave_open: open function for dev node. * @inode: Pointer to inode. * @file: Pointer to file descriptor. * * This function will be called when we open the dev node * from user-space application. * * Return: 0 for success. */ static int i2c_slave_open(struct inode *inode, struct file *file) { struct cdev *cdev = inode->i_cdev; struct i2c_slave *i2c_slave = container_of(cdev, struct i2c_slave, cdev); file->private_data = i2c_slave; return 0; } /* * i2c_slave_release: close function for dev node. * @inode: pointer to inode. * @file: Pointer to file descriptor. * * This function will be called when we close the dev node * from user-space application. * * Return: 0 for success. */ static int i2c_slave_release(struct inode *inode, struct file *file) { file->private_data = NULL; return 0; } /** * i2c_slave_poll: poll() syscall for I2C slave. * @f: Pointer to the file structure. * @wait: Pointer to Poll table. * * This function is used to poll on the I2C slave device. * when userspace client do a poll() system call. * * Return: POLLIN if RX data available else 0. */ static __poll_t i2c_slave_poll(struct file *file, struct poll_table_struct *wait) { struct i2c_slave *i2c_slave = file->private_data; __poll_t mask = 0; poll_wait(file, &i2c_slave->readq, wait); if (i2c_slave->rx_count > 0) { I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "%s: RX data available\n", __func__); mask |= POLLIN; } return mask; } static const struct file_operations fops = { .owner = THIS_MODULE, .open = i2c_slave_open, .poll = i2c_slave_poll, .release = i2c_slave_release, }; /** * i2c_slave_create_dev_node: Create dev node for poll * @i2c_slave: Pointer to Main Structure. * * This function will create user-space dev node to support * poll function on the I2C slave device. * * Return: 0 for success, negative number for error condition. */ static int i2c_slave_create_dev_node(struct i2c_slave *i2c_slave) { struct device *dev_ret; struct class *i2c_slave_class; dev_t i2c_slave_dev; int ret = 0; ret = alloc_chrdev_region(&i2c_slave_dev, 0, 1, I2C_SLAVE_DEV); if (ret < 0) { I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "%s: failed in alloc_chrdev_region ret:%d\n", ret); goto err_alloc; } cdev_init(&i2c_slave->cdev, &fops); ret = cdev_add(&i2c_slave->cdev, i2c_slave_dev, 1); if (ret < 0) { I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "%s: failed in cdev_add ret:%d\n", ret); goto err_cdev_add; } i2c_slave_class = class_create(THIS_MODULE, I2C_SLAVE_DEV); if (IS_ERR_OR_NULL(i2c_slave_class)) { I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "%s: failed in class_create:%d\n", ret); ret = PTR_ERR(i2c_slave_class); goto err_class_create; } dev_ret = device_create(i2c_slave_class, NULL, i2c_slave_dev, NULL, I2C_SLAVE_DEV); if (IS_ERR_OR_NULL(dev_ret)) { I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "%s: failed in device_create:%d\n", ret); ret = PTR_ERR(dev_ret); goto err_device_create; } return ret; err_device_create: class_destroy(i2c_slave_class); err_class_create: cdev_del(&i2c_slave->cdev); err_cdev_add: unregister_chrdev_region(i2c_slave_dev, 1); err_alloc: return ret; } /** * i2c_slave_func: To check supported i2c functionality. * @adap: I2C driver adapter. * * This function will use to determine what the adapter supports. * * Return: 0 for success, negative number for error condition. */ static u32 i2c_slave_func(struct i2c_adapter *adap) { return I2C_FUNC_SMBUS_BYTE; } static const struct i2c_algorithm i2c_slave_algo = { .smbus_xfer = i2c_slave_xfer, .functionality = i2c_slave_func, }; /** * i2c_slave_probe: Driver Probe function. * @pdev: Pointer to platform device structure. * * This function will performs pre-initialization tasks such as reading dtsi property, * setting clock, IRQ request, initializing registers, allocating memory, * and initializing registers for i2c slave. * * Return: 0 for success, negative number for error condition. */ static int i2c_slave_probe(struct platform_device *pdev) { struct i2c_slave *i2c_slave; struct resource *res; static const char adapName[10] = "I2C-slave"; char ipc_name[I2C_NAME_SIZE]; int ret = 0; i2c_slave = devm_kzalloc(&pdev->dev, sizeof(*i2c_slave), GFP_KERNEL); if (!i2c_slave) { ret = -ENOMEM; goto err; } i2c_slave->dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { ret = -EINVAL; goto err; } i2c_slave->base = devm_ioremap_resource(i2c_slave->dev, res); if (IS_ERR(i2c_slave->base)) { ret = PTR_ERR(i2c_slave->base); goto err; } scnprintf(ipc_name, I2C_NAME_SIZE, "%s", dev_name(i2c_slave->dev)); i2c_slave->ipcl = ipc_log_context_create(2, ipc_name, 0); if (!i2c_slave->ipcl) { dev_err(i2c_slave->dev, "Error: Failed to create IPC log file\n"); ret = -EINVAL; goto err_ipc; } ret = i2c_slave_create_dev_node(i2c_slave); if (ret < 0) { I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "failed to create dev node ret: %d:\n", ret); goto err_ipc; } ret = i2c_slave_enable_clk(i2c_slave); if (ret) goto err_ipc; i2c_slave->irq = platform_get_irq(pdev, 0); if (i2c_slave->irq < 0) { I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "get_irq failed: %d:\n", i2c_slave->irq); ret = i2c_slave->irq; goto err_irq; } ret = devm_request_irq(i2c_slave->dev, i2c_slave->irq, i2c_slave_irq, 0, "i2c_slave", i2c_slave); if (ret) { I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "Request_irq failed: %d: err: %d\n", i2c_slave->irq, ret); goto err_irq; } ret = i2c_slave_icc_init(i2c_slave); if (ret) { I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "ICC init failed ret: %d\n", ret); goto err_icc; } i2c_slave->adap.algo = &i2c_slave_algo; i2c_slave->rx_count = 0; /* Enable IRQ */ i2c_slave_enable_irq(i2c_slave); /* Set default slave address */ writel_relaxed(SLAVE_ADDR, i2c_slave->base + I2C_S_DEVICE_ADDR); i2c_slave->slave_addr = SLAVE_ADDR; /* Enable core */ writel_relaxed(CORE_EN, i2c_slave->base + I2C_S_CONFIG); ret = strscpy(i2c_slave->adap.name, adapName, sizeof(i2c_slave->adap.name)); if (ret != strlen(adapName)) { I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "Failed to set adapter name\n"); goto err_adap; } init_waitqueue_head(&i2c_slave->readq); i2c_set_adapdata(&i2c_slave->adap, i2c_slave); platform_set_drvdata(pdev, i2c_slave); i2c_slave->adap.dev.parent = i2c_slave->dev; i2c_slave->adap.dev.of_node = pdev->dev.of_node; ret = i2c_add_adapter(&i2c_slave->adap); if (ret) { I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "Add adapter failed, ret=%d\n", ret); goto err_adap; } I2C_SLAVE_DBG(i2c_slave->ipcl, true, i2c_slave->dev, "I2C Slave probed\n"); return 0; err_adap: icc_disable(i2c_slave->icc_path); devres_free(&i2c_slave->icc_path); err_icc: disable_irq(i2c_slave->irq); err_irq: clk_disable_unprepare(i2c_slave->ahb_clk); clk_disable_unprepare(i2c_slave->xo_clk); err_ipc: if (i2c_slave->ipcl) ipc_log_context_destroy(i2c_slave->ipcl); err: return ret; } /** * i2c_slave_remove: This function will release the resources. * @pdev: Pointer to platform device structure. * * This function will release clocks, IRQ and other allocated resources for * i2c slave. * * Return: 0 for success. */ static int i2c_slave_remove(struct platform_device *pdev) { struct i2c_slave *i2c_slave = platform_get_drvdata(pdev); clk_disable_unprepare(i2c_slave->ahb_clk); clk_disable_unprepare(i2c_slave->xo_clk); disable_irq(i2c_slave->irq); icc_disable(i2c_slave->icc_path); devres_free(&i2c_slave->icc_path); i2c_del_adapter(&i2c_slave->adap); if (i2c_slave->ipcl) ipc_log_context_destroy(i2c_slave->ipcl); return 0; } /** * i2c_slave_suspend: driver suspend function. * @dev: Pointer to device structure. * * This function will put driver into suspend state by releasing * icc, irq and core clock. * * Return: 0 for success. */ #ifdef I2C_SLAVE_SUSPEND_RESUME static int i2c_slave_suspend(struct device *dev) { struct i2c_slave *i2c_slave = dev_get_drvdata(dev); disable_irq(i2c_slave->irq); icc_disable(i2c_slave->icc_path); clk_disable_unprepare(i2c_slave->ahb_clk); clk_disable_unprepare(i2c_slave->xo_clk); I2C_SLAVE_DBG(i2c_slave->ipcl, false, i2c_slave->dev, "%s\n", __func__); return 0; } /** * i2c_slave_resume: driver resume function. * @dev: Pointer to device structure. * * This function will resume the driver by enabling icc, irq * and core clock. * * Return: 0 for success, negative number for error condition. */ static int i2c_slave_resume(struct device *dev) { struct i2c_slave *i2c_slave = dev_get_drvdata(dev); int ret = 0; enable_irq(i2c_slave->irq); ret = icc_enable(i2c_slave->icc_path); if (ret) { I2C_SLAVE_ERR(i2c_slave->ipcl, true, i2c_slave->dev, "ICC enable failed err: %d\n", ret); goto err_icc; } ret = clk_prepare_enable(i2c_slave->ahb_clk); if (ret) { I2C_SLAVE_DBG(i2c_slave->ipcl, true, i2c_slave->dev, "%s: failing at ahb clk prepare enable ret=%d\n", __func__, ret); goto err_ahb_clk; } ret = clk_prepare_enable(i2c_slave->xo_clk); if (ret) { I2C_SLAVE_DBG(i2c_slave->ipcl, true, i2c_slave->dev, "%s: failing at xo clk prepare enable ret=%d\n", __func__, ret); clk_disable_unprepare(i2c_slave->ahb_clk); goto err_xo_clk; } I2C_SLAVE_DBG(i2c_slave->ipcl, true, i2c_slave->dev, "%s:\n", __func__); return 0; err_xo_clk: clk_disable_unprepare(i2c_slave->ahb_clk); err_ahb_clk: icc_disable(i2c_slave->icc_path); err_icc: return ret; } #else static int i2c_slave_suspend(struct device *dev) { return 0; } static int i2c_slave_resume(struct device *dev) { return 0; } #endif static const struct dev_pm_ops i2c_slave_pm_ops = { .suspend = i2c_slave_suspend, .resume = i2c_slave_resume, }; static const struct of_device_id i2c_slave_dt_match[] = { {.compatible = "qcom,i2c-slave" }, { } }; MODULE_DEVICE_TABLE(of, i2c_slave_dt_match); static struct platform_driver i2c_slave_driver = { .driver = { .name = "i2c_slave", .pm = &i2c_slave_pm_ops, .of_match_table = i2c_slave_dt_match, }, .probe = i2c_slave_probe, .remove = i2c_slave_remove, }; module_platform_driver(i2c_slave_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("i2c slave");