linux i2c 驱动二 IIC控制器

目录

i2c模块框图 ug-1085(ch22)

2、控制器和从设备的设备树

 3、查看i2c控制器驱动注册流程:  标准的平台驱动框架

从设备读取温度接口:

读写实质: 最终就是通过client中的adapter->algo读写


基于zynqmp iic控制器

i2c模块框图 ug-1085(ch22)

(a)有两条i2c总线 i2c0 i2c1中断id 49 50; CPU通过APB总线访问i2c控制器 ,i2c控制器通过scl和sda链接外部设备;

(b)中断id: ug-1085(13)中断控制器是 GIC

 

(c)寄存器和数据流向框图

 Cpu通过APB总线访问i2c总线上挂载的外设,通过四个寄存器(控制寄存器、 发送数据寄存器、接收数据寄存器、状态寄存器)控制i2c控制器和外设(从设备)通信;

这些寄存器对应的地址(ug1087) 

 上述这些寄存器一般都在控制器发生传输初始化时候使用,后面控制器驱动程序中会用到;

2、控制器和从设备的设备树

pd_i2c1: pd-i2c1 {
		#power-domain-cells = <0x0>;
		pd-id = <0x26>;
};
i2c1: i2c@ff030000 {
			compatible = "cdns,i2c-r1p14", "cdns,i2c-r1p10";  /* 匹配控制器驱动 */
			status = "okay";						/* 表示本节点是否生效 */
			clock-frequency = <100000>;				/* scl时钟*/	
			interrupt-parent = <&gic>;				/*父中断是gic中断控制器*/
			interrupts = <0 18 4>;					/* 中断号 18  高电平*/
			reg = <0x0 0xff030000 0x0 0x1000>;       /* i2c基地址 */
			#address-cells = <1>;		
			#size-cells = <0>;
			power-domains = <&pd_i2c1>;
            
            tmp401: tmp401@4c { /* u23 */
                compatible = "ti,tmp401";
                reg = <0x4c>;
            };
};

根据设备树搜索源码: grep “cdns,i2c-r1p” -r | grep -v “dts” 

 3、查看i2c控制器驱动注册流程:  标准的平台驱动框架

 匹配后执行cdns_i2c_probe函数;

probe中需要做的几件事:

  1. 获取设备树资源并使用这些资源初始化i2c寄存器(控制、发送、接收、状态、中断);
  2. 构建一个i2c_adapter,并初始化必须实现成员algo的方法
    1. id->adap.algo = &cdns_i2c_algo;
    2. master_xfer functionality
  3. 初始化时钟注册中断(因为中断用来收发数据);
    1.  devm_request_irq(&pdev->dev, id->irq, cdns_i2c_isr, 0,DRIVER_NAME, id);
  4. 初始化并向总线注册一个适配器;    i2c_add_adapter(&id->adap);

 分析probe函数:

