|  | /* | 
|  | * Copyright (c) 2022 Andes Technology Corporation | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | /** | 
|  | * @file I2C driver for AndesTech atciic100 IP | 
|  | */ | 
|  | #include <errno.h> | 
|  | #include <zephyr/kernel.h> | 
|  | #include <zephyr/device.h> | 
|  | #include <zephyr/drivers/i2c.h> | 
|  | #include <zephyr/sys/util.h> | 
|  | #include <zephyr/sys/sys_io.h> | 
|  |  | 
|  | #define I2C_MAX_COUNT		256 | 
|  | #define BURST_CMD_COUNT		1 | 
|  |  | 
|  | #define RED_IDR			0x00 | 
|  | #define REG_CFG			0x10 | 
|  | #define REG_INTE		0x14 | 
|  | #define REG_STAT		0x18 | 
|  | #define REG_ADDR		0x1C | 
|  | #define REG_DATA		0x20 | 
|  | #define REG_CTRL		0x24 | 
|  | #define REG_CMD			0x28 | 
|  | #define REG_SET			0x2C | 
|  |  | 
|  | #define I2C_BASE(dev) \ | 
|  | ((const struct i2c_atciic100_config * const)(dev)->config)->base | 
|  |  | 
|  | #define I2C_CFG(dev)	(I2C_BASE(dev) + REG_CFG) | 
|  | #define I2C_INTE(dev)	(I2C_BASE(dev) + REG_INTE) | 
|  | #define I2C_STAT(dev)	(I2C_BASE(dev) + REG_STAT) | 
|  | #define I2C_ADDR(dev)	(I2C_BASE(dev) + REG_ADDR) | 
|  | #define I2C_CMD(dev)	(I2C_BASE(dev) + REG_CMD) | 
|  | #define I2C_SET(dev)	(I2C_BASE(dev) + REG_SET) | 
|  | #define I2C_DATA(dev)	(I2C_BASE(dev) + REG_DATA) | 
|  | #define I2C_CTRL(dev)	(I2C_BASE(dev) + REG_CTRL) | 
|  |  | 
|  | #define TARGET_ADDR_MSK			BIT_MASK(10) | 
|  | #define DATA_MSK			BIT_MASK(8) | 
|  |  | 
|  | /* Interrupt Enable Register(RW) */ | 
|  | #define IEN_ALL				BIT_MASK(10) | 
|  | #define IEN_CMPL			BIT(9) | 
|  | #define IEN_BYTE_RECV			BIT(8) | 
|  | #define IEN_BYTE_TRANS			BIT(7) | 
|  | #define IEN_START			BIT(6) | 
|  | #define IEN_STOP			BIT(5) | 
|  | #define IEN_ARB_LOSE			BIT(4) | 
|  | #define IEN_ADDR_HIT			BIT(3) | 
|  | #define IEN_FIFO_HALF			BIT(2) | 
|  | #define IEN_FIFO_FULL			BIT(1) | 
|  | #define IEN_FIFO_EMPTY			BIT(0) | 
|  |  | 
|  | /* Status Register(RW) */ | 
|  | #define STATUS_W1C_ALL			(BIT_MASK(7) << 3) | 
|  | #define STATUS_LINE_SDA			BIT(14) | 
|  | #define STATUS_LINE_SCL			BIT(13) | 
|  | #define STATUS_GEN_CALL			BIT(12) | 
|  | #define STATUS_BUS_BUSY			BIT(11) | 
|  | #define STATUS_ACK			BIT(10) | 
|  | #define STATUS_CMPL			BIT(9) | 
|  | #define STATUS_BYTE_RECV		BIT(8) | 
|  | #define STATUS_BYTE_TRANS		BIT(7) | 
|  | #define STATUS_START			BIT(6) | 
|  | #define STATUS_STOP			BIT(5) | 
|  | #define STATUS_ARB_LOSE			BIT(4) | 
|  | #define STATUS_ADDR_HIT			BIT(3) | 
|  | #define STATUS_FIFO_HALF		BIT(2) | 
|  | #define STATUS_FIFO_FULL		BIT(1) | 
|  | #define STATUS_FIFO_EMPTY		BIT(0) | 
|  |  | 
|  | /* Control Register(RW) */ | 
|  | #define CTRL_PHASE_START		BIT(12) | 
|  | #define CTRL_PHASE_ADDR			BIT(11) | 
|  | #define CTRL_PHASE_DATA			BIT(10) | 
|  | #define CTRL_PHASE_STOP			BIT(9) | 
|  | #define CTRL_DIR			BIT(8) | 
|  | #define CTRL_DATA_COUNT			BIT_MASK(8) | 
|  |  | 
|  | /* Command Register(RW) */ | 
|  | #define CMD_MSK				BIT_MASK(3) | 
|  | #define CMD_NO_ACT			(0x0) | 
|  | #define CMD_ISSUE_TRANSACTION		(0x1) | 
|  | #define CMD_ACK				(0x2) | 
|  | #define CMD_NACK			(0x3) | 
|  | #define CMD_CLEAR_FIFO			(0x4) | 
|  | #define CMD_RESET_I2C			(0x5) | 
|  |  | 
|  | /* Setup Register(RW) */ | 
|  | #define SETUP_T_SUDAT			(BIT_MASK(5) << 24) | 
|  | #define SETUP_T_SP			(BIT_MASK(3) << 21) | 
|  | #define SETUP_T_HDDAT			(BIT_MASK(5) << 16) | 
|  | #define SETUP_T_SCL_RATIO		BIT(13) | 
|  | #define SETUP_T_SCLHI			(BIT_MASK(9) << 4) | 
|  | #define SETUP_DMA_EN			BIT(3) | 
|  | #define SETUP_CONTROLLER		BIT(2) | 
|  | #define SETUP_ADDRESSING		BIT(1) | 
|  | #define SETUP_I2C_EN			BIT(0) | 
|  |  | 
|  | #if CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC == 30000000 | 
|  |  | 
|  | #define SETUP_T_SUDAT_STD		(0x3) | 
|  | #define SETUP_T_SP_STD			(0x1) | 
|  | #define SETUP_T_HDDAT_STD		(5) | 
|  | #define SETUP_T_SCL_RATIO_STD		(0x0) | 
|  | #define SETUP_T_SCLHI_STD		(138) | 
|  |  | 
|  | #define SETUP_T_SUDAT_FAST		(0x0) | 
|  | #define SETUP_T_SP_FAST			(0x1) | 
|  | #define SETUP_T_HDDAT_FAST		(5) | 
|  | #define SETUP_T_SCL_RATIO_FAST		(0x1) | 
|  | #define SETUP_T_SCLHI_FAST		(18) | 
|  |  | 
|  | #define SETUP_T_SUDAT_FAST_P		(0x0) | 
|  | #define SETUP_T_SP_FAST_P		(0x1) | 
|  | #define SETUP_T_HDDAT_FAST_P		(0x0) | 
|  | #define SETUP_T_SCL_RATIO_FAST_P	(0x1) | 
|  | #define SETUP_T_SCLHI_FAST_P		(6) | 
|  |  | 
|  | #elif CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC == 40000000 | 
|  |  | 
|  | #define SETUP_T_SUDAT_STD		(0x4) | 
|  | #define SETUP_T_SP_STD			(0x2) | 
|  | #define SETUP_T_HDDAT_STD		(0x6) | 
|  | #define SETUP_T_SCL_RATIO_STD		(0x0) | 
|  | #define SETUP_T_SCLHI_STD		(182) | 
|  |  | 
|  | #define SETUP_T_SUDAT_FAST		(0x0) | 
|  | #define SETUP_T_SP_FAST			(0x2) | 
|  | #define SETUP_T_HDDAT_FAST		(0x6) | 
|  | #define SETUP_T_SCL_RATIO_FAST		(0x1) | 
|  | #define SETUP_T_SCLHI_FAST		(23) | 
|  |  | 
|  | #define SETUP_T_SUDAT_FAST_P		(0x0) | 
|  | #define SETUP_T_SP_FAST_P		(0x2) | 
|  | #define SETUP_T_HDDAT_FAST_P		(0x0) | 
|  | #define SETUP_T_SCL_RATIO_FAST_P	(0x1) | 
|  | #define SETUP_T_SCLHI_FAST_P		(7) | 
|  |  | 
|  | #else | 
|  |  | 
|  | #define SETUP_T_SUDAT_STD		(0x9) | 
|  | #define SETUP_T_SP_STD			(0x3) | 
|  | #define SETUP_T_HDDAT_STD		(12) | 
|  | #define SETUP_T_SCL_RATIO_STD		(0x0) | 
|  | #define SETUP_T_SCLHI_STD		(287) | 
|  |  | 
|  | #define SETUP_T_SUDAT_FAST		(0x0) | 
|  | #define SETUP_T_SP_FAST			(0x3) | 
|  | #define SETUP_T_HDDAT_FAST		(12) | 
|  | #define SETUP_T_SCL_RATIO_FAST		(0x1) | 
|  | #define SETUP_T_SCLHI_FAST		(38) | 
|  |  | 
|  | #define SETUP_T_SUDAT_FAST_P		(0x0) | 
|  | #define SETUP_T_SP_FAST_P		(0x3) | 
|  | #define SETUP_T_HDDAT_FAST_P		(0x0) | 
|  | #define SETUP_T_SCL_RATIO_FAST_P	(0x1) | 
|  | #define SETUP_T_SCLHI_FAST_P		(13) | 
|  |  | 
|  | #endif | 
|  |  | 
|  | #define SETUP_SPEED_MSK			(SETUP_T_SUDAT		| \ | 
|  | SETUP_T_SP		| \ | 
|  | SETUP_T_HDDAT		| \ | 
|  | SETUP_T_SCL_RATIO	| \ | 
|  | SETUP_T_SCLHI) | 
|  |  | 
|  | #define SETUP_SPEED_STD			((SETUP_T_SUDAT_STD << 24)	| \ | 
|  | (SETUP_T_SP_STD  << 21)		| \ | 
|  | (SETUP_T_HDDAT_STD << 16)	| \ | 
|  | (SETUP_T_SCL_RATIO_STD << 13)	| \ | 
|  | (SETUP_T_SCLHI_STD << 4)) | 
|  |  | 
|  | #define SETUP_SPEED_FAST		((SETUP_T_SUDAT_FAST << 24)	| \ | 
|  | (SETUP_T_SP_FAST  << 21)	| \ | 
|  | (SETUP_T_HDDAT_FAST << 16)	| \ | 
|  | (SETUP_T_SCL_RATIO_FAST << 13)	| \ | 
|  | (SETUP_T_SCLHI_FAST << 4)) | 
|  |  | 
|  | #define SETUP_SPEED_FAST_PLUS		((SETUP_T_SUDAT_FAST_P << 24)	| \ | 
|  | (SETUP_T_SP_FAST_P  << 21)	| \ | 
|  | (SETUP_T_HDDAT_FAST_P << 16)	| \ | 
|  | (SETUP_T_SCL_RATIO_FAST_P << 13)| \ | 
|  | (SETUP_T_SCLHI_FAST_P << 4)) | 
|  |  | 
|  | #define MAX_XFER_SZ			(256) | 
|  |  | 
|  | enum _i2c_ctrl_reg_item_dir { | 
|  | I2C_CONTROLLER_TX = 0x0, | 
|  | I2C_CONTROLLER_RX = 0x1, | 
|  | I2C_TARGET_TX = 0x1, | 
|  | I2C_TARGET_RX = 0x0, | 
|  | }; | 
|  |  | 
|  | /* I2C driver running state */ | 
|  | enum _i2c_driver_state { | 
|  | I2C_DRV_NONE = 0x0, | 
|  | I2C_DRV_INIT = BIT(0), | 
|  | I2C_DRV_POWER = BIT(1), | 
|  | I2C_DRV_CFG_PARAM = BIT(2), | 
|  | I2C_DRV_CONTROLLER_TX = BIT(3), | 
|  | I2C_DRV_CONTROLLER_RX = BIT(4), | 
|  | I2C_DRV_TARGET_TX = BIT(5), | 
|  | I2C_DRV_TARGET_RX = BIT(6), | 
|  | I2C_DRV_CONTROLLER_TX_CMPL = BIT(7), | 
|  | I2C_DRV_CONTROLLER_RX_CMPL = BIT(8), | 
|  | I2C_DRV_TARGET_TX_CMPL = BIT(9), | 
|  | I2C_DRV_TARGET_RX_CMPL = BIT(10), | 
|  | }; | 
|  |  | 
|  | /* brief I2C Status */ | 
|  | struct _i2c_status { | 
|  | /* /< Mode: 0=Slave, 1=Master */ | 
|  | uint32_t mode:1; | 
|  | uint32_t general_call: 1; | 
|  | uint32_t arbitration_lost : 1; | 
|  | uint32_t target_ack       : 1; | 
|  | }; | 
|  |  | 
|  | struct i2c_atciic100_dev_data_t { | 
|  | struct k_sem			bus_lock; | 
|  | struct k_sem			device_sync_sem; | 
|  | volatile uint32_t		driver_state; | 
|  | uint8_t				*middleware_rx_buf; | 
|  | uint8_t				*middleware_tx_buf; | 
|  | uint32_t			fifo_depth; | 
|  | uint32_t			target_addr; | 
|  | uint32_t			xfer_wt_num; | 
|  | uint32_t			xfer_rd_num; | 
|  | uint32_t			xfered_data_wt_ptr; /* write pointer  */ | 
|  | uint32_t			xfered_data_rd_ptr; /* read pointer  */ | 
|  | volatile struct _i2c_status	status; | 
|  | const struct i2c_target_callbacks	*target_callbacks; | 
|  | struct i2c_target_config	*target_config; | 
|  | }; |