diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/Kconfig | 12 | ||||
-rw-r--r-- | drivers/i2c/Makefile | 2 | ||||
-rw-r--r-- | drivers/i2c/kona_i2c.c | 728 | ||||
-rw-r--r-- | drivers/i2c/mxc_i2c.c | 4 | ||||
-rw-r--r-- | drivers/i2c/qup_i2c.c | 579 | ||||
-rw-r--r-- | drivers/i2c/sh_i2c.c | 5 |
6 files changed, 594 insertions, 736 deletions
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 76e19918aa..427074bff8 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -580,6 +580,18 @@ config SYS_I2C_OCTEON chips have several I2C ports and all are provided, controlled by the device tree. +config SYS_I2C_QUP + bool "Qualcomm QUP I2C controller" + depends on ARCH_SNAPDRAGON + help + Support for Qualcomm QUP I2C controller based on Qualcomm Universal + Peripherals (QUP) engine. The QUP engine is an advanced high + performance slave port that provides a common data path (an output + FIFO and an input FIFO) for I2C and SPI interfaces. The I2C/SPI QUP + controller is publicly documented in the Snapdragon 410E (APQ8016E) + Technical Reference Manual, chapter "6.1 Qualcomm Universal + Peripherals Engine (QUP)". + config SYS_I2C_S3C24X0 bool "Samsung I2C driver" depends on (ARCH_EXYNOS4 || ARCH_EXYNOS5) && DM_I2C diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 920aafb91c..8a70b5ba88 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -25,7 +25,6 @@ obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o obj-$(CONFIG_SYS_I2C_INTEL) += intel_i2c.o obj-$(CONFIG_SYS_I2C_IMX_LPI2C) += imx_lpi2c.o obj-$(CONFIG_SYS_I2C_IPROC) += iproc_i2c.o -obj-$(CONFIG_SYS_I2C_KONA) += kona_i2c.o obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o obj-$(CONFIG_SYS_I2C_MESON) += meson_i2c.o obj-$(CONFIG_SYS_I2C_MICROCHIP) += i2c-microchip.o @@ -38,6 +37,7 @@ obj-$(CONFIG_SYS_I2C_NPCM) += npcm_i2c.o obj-$(CONFIG_SYS_I2C_OCORES) += ocores_i2c.o obj-$(CONFIG_SYS_I2C_OCTEON) += octeon_i2c.o obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o +obj-$(CONFIG_SYS_I2C_QUP) += qup_i2c.o obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o obj-$(CONFIG_SYS_I2C_ROCKCHIP) += rk_i2c.o diff --git a/drivers/i2c/kona_i2c.c b/drivers/i2c/kona_i2c.c deleted file mode 100644 index b9b0ff1c39..0000000000 --- a/drivers/i2c/kona_i2c.c +++ /dev/null @@ -1,728 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright 2013 Broadcom Corporation. - * - * NOTE: This driver should be converted to driver model before June 2017. - * Please see doc/driver-model/i2c-howto.rst for instructions. - */ - -#include <common.h> -#include <log.h> -#include <asm/io.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <asm/arch/sysmap.h> -#include <asm/kona-common/clk.h> -#include <i2c.h> - -/* Hardware register offsets and field defintions */ -#define CS_OFFSET 0x00000020 -#define CS_ACK_SHIFT 3 -#define CS_ACK_MASK 0x00000008 -#define CS_ACK_CMD_GEN_START 0x00000000 -#define CS_ACK_CMD_GEN_RESTART 0x00000001 -#define CS_CMD_SHIFT 1 -#define CS_CMD_CMD_NO_ACTION 0x00000000 -#define CS_CMD_CMD_START_RESTART 0x00000001 -#define CS_CMD_CMD_STOP 0x00000002 -#define CS_EN_SHIFT 0 -#define CS_EN_CMD_ENABLE_BSC 0x00000001 - -#define TIM_OFFSET 0x00000024 -#define TIM_PRESCALE_SHIFT 6 -#define TIM_P_SHIFT 3 -#define TIM_NO_DIV_SHIFT 2 -#define TIM_DIV_SHIFT 0 - -#define DAT_OFFSET 0x00000028 - -#define TOUT_OFFSET 0x0000002c - -#define TXFCR_OFFSET 0x0000003c -#define TXFCR_FIFO_FLUSH_MASK 0x00000080 -#define TXFCR_FIFO_EN_MASK 0x00000040 - -#define IER_OFFSET 0x00000044 -#define IER_READ_COMPLETE_INT_MASK 0x00000010 -#define IER_I2C_INT_EN_MASK 0x00000008 -#define IER_FIFO_INT_EN_MASK 0x00000002 -#define IER_NOACK_EN_MASK 0x00000001 - -#define ISR_OFFSET 0x00000048 -#define ISR_RESERVED_MASK 0xffffff60 -#define ISR_CMDBUSY_MASK 0x00000080 -#define ISR_READ_COMPLETE_MASK 0x00000010 -#define ISR_SES_DONE_MASK 0x00000008 -#define ISR_ERR_MASK 0x00000004 -#define ISR_TXFIFOEMPTY_MASK 0x00000002 -#define ISR_NOACK_MASK 0x00000001 - -#define CLKEN_OFFSET 0x0000004c -#define CLKEN_AUTOSENSE_OFF_MASK 0x00000080 -#define CLKEN_M_SHIFT 4 -#define CLKEN_N_SHIFT 1 -#define CLKEN_CLKEN_MASK 0x00000001 - -#define FIFO_STATUS_OFFSET 0x00000054 -#define FIFO_STATUS_RXFIFO_EMPTY_MASK 0x00000004 -#define FIFO_STATUS_TXFIFO_EMPTY_MASK 0x00000010 - -#define HSTIM_OFFSET 0x00000058 -#define HSTIM_HS_MODE_MASK 0x00008000 -#define HSTIM_HS_HOLD_SHIFT 10 -#define HSTIM_HS_HIGH_PHASE_SHIFT 5 -#define HSTIM_HS_SETUP_SHIFT 0 - -#define PADCTL_OFFSET 0x0000005c -#define PADCTL_PAD_OUT_EN_MASK 0x00000004 - -#define RXFCR_OFFSET 0x00000068 -#define RXFCR_NACK_EN_SHIFT 7 -#define RXFCR_READ_COUNT_SHIFT 0 -#define RXFIFORDOUT_OFFSET 0x0000006c - -/* Locally used constants */ -#define MAX_RX_FIFO_SIZE 64U /* bytes */ -#define MAX_TX_FIFO_SIZE 64U /* bytes */ - -#define I2C_TIMEOUT 100000 /* usecs */ - -#define WAIT_INT_CHK 100 /* usecs */ -#if I2C_TIMEOUT % WAIT_INT_CHK -#error I2C_TIMEOUT must be a multiple of WAIT_INT_CHK -#endif - -/* Operations that can be commanded to the controller */ -enum bcm_kona_cmd_t { - BCM_CMD_NOACTION = 0, - BCM_CMD_START, - BCM_CMD_RESTART, - BCM_CMD_STOP, -}; - -/* Internal divider settings for standard mode, fast mode and fast mode plus */ -struct bus_speed_cfg { - uint8_t time_m; /* Number of cycles for setup time */ - uint8_t time_n; /* Number of cycles for hold time */ - uint8_t prescale; /* Prescale divider */ - uint8_t time_p; /* Timing coefficient */ - uint8_t no_div; /* Disable clock divider */ - uint8_t time_div; /* Post-prescale divider */ -}; - -static const struct bus_speed_cfg std_cfg_table[] = { - [IC_SPEED_MODE_STANDARD] = {0x01, 0x01, 0x03, 0x06, 0x00, 0x02}, - [IC_SPEED_MODE_FAST] = {0x05, 0x01, 0x03, 0x05, 0x01, 0x02}, - [IC_SPEED_MODE_FAST_PLUS] = {0x01, 0x01, 0x03, 0x01, 0x01, 0x03}, -}; - -struct bcm_kona_i2c_dev { - void *base; - uint speed; - const struct bus_speed_cfg *std_cfg; -}; - -/* Keep these two defines in sync */ -#define DEF_SPD I2C_SPEED_STANDARD_RATE -#define DEF_SPD_ENUM IC_SPEED_MODE_STANDARD - -#define DEF_DEVICE(num) \ -{(void *)CONFIG_SYS_I2C_BASE##num, DEF_SPD, &std_cfg_table[DEF_SPD_ENUM]} - -static struct bcm_kona_i2c_dev g_i2c_devs[CFG_SYS_MAX_I2C_BUS] = { -#ifdef CONFIG_SYS_I2C_BASE0 - DEF_DEVICE(0), -#endif -#ifdef CONFIG_SYS_I2C_BASE1 - DEF_DEVICE(1), -#endif -#ifdef CONFIG_SYS_I2C_BASE2 - DEF_DEVICE(2), -#endif -#ifdef CONFIG_SYS_I2C_BASE3 - DEF_DEVICE(3), -#endif -#ifdef CONFIG_SYS_I2C_BASE4 - DEF_DEVICE(4), -#endif -#ifdef CONFIG_SYS_I2C_BASE5 - DEF_DEVICE(5), -#endif -}; - -#define I2C_M_TEN 0x0010 /* ten bit address */ -#define I2C_M_RD 0x0001 /* read data */ -#define I2C_M_NOSTART 0x4000 /* no restart between msgs */ - -struct kona_i2c_msg { - uint16_t addr; - uint16_t flags; - uint16_t len; - uint8_t *buf; -}; - -static void bcm_kona_i2c_send_cmd_to_ctrl(struct bcm_kona_i2c_dev *dev, - enum bcm_kona_cmd_t cmd) -{ - debug("%s, %d\n", __func__, cmd); - - switch (cmd) { - case BCM_CMD_NOACTION: - writel((CS_CMD_CMD_NO_ACTION << CS_CMD_SHIFT) | - (CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT), - dev->base + CS_OFFSET); - break; - - case BCM_CMD_START: - writel((CS_ACK_CMD_GEN_START << CS_ACK_SHIFT) | - (CS_CMD_CMD_START_RESTART << CS_CMD_SHIFT) | - (CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT), - dev->base + CS_OFFSET); - break; - - case BCM_CMD_RESTART: - writel((CS_ACK_CMD_GEN_RESTART << CS_ACK_SHIFT) | - (CS_CMD_CMD_START_RESTART << CS_CMD_SHIFT) | - (CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT), - dev->base + CS_OFFSET); - break; - - case BCM_CMD_STOP: - writel((CS_CMD_CMD_STOP << CS_CMD_SHIFT) | - (CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT), - dev->base + CS_OFFSET); - break; - - default: - printf("Unknown command %d\n", cmd); - } -} - -static void bcm_kona_i2c_enable_clock(struct bcm_kona_i2c_dev *dev) -{ - writel(readl(dev->base + CLKEN_OFFSET) | CLKEN_CLKEN_MASK, - dev->base + CLKEN_OFFSET); -} - -static void bcm_kona_i2c_disable_clock(struct bcm_kona_i2c_dev *dev) -{ - writel(readl(dev->base + CLKEN_OFFSET) & ~CLKEN_CLKEN_MASK, - dev->base + CLKEN_OFFSET); -} - -/* Wait until at least one of the mask bit(s) are set */ -static unsigned long wait_for_int_timeout(struct bcm_kona_i2c_dev *dev, - unsigned long time_left, - uint32_t mask) -{ - uint32_t status; - - while (time_left) { - status = readl(dev->base + ISR_OFFSET); - - if ((status & ~ISR_RESERVED_MASK) == 0) { - debug("Bogus I2C interrupt 0x%x\n", status); - continue; - } - - /* Must flush the TX FIFO when NAK detected */ - if (status & ISR_NOACK_MASK) - writel(TXFCR_FIFO_FLUSH_MASK | TXFCR_FIFO_EN_MASK, - dev->base + TXFCR_OFFSET); - - writel(status & ~ISR_RESERVED_MASK, dev->base + ISR_OFFSET); - - if (status & mask) { - /* We are done since one of the mask bits are set */ - return time_left; - } - udelay(WAIT_INT_CHK); - time_left -= WAIT_INT_CHK; - } - return 0; -} - -/* Send command to I2C bus */ -static int bcm_kona_send_i2c_cmd(struct bcm_kona_i2c_dev *dev, - enum bcm_kona_cmd_t cmd) -{ - int rc = 0; - unsigned long time_left = I2C_TIMEOUT; - - /* Send the command */ - bcm_kona_i2c_send_cmd_to_ctrl(dev, cmd); - - /* Wait for transaction to finish or timeout */ - time_left = wait_for_int_timeout(dev, time_left, IER_I2C_INT_EN_MASK); - - if (!time_left) { - printf("controller timed out\n"); - rc = -ETIMEDOUT; - } - - /* Clear command */ - bcm_kona_i2c_send_cmd_to_ctrl(dev, BCM_CMD_NOACTION); - - return rc; -} - -/* Read a single RX FIFO worth of data from the i2c bus */ -static int bcm_kona_i2c_read_fifo_single(struct bcm_kona_i2c_dev *dev, - uint8_t *buf, unsigned int len, - unsigned int last_byte_nak) -{ - unsigned long time_left = I2C_TIMEOUT; - - /* Start the RX FIFO */ - writel((last_byte_nak << RXFCR_NACK_EN_SHIFT) | - (len << RXFCR_READ_COUNT_SHIFT), dev->base + RXFCR_OFFSET); - - /* Wait for FIFO read to complete */ - time_left = - wait_for_int_timeout(dev, time_left, IER_READ_COMPLETE_INT_MASK); - - if (!time_left) { - printf("RX FIFO time out\n"); - return -EREMOTEIO; - } - - /* Read data from FIFO */ - for (; len > 0; len--, buf++) - *buf = readl(dev->base + RXFIFORDOUT_OFFSET); - - return 0; -} - -/* Read any amount of data using the RX FIFO from the i2c bus */ -static int bcm_kona_i2c_read_fifo(struct bcm_kona_i2c_dev *dev, - struct kona_i2c_msg *msg) -{ - unsigned int bytes_to_read = MAX_RX_FIFO_SIZE; - unsigned int last_byte_nak = 0; - unsigned int bytes_read = 0; - int rc; - - uint8_t *tmp_buf = msg->buf; - - while (bytes_read < msg->len) { - if (msg->len - bytes_read <= MAX_RX_FIFO_SIZE) { - last_byte_nak = 1; /* NAK last byte of transfer */ - bytes_to_read = msg->len - bytes_read; - } - - rc = bcm_kona_i2c_read_fifo_single(dev, tmp_buf, bytes_to_read, - last_byte_nak); - if (rc < 0) - return -EREMOTEIO; - - bytes_read += bytes_to_read; - tmp_buf += bytes_to_read; - } - - return 0; -} - -/* Write a single byte of data to the i2c bus */ -static int bcm_kona_i2c_write_byte(struct bcm_kona_i2c_dev *dev, uint8_t data, - unsigned int nak_expected) -{ - unsigned long time_left = I2C_TIMEOUT; - unsigned int nak_received; - - /* Clear pending session done interrupt */ - writel(ISR_SES_DONE_MASK, dev->base + ISR_OFFSET); - - /* Send one byte of data */ - writel(data, dev->base + DAT_OFFSET); - - time_left = wait_for_int_timeout(dev, time_left, IER_I2C_INT_EN_MASK); - - if (!time_left) { - debug("controller timed out\n"); - return -ETIMEDOUT; - } - - nak_received = readl(dev->base + CS_OFFSET) & CS_ACK_MASK ? 1 : 0; - - if (nak_received ^ nak_expected) { - debug("unexpected NAK/ACK\n"); - return -EREMOTEIO; - } - - return 0; -} - -/* Write a single TX FIFO worth of data to the i2c bus */ -static int bcm_kona_i2c_write_fifo_single(struct bcm_kona_i2c_dev *dev, - uint8_t *buf, unsigned int len) -{ - int k; - unsigned long time_left = I2C_TIMEOUT; - unsigned int fifo_status; - - /* Write data into FIFO */ - for (k = 0; k < len; k++) - writel(buf[k], (dev->base + DAT_OFFSET)); - - /* Wait for FIFO to empty */ - do { - time_left = - wait_for_int_timeout(dev, time_left, - (IER_FIFO_INT_EN_MASK | - IER_NOACK_EN_MASK)); - fifo_status = readl(dev->base + FIFO_STATUS_OFFSET); - } while (time_left && !(fifo_status & FIFO_STATUS_TXFIFO_EMPTY_MASK)); - - /* Check if there was a NAK */ - if (readl(dev->base + CS_OFFSET) & CS_ACK_MASK) { - printf("unexpected NAK\n"); - return -EREMOTEIO; - } - - /* Check if a timeout occurred */ - if (!time_left) { - printf("completion timed out\n"); - return -EREMOTEIO; - } - - return 0; -} - -/* Write any amount of data using TX FIFO to the i2c bus */ -static int bcm_kona_i2c_write_fifo(struct bcm_kona_i2c_dev *dev, - struct kona_i2c_msg *msg) -{ - unsigned int bytes_to_write = MAX_TX_FIFO_SIZE; - unsigned int bytes_written = 0; - int rc; - - uint8_t *tmp_buf = msg->buf; - - while (bytes_written < msg->len) { - if (msg->len - bytes_written <= MAX_TX_FIFO_SIZE) - bytes_to_write = msg->len - bytes_written; - - rc = bcm_kona_i2c_write_fifo_single(dev, tmp_buf, - bytes_to_write); - if (rc < 0) - return -EREMOTEIO; - - bytes_written += bytes_to_write; - tmp_buf += bytes_to_write; - } - - return 0; -} - -/* Send i2c address */ -static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev, - struct kona_i2c_msg *msg) -{ - unsigned char addr; - - if (msg->flags & I2C_M_TEN) { - /* First byte is 11110XX0 where XX is upper 2 bits */ - addr = 0xf0 | ((msg->addr & 0x300) >> 7); - if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0) - return -EREMOTEIO; - - /* Second byte is the remaining 8 bits */ - addr = msg->addr & 0xff; - if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0) - return -EREMOTEIO; - - if (msg->flags & I2C_M_RD) { - /* For read, send restart command */ - if (bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART) < 0) - return -EREMOTEIO; - - /* Then re-send the first byte with the read bit set */ - addr = 0xf0 | ((msg->addr & 0x300) >> 7) | 0x01; - if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0) - return -EREMOTEIO; - } - } else { - addr = msg->addr << 1; - - if (msg->flags & I2C_M_RD) - addr |= 1; - - if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0) - return -EREMOTEIO; - } - - return 0; -} - -static void bcm_kona_i2c_enable_autosense(struct bcm_kona_i2c_dev *dev) -{ - writel(readl(dev->base + CLKEN_OFFSET) & ~CLKEN_AUTOSENSE_OFF_MASK, - dev->base + CLKEN_OFFSET); -} - -static void bcm_kona_i2c_config_timing(struct bcm_kona_i2c_dev *dev) -{ - writel(readl(dev->base + HSTIM_OFFSET) & ~HSTIM_HS_MODE_MASK, - dev->base + HSTIM_OFFSET); - - writel((dev->std_cfg->prescale << TIM_PRESCALE_SHIFT) | - (dev->std_cfg->time_p << TIM_P_SHIFT) | - (dev->std_cfg->no_div << TIM_NO_DIV_SHIFT) | - (dev->std_cfg->time_div << TIM_DIV_SHIFT), - dev->base + TIM_OFFSET); - - writel((dev->std_cfg->time_m << CLKEN_M_SHIFT) | - (dev->std_cfg->time_n << CLKEN_N_SHIFT) | - CLKEN_CLKEN_MASK, dev->base + CLKEN_OFFSET); -} - -/* Master transfer function */ -static int bcm_kona_i2c_xfer(struct bcm_kona_i2c_dev *dev, - struct kona_i2c_msg msgs[], int num) -{ - struct kona_i2c_msg *pmsg; - int rc = 0; - int i; - - /* Enable pad output */ - writel(0, dev->base + PADCTL_OFFSET); - - /* Enable internal clocks */ - bcm_kona_i2c_enable_clock(dev); - - /* Send start command */ - rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_START); - if (rc < 0) { - printf("Start command failed rc = %d\n", rc); - goto xfer_disable_pad; - } - - /* Loop through all messages */ - for (i = 0; i < num; i++) { - pmsg = &msgs[i]; - - /* Send restart for subsequent messages */ - if ((i != 0) && ((pmsg->flags & I2C_M_NOSTART) == 0)) { - rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART); - if (rc < 0) { - printf("restart cmd failed rc = %d\n", rc); - goto xfer_send_stop; - } - } - - /* Send slave address */ - if (!(pmsg->flags & I2C_M_NOSTART)) { - rc = bcm_kona_i2c_do_addr(dev, pmsg); - if (rc < 0) { - debug("NAK from addr %2.2x msg#%d rc = %d\n", - pmsg->addr, i, rc); - goto xfer_send_stop; - } - } - - /* Perform data transfer */ - if (pmsg->flags & I2C_M_RD) { - rc = bcm_kona_i2c_read_fifo(dev, pmsg); - if (rc < 0) { - printf("read failure\n"); - goto xfer_send_stop; - } - } else { - rc = bcm_kona_i2c_write_fifo(dev, pmsg); - if (rc < 0) { - printf("write failure"); - goto xfer_send_stop; - } - } - } - - rc = num; - -xfer_send_stop: - /* Send a STOP command */ - bcm_kona_send_i2c_cmd(dev, BCM_CMD_STOP); - -xfer_disable_pad: - /* Disable pad output */ - writel(PADCTL_PAD_OUT_EN_MASK, dev->base + PADCTL_OFFSET); - - /* Stop internal clock */ - bcm_kona_i2c_disable_clock(dev); - - return rc; -} - -static uint bcm_kona_i2c_assign_bus_speed(struct bcm_kona_i2c_dev *dev, - uint speed) -{ - switch (speed) { - case I2C_SPEED_STANDARD_RATE: - dev->std_cfg = &std_cfg_table[IC_SPEED_MODE_STANDARD]; - break; - case I2C_SPEED_FAST_RATE: - dev->std_cfg = &std_cfg_table[IC_SPEED_MODE_FAST]; - break; - case I2C_SPEED_FAST_PLUS_RATE: - dev->std_cfg = &std_cfg_table[IC_SPEED_MODE_FAST_PLUS]; - break; - default: - printf("%d hz bus speed not supported\n", speed); - return -EINVAL; - } - dev->speed = speed; - return 0; -} - -static void bcm_kona_i2c_init(struct bcm_kona_i2c_dev *dev) -{ - /* Parse bus speed */ - bcm_kona_i2c_assign_bus_speed(dev, dev->speed); - - /* Enable internal clocks */ - bcm_kona_i2c_enable_clock(dev); - - /* Configure internal dividers */ - bcm_kona_i2c_config_timing(dev); - - /* Disable timeout */ - writel(0, dev->base + TOUT_OFFSET); - - /* Enable autosense */ - bcm_kona_i2c_enable_autosense(dev); - - /* Enable TX FIFO */ - writel(TXFCR_FIFO_FLUSH_MASK | TXFCR_FIFO_EN_MASK, - dev->base + TXFCR_OFFSET); - - /* Mask all interrupts */ - writel(0, dev->base + IER_OFFSET); - - /* Clear all pending interrupts */ - writel(ISR_CMDBUSY_MASK | - ISR_READ_COMPLETE_MASK | - ISR_SES_DONE_MASK | - ISR_ERR_MASK | - ISR_TXFIFOEMPTY_MASK | ISR_NOACK_MASK, dev->base + ISR_OFFSET); - - /* Enable the controller but leave it idle */ - bcm_kona_i2c_send_cmd_to_ctrl(dev, BCM_CMD_NOACTION); - - /* Disable pad output */ - writel(PADCTL_PAD_OUT_EN_MASK, dev->base + PADCTL_OFFSET); -} - -/* - * uboot layer - */ -struct bcm_kona_i2c_dev *kona_get_dev(struct i2c_adapter *adap) -{ - return &g_i2c_devs[adap->hwadapnr]; -} - -static void kona_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) -{ - struct bcm_kona_i2c_dev *dev = kona_get_dev(adap); - - if (clk_bsc_enable(dev->base)) - return; - - bcm_kona_i2c_init(dev); -} - -static int kona_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, - int alen, uchar *buffer, int len) -{ - /* msg[0] writes the addr, msg[1] reads the data */ - struct kona_i2c_msg msg[2]; - unsigned char msgbuf0[64]; - struct bcm_kona_i2c_dev *dev = kona_get_dev(adap); - - msg[0].addr = chip; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = msgbuf0; /* msgbuf0 contains incrementing reg addr */ - - msg[1].addr = chip; - msg[1].flags = I2C_M_RD; - /* msg[1].buf dest ptr increments each read */ - - msgbuf0[0] = (unsigned char)addr; - msg[1].buf = buffer; - msg[1].len = len; - if (bcm_kona_i2c_xfer(dev, msg, 2) < 0) { - /* Sending 2 i2c messages */ - kona_i2c_init(adap, adap->speed, adap->slaveaddr); - debug("I2C read: I/O error\n"); - return -EIO; - } - return 0; -} - -static int kona_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, - int alen, uchar *buffer, int len) -{ - struct kona_i2c_msg msg[1]; - unsigned char msgbuf0[64]; - unsigned int i; - struct bcm_kona_i2c_dev *dev = kona_get_dev(adap); - - msg[0].addr = chip; - msg[0].flags = 0; - msg[0].len = 2; /* addr byte plus data */ - msg[0].buf = msgbuf0; - - for (i = 0; i < len; i++) { - msgbuf0[0] = addr++; - msgbuf0[1] = buffer[i]; - if (bcm_kona_i2c_xfer(dev, msg, 1) < 0) { - kona_i2c_init(adap, adap->speed, adap->slaveaddr); - debug("I2C write: I/O error\n"); - return -EIO; - } - } - return 0; -} - -static int kona_i2c_probe(struct i2c_adapter *adap, uchar chip) -{ - uchar tmp; - - /* - * read addr 0x0 of the given chip. - */ - return kona_i2c_read(adap, chip, 0x0, 1, &tmp, 1); -} - -static uint kona_i2c_set_bus_speed(struct i2c_adapter *adap, uint speed) -{ - struct bcm_kona_i2c_dev *dev = kona_get_dev(adap); - return bcm_kona_i2c_assign_bus_speed(dev, speed); -} - -/* - * Register kona i2c adapters. Keep the order below so - * that the bus number matches the adapter number. - */ -#define DEF_ADAPTER(num) \ -U_BOOT_I2C_ADAP_COMPLETE(kona##num, kona_i2c_init, kona_i2c_probe, \ - kona_i2c_read, kona_i2c_write, \ - kona_i2c_set_bus_speed, DEF_SPD, 0x00, num) - -#ifdef CONFIG_SYS_I2C_BASE0 - DEF_ADAPTER(0) -#endif -#ifdef CONFIG_SYS_I2C_BASE1 - DEF_ADAPTER(1) -#endif -#ifdef CONFIG_SYS_I2C_BASE2 - DEF_ADAPTER(2) -#endif -#ifdef CONFIG_SYS_I2C_BASE3 - DEF_ADAPTER(3) -#endif -#ifdef CONFIG_SYS_I2C_BASE4 - DEF_ADAPTER(4) -#endif -#ifdef CONFIG_SYS_I2C_BASE5 - DEF_ADAPTER(5) -#endif diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 9a1599dcd9..86b9fb57c8 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -744,7 +744,7 @@ void bus_i2c_init(int index, int speed, int unused, return; } - if (CONFIG_IS_ENABLED(IMX_MODULE_FUSE)) { + if (IS_ENABLED(CONFIG_IMX_MODULE_FUSE)) { if (i2c_fused((ulong)mxc_i2c_buses[index].base)) { printf("SoC fuse indicates I2C@0x%lx is unavailable.\n", (ulong)mxc_i2c_buses[index].base); @@ -878,7 +878,7 @@ static int mxc_i2c_probe(struct udevice *bus) if (addr == FDT_ADDR_T_NONE) return -EINVAL; - if (CONFIG_IS_ENABLED(IMX_MODULE_FUSE)) { + if (IS_ENABLED(CONFIG_IMX_MODULE_FUSE)) { if (i2c_fused((ulong)addr)) { printf("SoC fuse indicates I2C@0x%lx is unavailable.\n", (ulong)addr); diff --git a/drivers/i2c/qup_i2c.c b/drivers/i2c/qup_i2c.c new file mode 100644 index 0000000000..5ae3cccd4a --- /dev/null +++ b/drivers/i2c/qup_i2c.c @@ -0,0 +1,579 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2009-2013, 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2014, Sony Mobile Communications AB. + * Copyright (c) 2022-2023, Sumit Garg <sumit.garg@linaro.org> + * + * Inspired by corresponding driver in Linux: drivers/i2c/busses/i2c-qup.c + */ + +#include <init.h> +#include <env.h> +#include <common.h> +#include <log.h> +#include <dm/device_compat.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/compat.h> +#include <linux/bitops.h> +#include <asm/io.h> +#include <i2c.h> +#include <watchdog.h> +#include <fdtdec.h> +#include <clk.h> +#include <reset.h> +#include <asm/arch/gpio.h> +#include <cpu_func.h> +#include <asm/system.h> +#include <asm/gpio.h> +#include <dm.h> +#include <dm/pinctrl.h> + +/* QUP Registers */ +#define QUP_CONFIG 0x000 +#define QUP_STATE 0x004 +#define QUP_IO_MODE 0x008 +#define QUP_SW_RESET 0x00c +#define QUP_OPERATIONAL 0x018 +#define QUP_ERROR_FLAGS 0x01c /* NOT USED */ +#define QUP_ERROR_FLAGS_EN 0x020 /* NOT USED */ +#define QUP_TEST_CTRL 0x024 /* NOT USED */ +#define QUP_OPERATIONAL_MASK 0x028 /* NOT USED */ +#define QUP_HW_VERSION 0x030 +#define QUP_MX_OUTPUT_CNT 0x100 +#define QUP_OUT_DEBUG 0x108 /* NOT USED */ +#define QUP_OUT_FIFO_CNT 0x10C /* NOT USED */ +#define QUP_OUT_FIFO_BASE 0x110 +#define QUP_MX_WRITE_CNT 0x150 +#define QUP_MX_INPUT_CNT 0x200 +#define QUP_MX_READ_CNT 0x208 +#define QUP_IN_READ_CUR 0x20C /* NOT USED */ +#define QUP_IN_DEBUG 0x210 /* NOT USED */ +#define QUP_IN_FIFO_CNT 0x214 /* NOT USED */ +#define QUP_IN_FIFO_BASE 0x218 +#define QUP_I2C_CLK_CTL 0x400 +#define QUP_I2C_STATUS 0x404 /* NOT USED */ +#define QUP_I2C_MASTER_GEN 0x408 +#define QUP_I2C_MASTER_BUS_CLR 0x40C /* NOT USED */ + +/* QUP States and reset values */ +#define QUP_RESET_STATE 0 +#define QUP_RUN_STATE 1 +#define QUP_PAUSE_STATE 3 +#define QUP_STATE_MASK 3 + +#define QUP_STATE_VALID BIT(2) +#define QUP_I2C_MAST_GEN BIT(4) +#define QUP_I2C_FLUSH BIT(6) + +#define QUP_OPERATIONAL_RESET 0x000ff0 +#define QUP_I2C_STATUS_RESET 0xfffffc + +/* QUP OPERATIONAL FLAGS */ +#define QUP_I2C_NACK_FLAG BIT(3) +#define QUP_OUT_NOT_EMPTY BIT(4) +#define QUP_IN_NOT_EMPTY BIT(5) +#define QUP_OUT_FULL BIT(6) +#define QUP_OUT_SVC_FLAG BIT(8) +#define QUP_IN_SVC_FLAG BIT(9) +#define QUP_MX_OUTPUT_DONE BIT(10) +#define QUP_MX_INPUT_DONE BIT(11) +#define OUT_BLOCK_WRITE_REQ BIT(12) +#define IN_BLOCK_READ_REQ BIT(13) + +/* + * QUP engine acting as I2C controller is referred to as + * I2C mini core, following are related macros. + */ +#define QUP_NO_OUTPUT BIT(6) +#define QUP_NO_INPUT BIT(7) +#define QUP_CLOCK_AUTO_GATE BIT(13) +#define QUP_I2C_MINI_CORE (2 << 8) +#define QUP_I2C_N_VAL_V2 7 + +/* Packing/Unpacking words in FIFOs, and IO modes */ +#define QUP_OUTPUT_BLK_MODE BIT(10) +#define QUP_OUTPUT_BAM_MODE (BIT(10) | BIT(11)) +#define QUP_INPUT_BLK_MODE BIT(12) +#define QUP_INPUT_BAM_MODE (BIT(12) | BIT(13)) +#define QUP_BAM_MODE (QUP_OUTPUT_BAM_MODE | QUP_INPUT_BAM_MODE) +#define QUP_BLK_MODE (QUP_OUTPUT_BLK_MODE | QUP_INPUT_BLK_MODE) +#define QUP_UNPACK_EN BIT(14) +#define QUP_PACK_EN BIT(15) + +#define QUP_REPACK_EN (QUP_UNPACK_EN | QUP_PACK_EN) +#define QUP_V2_TAGS_EN 1 + +#define QUP_OUTPUT_BLOCK_SIZE(x) (((x) >> 0) & 0x03) +#define QUP_OUTPUT_FIFO_SIZE(x) (((x) >> 2) & 0x07) +#define QUP_INPUT_BLOCK_SIZE(x) (((x) >> 5) & 0x03) +#define QUP_INPUT_FIFO_SIZE(x) (((x) >> 7) & 0x07) + +/* QUP v2 tags */ +#define QUP_TAG_V2_START 0x81 +#define QUP_TAG_V2_DATAWR 0x82 +#define QUP_TAG_V2_DATAWR_STOP 0x83 +#define QUP_TAG_V2_DATARD 0x85 +#define QUP_TAG_V2_DATARD_NACK 0x86 +#define QUP_TAG_V2_DATARD_STOP 0x87 + +#define QUP_I2C_MX_CONFIG_DURING_RUN BIT(31) + +/* Minimum transfer timeout for i2c transfers in micro seconds */ +#define TOUT_CNT (2 * 1000 * 1000) + +/* Default values. Use these if FW query fails */ +#define DEFAULT_CLK_FREQ I2C_SPEED_STANDARD_RATE +#define DEFAULT_SRC_CLK 19200000 + +/* + * Max tags length (start, stop and maximum 2 bytes address) for each QUP + * data transfer + */ +#define QUP_MAX_TAGS_LEN 4 +/* Max data length for each DATARD tags */ +#define RECV_MAX_DATA_LEN 254 +/* TAG length for DATA READ in RX FIFO */ +#define READ_RX_TAGS_LEN 2 + +struct qup_i2c_priv { + phys_addr_t base; + struct clk core; + struct clk iface; + u32 in_fifo_sz; + u32 out_fifo_sz; + u32 clk_ctl; + u32 config_run; +}; + +static inline u8 i2c_8bit_addr_from_msg(const struct i2c_msg *msg) +{ + return (msg->addr << 1) | (msg->flags & I2C_M_RD ? 1 : 0); +} + +static int qup_i2c_poll_state_mask(struct qup_i2c_priv *qup, + u32 req_state, u32 req_mask) +{ + int retries = 1; + u32 state; + + /* + * State transition takes 3 AHB clocks cycles + 3 I2C master clock + * cycles. So retry once after a 1uS delay. + */ + do { + state = readl(qup->base + QUP_STATE); + + if (state & QUP_STATE_VALID && + (state & req_mask) == req_state) + return 0; + + udelay(1); + } while (retries--); + + return -ETIMEDOUT; +} + +static int qup_i2c_poll_state(struct qup_i2c_priv *qup, u32 req_state) +{ + return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK); +} + +static int qup_i2c_poll_state_valid(struct qup_i2c_priv *qup) +{ + return qup_i2c_poll_state_mask(qup, 0, 0); +} + +static int qup_i2c_poll_state_i2c_master(struct qup_i2c_priv *qup) +{ + return qup_i2c_poll_state_mask(qup, QUP_I2C_MAST_GEN, QUP_I2C_MAST_GEN); +} + +static int qup_i2c_change_state(struct qup_i2c_priv *qup, u32 state) +{ + if (qup_i2c_poll_state_valid(qup) != 0) + return -EIO; + + writel(state, qup->base + QUP_STATE); + + if (qup_i2c_poll_state(qup, state) != 0) + return -EIO; + return 0; +} + +/* + * Function to check wheather Input or Output FIFO + * has data to be serviced + */ +static int qup_i2c_check_fifo_status(struct qup_i2c_priv *qup, u32 reg_addr, + u32 flags) +{ + unsigned long count = TOUT_CNT; + u32 val, status_flag; + int ret = 0; + + do { + val = readl(qup->base + reg_addr); + status_flag = val & flags; + + if (!count) { + printf("%s, timeout\n", __func__); + ret = -ETIMEDOUT; + break; + } + + count--; + udelay(1); + } while (!status_flag); + + return ret; +} + +/* + * Function to configure Input and Output enable/disable + */ +static void qup_i2c_enable_io_config(struct qup_i2c_priv *qup, u32 write_cnt, + u32 read_cnt) +{ + u32 qup_config = QUP_I2C_MINI_CORE | QUP_I2C_N_VAL_V2; + + writel(qup->config_run | write_cnt, qup->base + QUP_MX_WRITE_CNT); + + if (read_cnt) + writel(qup->config_run | read_cnt, qup->base + QUP_MX_READ_CNT); + else + qup_config |= QUP_NO_INPUT; + + writel(qup_config, qup->base + QUP_CONFIG); +} + +static unsigned int qup_i2c_read_word(struct qup_i2c_priv *qup) +{ + return readl(qup->base + QUP_IN_FIFO_BASE); +} + +static void qup_i2c_write_word(struct qup_i2c_priv *qup, u32 word) +{ + writel(word, qup->base + QUP_OUT_FIFO_BASE); +} + +static int qup_i2c_blsp_read(struct qup_i2c_priv *qup, unsigned int addr, + bool last, u8 *buffer, unsigned int bytes) +{ + unsigned int i, j, word; + int ret = 0; + + /* FIFO mode size limitation, for larger size implement block mode */ + if (bytes > (qup->in_fifo_sz - READ_RX_TAGS_LEN)) + return -EINVAL; + + qup_i2c_enable_io_config(qup, QUP_MAX_TAGS_LEN, + bytes + READ_RX_TAGS_LEN); + + if (last) + qup_i2c_write_word(qup, QUP_TAG_V2_START | addr << 8 | + QUP_TAG_V2_DATARD_STOP << 16 | + bytes << 24); + else + qup_i2c_write_word(qup, QUP_TAG_V2_START | addr << 8 | + QUP_TAG_V2_DATARD << 16 | bytes << 24); + + ret = qup_i2c_change_state(qup, QUP_RUN_STATE); + if (ret) + return ret; + + ret = qup_i2c_check_fifo_status(qup, QUP_OPERATIONAL, QUP_OUT_SVC_FLAG); + if (ret) + return ret; + writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL); + + ret = qup_i2c_check_fifo_status(qup, QUP_OPERATIONAL, QUP_IN_SVC_FLAG); + if (ret) + return ret; + writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL); + + word = qup_i2c_read_word(qup); + *(buffer++) = (word >> (8 * READ_RX_TAGS_LEN)) & 0xff; + if (bytes > 1) + *(buffer++) = (word >> (8 * (READ_RX_TAGS_LEN + 1))) & 0xff; + + for (i = 2; i < bytes; i += 4) { + word = qup_i2c_read_word(qup); + + for (j = 0; j < 4; j++) { + if ((i + j) == bytes) + break; + *buffer = (word >> (j * 8)) & 0xff; + buffer++; + } + } + + ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE); + return ret; +} + +static int qup_i2c_blsp_write(struct qup_i2c_priv *qup, unsigned int addr, + bool first, bool last, const u8 *buffer, + unsigned int bytes) +{ + unsigned int i; + u32 word = 0; + int ret = 0; + + /* FIFO mode size limitation, for larger size implement block mode */ + if (bytes > (qup->out_fifo_sz - QUP_MAX_TAGS_LEN)) + return -EINVAL; + + qup_i2c_enable_io_config(qup, bytes + QUP_MAX_TAGS_LEN, 0); + + if (first) { + ret = qup_i2c_change_state(qup, QUP_RUN_STATE); + if (ret) + return ret; + + writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL); + + ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE); + if (ret) + return ret; + } + + if (last) + qup_i2c_write_word(qup, QUP_TAG_V2_START | addr << 8 | + QUP_TAG_V2_DATAWR_STOP << 16 | + bytes << 24); + else + qup_i2c_write_word(qup, QUP_TAG_V2_START | addr << 8 | + QUP_TAG_V2_DATAWR << 16 | bytes << 24); + + for (i = 0; i < bytes; i++) { + /* Write the byte of data */ + word |= *buffer << ((i % 4) * 8); + if ((i % 4) == 3) { + qup_i2c_write_word(qup, word); + word = 0; + } + buffer++; + } + + if ((i % 4) != 0) + qup_i2c_write_word(qup, word); + + ret = qup_i2c_change_state(qup, QUP_RUN_STATE); + if (ret) + return ret; + + ret = qup_i2c_check_fifo_status(qup, QUP_OPERATIONAL, QUP_OUT_SVC_FLAG); + if (ret) + return ret; + writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL); + + ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE); + return ret; +} + +static void qup_i2c_conf_mode_v2(struct qup_i2c_priv *qup) +{ + u32 io_mode = QUP_REPACK_EN; + + writel(0, qup->base + QUP_MX_OUTPUT_CNT); + writel(0, qup->base + QUP_MX_INPUT_CNT); + + writel(io_mode, qup->base + QUP_IO_MODE); +} + +static int qup_i2c_xfer_v2(struct udevice *bus, struct i2c_msg msgs[], int num) +{ + struct qup_i2c_priv *qup = dev_get_priv(bus); + int ret, idx = 0; + u32 i2c_addr; + + writel(1, qup->base + QUP_SW_RESET); + ret = qup_i2c_poll_state(qup, QUP_RESET_STATE); + if (ret) + goto out; + + /* Configure QUP as I2C mini core */ + writel(QUP_I2C_MINI_CORE | QUP_I2C_N_VAL_V2 | QUP_NO_INPUT, + qup->base + QUP_CONFIG); + writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN); + + if (qup_i2c_poll_state_i2c_master(qup)) { + ret = -EIO; + goto out; + } + + qup_i2c_conf_mode_v2(qup); + + for (idx = 0; idx < num; idx++) { + struct i2c_msg *m = &msgs[idx]; + + qup->config_run = !idx ? 0 : QUP_I2C_MX_CONFIG_DURING_RUN; + i2c_addr = i2c_8bit_addr_from_msg(m); + + if (m->flags & I2C_M_RD) + ret = qup_i2c_blsp_read(qup, i2c_addr, idx == (num - 1), + m->buf, m->len); + else + ret = qup_i2c_blsp_write(qup, i2c_addr, idx == 0, + idx == (num - 1), m->buf, + m->len); + if (ret) + break; + } +out: + qup_i2c_change_state(qup, QUP_RESET_STATE); + return ret; +} + +static int qup_i2c_enable_clocks(struct udevice *dev, struct qup_i2c_priv *qup) +{ + int ret; + + ret = clk_enable(&qup->core); + if (ret) { + dev_err(dev, "clk_enable failed %d\n", ret); + return ret; + } + + ret = clk_enable(&qup->iface); + if (ret) { + dev_err(dev, "clk_enable failed %d\n", ret); + return ret; + } + + return 0; +} + +static int qup_i2c_probe(struct udevice *dev) +{ + static const int blk_sizes[] = {4, 16, 32}; + struct qup_i2c_priv *qup = dev_get_priv(dev); + u32 io_mode, hw_ver, size, size_idx; + int ret; + + qup->base = (phys_addr_t)dev_read_addr_ptr(dev); + if (!qup->base) + return -EINVAL; + + ret = clk_get_by_name(dev, "core", &qup->core); + if (ret) { + pr_err("clk_get_by_name(core) failed: %d\n", ret); + return ret; + } + ret = clk_get_by_name(dev, "iface", &qup->iface); + if (ret) { + pr_err("clk_get_by_name(iface) failed: %d\n", ret); + return ret; + } + qup_i2c_enable_clocks(dev, qup); + + writel(1, qup->base + QUP_SW_RESET); + ret = qup_i2c_poll_state_valid(qup); + if (ret) + return ret; + + hw_ver = readl(qup->base + QUP_HW_VERSION); + dev_dbg(dev, "Revision %x\n", hw_ver); + + io_mode = readl(qup->base + QUP_IO_MODE); + + /* + * The block/fifo size w.r.t. 'actual data' is 1/2 due to 'tag' + * associated with each byte written/received + */ + size_idx = QUP_OUTPUT_BLOCK_SIZE(io_mode); + if (size_idx >= ARRAY_SIZE(blk_sizes)) { + ret = -EIO; + return ret; + } + size = QUP_OUTPUT_FIFO_SIZE(io_mode); + qup->out_fifo_sz = blk_sizes[size_idx] * (2 << size); + + size_idx = QUP_INPUT_BLOCK_SIZE(io_mode); + if (size_idx >= ARRAY_SIZE(blk_sizes)) { + ret = -EIO; + return ret; + } + size = QUP_INPUT_FIFO_SIZE(io_mode); + qup->in_fifo_sz = blk_sizes[size_idx] * (2 << size); + + dev_dbg(dev, "IN:fifo:%d, OUT:fifo:%d\n", qup->in_fifo_sz, + qup->out_fifo_sz); + + return 0; +} + +static int qup_i2c_set_bus_speed(struct udevice *dev, unsigned int clk_freq) +{ + struct qup_i2c_priv *qup = dev_get_priv(dev); + unsigned int src_clk_freq; + int fs_div, hs_div; + + /* We support frequencies up to FAST Mode Plus (1MHz) */ + if (!clk_freq || clk_freq > I2C_SPEED_FAST_PLUS_RATE) { + dev_err(dev, "clock frequency not supported %d\n", clk_freq); + return -EINVAL; + } + + src_clk_freq = clk_get_rate(&qup->iface); + if ((int)src_clk_freq < 0) { + src_clk_freq = DEFAULT_SRC_CLK; + dev_dbg(dev, "using default core freq %d\n", src_clk_freq); + } + + dev_dbg(dev, "src_clk_freq %u\n", src_clk_freq); + dev_dbg(dev, "clk_freq %u\n", clk_freq); + + hs_div = 3; + if (clk_freq <= I2C_SPEED_STANDARD_RATE) { + fs_div = ((src_clk_freq / clk_freq) / 2) - 3; + qup->clk_ctl = (hs_div << 8) | (fs_div & 0xff); + } else { + /* 33%/66% duty cycle */ + fs_div = ((src_clk_freq / clk_freq) - 6) * 2 / 3; + qup->clk_ctl = ((fs_div / 2) << 16) | (hs_div << 8) | (fs_div & 0xff); + } + + dev_dbg(dev, "clk_ctl %u\n", qup->clk_ctl); + + return 0; +} + +/* Probe to see if a chip is present. */ +static int qup_i2c_probe_chip(struct udevice *dev, uint chip_addr, + uint chip_flags) +{ + struct qup_i2c_priv *qup = dev_get_priv(dev); + u32 hw_ver = readl(qup->base + QUP_HW_VERSION); + + return hw_ver ? 0 : -1; +} + +static const struct dm_i2c_ops qup_i2c_ops = { + .xfer = qup_i2c_xfer_v2, + .probe_chip = qup_i2c_probe_chip, + .set_bus_speed = qup_i2c_set_bus_speed, +}; + +/* + * Currently this driver only supports v2.x of QUP I2C controller, hence + * functions above are named with a _v2 suffix. So when we have the + * v1.1.1 support added as per the Linux counterpart then it should be easy + * to add corresponding functions named with a _v1 suffix. + */ +static const struct udevice_id qup_i2c_ids[] = { + { .compatible = "qcom,i2c-qup-v2.1.1" }, + { .compatible = "qcom,i2c-qup-v2.2.1" }, + {} +}; + +U_BOOT_DRIVER(i2c_qup) = { + .name = "i2c_qup", + .id = UCLASS_I2C, + .of_match = qup_i2c_ids, + .probe = qup_i2c_probe, + .priv_auto = sizeof(struct qup_i2c_priv), + .ops = &qup_i2c_ops, +}; diff --git a/drivers/i2c/sh_i2c.c b/drivers/i2c/sh_i2c.c index 6cecec4145..3335d9482a 100644 --- a/drivers/i2c/sh_i2c.c +++ b/drivers/i2c/sh_i2c.c @@ -172,14 +172,9 @@ static int sh_i2c_raw_read(struct sh_i2c *dev, u8 chip, u8 addr) { int ret = -1; -#if defined(CONFIG_SH73A0) - if (sh_i2c_set_addr(dev, chip, addr, 0) != 0) - goto exit0; -#else if (sh_i2c_set_addr(dev, chip, addr, 1) != 0) goto exit0; udelay(100); -#endif writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS|SH_I2C_ICCR_BUSY), &dev->iccr); sh_irq_dte(dev); |