static int cdns_i2c_probe(struct platform_device *pdev)
{
	struct resource *r_mem;
	struct cdns_i2c *id;
	int ret;
	const struct of_device_id *match;
/* 给struct cdns_i2c 申请空间 内部包含适配器等其他资源 */
	id = devm_kzalloc(&pdev->dev, sizeof(*id), GFP_KERNEL); 
	id->dev = &pdev->dev;        			        /* 保存平台设备 */
	platform_set_drvdata(pdev, id); 	            /* 保存struct cdns_i2c到驱动数据 */		
	match = of_match_node(cdns_i2c_of_match, pdev->dev.of_node);
	if (match && match->data) {
		const struct cdns_platform_data *data = match->data;
		id->quirks = data->quirks;                  //  0
	}

	id->pinctrl = devm_pinctrl_get(&pdev->dev);  
	if (!IS_ERR(id->pinctrl)) {
		ret = cdns_i2c_init_recovery_info(id, pdev);
		if (ret)
			return ret;
	}
/* 从设备树获取基地址 */
	r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	id->membase = devm_ioremap_resource(&pdev->dev, r_mem);
	if (IS_ERR(id->membase))
		return PTR_ERR(id->membase);
/* 获取中断号 */
	id->irq = platform_get_irq(pdev, 0);
/* 初始化适配器 */
	id->adap.owner = THIS_MODULE;
	id->adap.dev.of_node = pdev->dev.of_node;
	id->adap.algo = &cdns_i2c_algo;
	id->adap.timeout = CDNS_I2C_TIMEOUT;
	id->adap.retries = 3;		/* Default retry value. */
	id->adap.algo_data = id;
	id->adap.dev.parent = &pdev->dev;
	init_completion(&id->xfer_done);
	snprintf(id->adap.name, sizeof(id->adap.name), 
"Cadence I2C at %08lx", (unsigned long)r_mem->start);
	id->clk = devm_clk_get(&pdev->dev, NULL);
	ret = clk_prepare_enable(id->clk);
	pm_runtime_set_autosuspend_delay(id->dev, CNDS_I2C_PM_TIMEOUT);
	pm_runtime_use_autosuspend(id->dev);
	pm_runtime_set_active(id->dev);
	pm_runtime_enable(id->dev);
	id->clk_rate_change_nb.notifier_call = cdns_i2c_clk_notifier_cb;
	ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
			&id->i2c_clk);
	if (ret || (id->i2c_clk > CDNS_I2C_SPEED_MAX))
		id->i2c_clk = CDNS_I2C_SPEED_DEFAULT;
/* 是指控制寄存器状态 使能ack  7位传输 master模式 */
	id->ctrl_reg = CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS;
/* 设置时钟 */
	ret = cdns_i2c_setclk(id->input_clk, id);
/* 注册中断 */
	ret = devm_request_irq(&pdev->dev, id->irq, cdns_i2c_isr, 0,DRIVER_NAME, id);
/* 设置超时时间 把id->ctrl_reg 写入寄存器	*/
	cdns_i2c_init(id); 
/* 注册适配器 */ 
	ret = i2c_add_adapter(&id->adap);
	if (ret < 0)
		goto err_clk_dis;

	dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n",
		 id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq);

	return 0;
}

主要看下cdns_i2c_algo 和中断处理函数 cdns_i2c_isr:

static const struct i2c_algorithm cdns_i2c_algo = {

        .master_xfer = cdns_i2c_master_xfer,          //i2c-core-base.c中__i2c_transfer会调用

        .functionality = cdns_i2c_func,                      //是能够master_xfer接口能够支持的iic驱动种类

};

master_xfer都是在读写接口中调用,被核心层封装在了__i2c_transfer中如下:

 zynqmp中cdns_i2c_master_xfer的实现:

这个函数中就可以看到对寄存器的一些操作,控制寄存器 状态寄存器等

static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num){
	int ret, count;
	u32 reg;
	struct cdns_i2c *id = adap->algo_data;
	bool hold_quirk;
	ret = pm_runtime_get_sync(id->dev);
	/* CDNS_I2C_SR_OFFSET = 0x04; 读取0x4状态寄存器 CDNS_I2C_SR_BA: bit 8 总线正在传输中 */
	if (msgs->len)
		if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA) { //总线正在传输中的话直接返回
			ret = -EAGAIN;
			goto out;
		}

	hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT);     //重复标志
	/* Set the flag to one when multiple messages are to be	 * processed with a repeated start.	 */
	if (num > 1) {   //发送多条消息分支
		for (count = 0; (count < num - 1 && hold_quirk); count++) {
			if (msgs[count].flags & I2C_M_RD) {
				dev_warn(adap->dev.parent,
					 "Can't do repeated start after a receive message\n");
				ret = -EOPNOTSUPP;
				goto out;
			}
		}
		id->bus_hold_flag = 1;
		reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
		reg |= CDNS_I2C_CR_HOLD;
		cdns_i2c_writereg(reg, CDNS_I2C_CR_OFFSET);	// 控制寄存器置位bit 4 
	} else {     //发送单个
		id->bus_hold_flag = 0;
	}
	/* Process the msg one by one */
	for (count = 0; count < num; count++, msgs++) {
		if (count == (num - 1))					//当最后一次发送的时候释放标志位;释放sclk
			id->bus_hold_flag = 0;
		ret = cdns_i2c_process_msg(id, msgs, adap);		//发送消息
		/* Report the other error interrupts to application */
		if (id->err_status) {
			cdns_i2c_master_reset(adap);		//如果发送消息过程中出现了错误则复位,后面看如何复位
			if (id->err_status & CDNS_I2C_IXR_NACK) {
				ret = -ENXIO;
				goto out;
			}
			ret = -EIO;
			goto out;
		}
	}
	ret = num;
out:
	pm_runtime_mark_last_busy(id->dev);
	pm_runtime_put_autosuspend(id->dev);
	return ret;
}

循环当中调用的就是cdns_i2c_process_msg来发送数据:   在这个函数中可以看到主要是读取状态区分读写 和 地址位宽

static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
		struct i2c_adapter *adap)
{
	unsigned long time_left;
	u32 reg;
	id->p_msg = msg;                           //保存了要发送的消息到struct cdns_i2c 结构体
	id->err_status = 0;
	reinit_completion(&id->xfer_done);                  //把id->xfer_done设置为0
	/* Check for the TEN Bit mode on each msg */
	reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);  		//读取控制寄存器 0x00
	if (msg->flags & I2C_M_TEN) {					    //10位地址
		if (reg & CDNS_I2C_CR_NEA)				
			cdns_i2c_writereg(reg & ~CDNS_I2C_CR_NEA,
					CDNS_I2C_CR_OFFSET);
	} else {								            //7位地址  
		if (!(reg & CDNS_I2C_CR_NEA))
			cdns_i2c_writereg(reg | CDNS_I2C_CR_NEA,
					CDNS_I2C_CR_OFFSET);
	}
	/* Check for zero length - Slave monitor mode */
	if (msg->len == 0)
		cdns_i2c_slvmon(id);
	 /* Check for the R/W flag on each msg */
	else if (msg->flags & I2C_M_RD)		               //主机读取从设备的话 I2C_M_RD= 1;
		cdns_i2c_mrecv(id);	                           //接收数据	
	else
		cdns_i2c_msend(id);		                       //发送数据
	/* Wait for the signal of completion */
	time_left = wait_for_completion_timeout(&id->xfer_done, adap->timeout); //等待id->xfer_done 置位
	if (time_left == 0) {
		i2c_recover_bus(adap);
		cdns_i2c_master_reset(adap);
		dev_err(id->adap.dev.parent, "timeout waiting on completion\n");
		return -ETIMEDOUT;
	}
	cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK,  CDNS_I2C_IDR_OFFSET);
	/* If it is bus arbitration error, try again */
	if (id->err_status & CDNS_I2C_IXR_ARB_LOST)
		return -EAGAIN;
	return 0;
}

cdns_i2c_mrecv: 一路下来终于到了接收数据的地方 (做了一下删减)

 使能中断cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);

static void cdns_i2c_mrecv(struct cdns_i2c *id)
{
	unsigned int ctrl_reg;
	unsigned int isr_status;
	id->p_recv_buf = id->p_msg->buf;		//保存
	id->recv_count = id->p_msg->len;
	/* Put the controller in master receive mode and clear the FIFO */
	ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
	ctrl_reg |= CDNS_I2C_CR_RW | CDNS_I2C_CR_CLR_FIFO;
	if (id->p_msg->flags & I2C_M_RECV_LEN)
		id->recv_count = I2C_SMBUS_BLOCK_MAX + 1;
	id->curr_recv_count = id->recv_count;
检查iic中接收数据的长度比fifo的深度大,需要多次传输;
	if (id->recv_count > CDNS_I2C_FIFO_DEPTH)  	ctrl_reg |= CDNS_I2C_CR_HOLD;
	cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
	//清除中断状态寄存器中的中断: 0x10
	isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
	cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
	if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {   //传输大小判断 0x14寄存器
		cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,  CDNS_I2C_XFER_SIZE_OFFSET);
		id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
	} else { 		cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);	}
//中断使能 bit[ 0 1 2 5 6 7 9]置位  0x24中断使能寄存器
	cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
//从设备地址 写入到 0x08  IIC地址寄存器
	cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK, CDNS_I2C_ADDR_OFFSET);
	/* Clear the bus hold flag if bytes to receive is less than FIFO size */
	if (!id->bus_hold_flag && ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&         
             (id->recv_count <= CDNS_I2C_FIFO_DEPTH))
			cdns_i2c_clear_bus_hold(id);
 }

看完这个函数 发现cdns_i2c_mrecv中没有对数据寄存器(0x0C)操作怎么读取数据?? cdns_i2c_process_msg里它使能了中断又等待id->xfer_done置位;搜索下就知道是在中断中传输的数据;中断的处理函数在probe中已经注册好了,还没有分析;

分析中断处理函数:中断函数最后对id->xfer_done做了置位; cdns_i2c_process_msg中等待判断这个标识置位

cdns_i2c_isr中断处理函数:
static irqreturn_t cdns_i2c_isr(int irq, void *ptr){
	cdns_i2c_master_isr(ptr);
	return IRQ_HANDLED;
}
static irqreturn_t cdns_i2c_master_isr(void *ptr)  //最终对i2c控制寄存器操作的函数
{
	unsigned int isr_status, avail_bytes, updatetx;
	unsigned int bytes_to_send;
	bool hold_quirk;
	struct cdns_i2c *id = ptr;
	/* Signal completion only after everything is updated */
	int done_flag = 0;
	irqreturn_t status = IRQ_NONE;
/* 读取中断状态,清空中断状态 */
	isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
	cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
/* 检测中断状态 nack表示从机响应,或者主机正在仲裁,直接返回*/
	if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) {
		done_flag = 1; 		status = IRQ_HANDLED;
	}
	updatetx = 0;
	if (id->recv_count > id->curr_recv_count)
		updatetx = 1;

	hold_quirk = (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT) && updatetx;

	/* When receiving, handle data interrupt and completion interrupt */
	if (id->p_recv_buf &&
	    ((isr_status & CDNS_I2C_IXR_COMP) ||
	     (isr_status & CDNS_I2C_IXR_DATA))) {
		/* 读取数据  先读取状态寄存器 为读取数据有效 fifo深度*/
		while(cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_RXDV) {
			if((id->recv_count<CDNS_I2C_FIFO_DEPTH)&&!id->bus_hold_flag)
				cdns_i2c_clear_bus_hold(id);
/* 读取数据寄存器填充到 p_recv_buf中 */
			*(id->p_recv_buf)++ = cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
			id->recv_count--;
			id->curr_recv_count--;
			if (cdns_is_holdquirk(id, hold_quirk)) 	break;
		}
/*大型数据传输*/
		if (cdns_is_holdquirk(id, hold_quirk)) {
			/* wait while fifo is full */
			while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
			       (id->curr_recv_count - CDNS_I2C_FIFO_DEPTH));
				if(((int)(id->recv_count)-CDNS_I2C_FIFO_DEPTH) >
CDNS_I2C_TRANSFER_SIZE){
				cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
						  CDNS_I2C_XFER_SIZE_OFFSET);
				id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE +
						      CDNS_I2C_FIFO_DEPTH;
			} else {
				cdns_i2c_writereg(id->recv_count -
						  CDNS_I2C_FIFO_DEPTH,
						  CDNS_I2C_XFER_SIZE_OFFSET);
				id->curr_recv_count = id->recv_count;
			}
		} else if (id->recv_count && !hold_quirk &&
						!id->curr_recv_count) {

			/* Set the slave address in address register*/
			cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
						CDNS_I2C_ADDR_OFFSET);

			if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {
				cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
						CDNS_I2C_XFER_SIZE_OFFSET);
				id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
			} else {
				cdns_i2c_writereg(id->recv_count,
						CDNS_I2C_XFER_SIZE_OFFSET);
				id->curr_recv_count = id->recv_count;
			}
		}

		/* Clear hold (if not repeated start) and signal completion */
		if ((isr_status & CDNS_I2C_IXR_COMP) && !id->recv_count) {
			if (!id->bus_hold_flag)
				cdns_i2c_clear_bus_hold(id);
			done_flag = 1;
		}
		status = IRQ_HANDLED;
	}

	/* When sending, handle transfer complete interrupt */
	if ((isr_status & CDNS_I2C_IXR_COMP) && !id->p_recv_buf) {
		if (id->send_count) {
			avail_bytes = CDNS_I2C_FIFO_DEPTH -
			    cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
			if (id->send_count > avail_bytes)
				bytes_to_send = avail_bytes;
			else
				bytes_to_send = id->send_count;
			while (bytes_to_send--) {
				cdns_i2c_writereg(
					(*(id->p_send_buf)++),
					 CDNS_I2C_DATA_OFFSET);
				id->send_count--;
			}
		} else {
			done_flag = 1;
		}
		if (!id->send_count && !id->bus_hold_flag)
			cdns_i2c_clear_bus_hold(id);
		status = IRQ_HANDLED;
	}
	/* Handling Slave monitor mode interrupt */
	if (isr_status & CDNS_I2C_IXR_SLV_RDY) {
		unsigned int ctrl_reg;
		/* Read control register */
		ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
		/* Disable slave monitor mode */
		ctrl_reg &= ~CDNS_I2C_CR_SLVMON;
		cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
		/* Clear interrupt flag for slvmon mode */
		cdns_i2c_writereg(CDNS_I2C_IXR_SLV_RDY, CDNS_I2C_IDR_OFFSET);
		done_flag = 1;
		status = IRQ_HANDLED;
	}
/* 保存错误标识,在cdns_i2c_process_msg中判断处理 */
	id->err_status = isr_status & CDNS_I2C_IXR_ERR_INTR_MASK;
	if (id->err_status)
		status = IRQ_HANDLED;
/*对数据处理完成 cdns_i2c_process_msg中等待判断这个标识置位 */
	if (done_flag)
		complete(&id->xfer_done);
	return status;
}

流程理一下; 

cdns_i2c_probe         通过设备树匹配到probe

        获取设备树资源(终端号,i2c基地址  时钟等等);

        初始化adapter 结构

        初始化alogrithm  id->adap.algo = &cdns_i2c_algo;

        注册中断

        注册adapter

设备驱动呢怎么使用adapter 和 alogrithm?

简单看个例子:

static const struct i2c_device_id tmp401_id[] = {
	{ "tmp401", tmp401 },
	{ "tmp411", tmp411 },
};

static struct i2c_driver tmp401_driver = {
	.class		= I2C_CLASS_HWMON,
	.driver = {
		.name	= "tmp401",
		.of_match_table = of_match_ptr(tmp401_of_match),
	},
	.probe		= tmp401_probe,
	.id_table	= tmp401_id,
	.detect		= tmp401_detect,
	.address_list	= normal_i2c,
};

匹配后执行: static int tmp401_probe(struct i2c_client *client,  const struct i2c_device_id *id)

struct i2c_client {
    unsigned short flags;        /* div., see below        */
    unsigned short addr;        /* chip address - NOTE: 7bit    */
                    /* addresses are stored in the    */
                    /* _LOWER_ 7 bits        */
    char name[I2C_NAME_SIZE];
    struct i2c_adapter *adapter;    // 这个不就是我们控制器中初始化的过的嘛用它来产生中断收发数据
    struct device dev;        /* the device structure        */
    int irq;            /* irq issued by device        */
    struct list_head detected;
};

看下probe函数: 做了删减

static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);

static const struct attribute_group tmp401_group = {
	.attrs = tmp401_attributes,
};
static struct attribute *tmp401_attributes[] = {
	&sensor_dev_attr_temp1_input.dev_attr.attr,
    NULL
}


static int tmp401_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	static const char * const names[] = {
		"TMP401", "TMP411", "TMP431", "TMP432", "TMP435", "TMP461"
	};
	struct device *dev = &client->dev;
	struct device *hwmon_dev;
	struct tmp401_data *data;
	int groups = 0, status;

	data = devm_kzalloc(dev, sizeof(struct tmp401_data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	data->client = client;
	mutex_init(&data->update_lock);
	data->kind = id->driver_data;

	/* Initialize the TMP401 chip */
	status = tmp401_init_client(data, client);
	if (status < 0)
		return status;

	/* Register sysfs hooks */
	data->groups[groups++] = &tmp401_group;

	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
							   data, data->groups);
	if (IS_ERR(hwmon_dev))
		return PTR_ERR(hwmon_dev);

	dev_info(dev, "Detected TI %s chip\n", names[data->kind]);

	return 0;
}

从设备读取温度接口:

static ssize_t show_temp_crit_hyst(struct device *dev,
	struct device_attribute *devattr, char *buf)
{
	int temp, index = to_sensor_dev_attr(devattr)->index;
	struct tmp401_data *data = tmp401_update_device(dev);

	if (IS_ERR(data))
		return PTR_ERR(data);

	mutex_lock(&data->update_lock);
	temp = tmp401_register_to_temp(data->temp[3][index], data->config);
	temp -= data->temp_crit_hyst * 1000;
	mutex_unlock(&data->update_lock);

	return sprintf(buf, "%d\n", temp);
}


static struct tmp401_data *tmp401_update_device(struct device *dev)
{
	struct tmp401_data *data = dev_get_drvdata(dev);
	struct i2c_client *client = data->client;
	struct tmp401_data *ret = data;
	int i, val;
	unsigned long next_update;

	mutex_lock(&data->update_lock);

	next_update = data->last_updated +
		      msecs_to_jiffies(data->update_interval);
	if (time_after(jiffies, next_update) || !data->valid) {
		if (data->kind != tmp432) {
			/*
			 * The driver uses the TMP432 status format internally.
			 * Convert status to TMP432 format for other chips.
			 */
			val = i2c_smbus_read_byte_data(client, TMP401_STATUS);
			if (val < 0) {
				ret = ERR_PTR(val);
				goto abort;
			}
			data->status[0] =
			  (val & TMP401_STATUS_REMOTE_OPEN) >> 1;
			data->status[1] =
			  ((val & TMP401_STATUS_REMOTE_LOW) >> 2) |
			  ((val & TMP401_STATUS_LOCAL_LOW) >> 5);
			data->status[2] =
			  ((val & TMP401_STATUS_REMOTE_HIGH) >> 3) |
			  ((val & TMP401_STATUS_LOCAL_HIGH) >> 6);
			data->status[3] = val & (TMP401_STATUS_LOCAL_CRIT
						| TMP401_STATUS_REMOTE_CRIT);
		} else {
			for (i = 0; i < ARRAY_SIZE(data->status); i++) {
				val = i2c_smbus_read_byte_data(client,
							TMP432_STATUS_REG[i]);
				if (val < 0) {
					ret = ERR_PTR(val);
					goto abort;
				}
				data->status[i] = val;
			}
		}

		val = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
		if (val < 0) {
			ret = ERR_PTR(val);
			goto abort;
		}
		data->config = val;
		val = tmp401_update_device_reg16(client, data);
		if (val < 0) {
			ret = ERR_PTR(val);
			goto abort;
		}
		val = i2c_smbus_read_byte_data(client, TMP401_TEMP_CRIT_HYST);
		if (val < 0) {
			ret = ERR_PTR(val);
			goto abort;
		}
		data->temp_crit_hyst = val;

		data->last_updated = jiffies;
		data->valid = 1;
	}

abort:
	mutex_unlock(&data->update_lock);
	return ret;
}

读写实质: 最终就是通过client中的adapter->algo读写

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值