当前位置:网站首页>Analysis of I2C adapter driver of s5pv210 chip (i2c-s3c2410. C)

Analysis of I2C adapter driver of s5pv210 chip (i2c-s3c2410. C)

2022-07-04 17:43:00 Snail taking off

1、 What is an adapter driver

(1) Adapter driver is used to control Soc Upper I2C Controller , encapsulation I2C Communication mode of controller ;
(2) The adapter driver will send I2C Core layer registration ,I2C The core layer will manage all the registered adapter drivers in the kernel , Every registered adapter driver represents Soc One of them I2C controller ;
(3)I2C The driver of the interface device will pass I2C The bus matches the corresponding adapter , Then call the data transceiver interface provided by the adapter to communicate ;

2、 How does the adapter driver work with Soc Upper I2C The controller corresponds to

/*********gslX680.c**************/
#define GSLX680_I2C_NAME "gslX680"

static struct i2c_driver gsl_ts_driver = {
    
	.driver = {
    
		.name = GSLX680_I2C_NAME,
		.owner = THIS_MODULE,
	},
#ifndef CONFIG_HAS_EARLYSUSPEND
	.suspend	= gsl_ts_suspend,
	.resume	= gsl_ts_resume,
#endif
	.probe		= gsl_ts_probe,
	.remove		= __devexit_p(gsl_ts_remove),
	.id_table	= gsl_ts_id,
};

// Function call relationship 
gsl_ts_init()	// Driver loading function 
	i2c_add_driver(&gsl_ts_driver);	// towards I2C Bus registration gslX680 drive 
		gsl_ts_probe()	// When gslX680 Drive in I2C Match on the bus struct i2c_client Is called probe Method 


/********* Kernel registration i2c_board_info Information ************/
static struct i2c_board_info i2c_devs1[] __initdata = {
    

	{
    
		I2C_BOARD_INFO("gslX680", 0x40),	//gslX680 Is the name used to match the driver ,0x40 The device is I2C Address on the bus 
	},

};

smdkc110_machine_init()	//struct machine_desc->init_machine()
	i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));	// The direction number is 1 Adapter registration for i2c_board_info Information 

(1) It's on it gslX680 Touch screen driver code and in I2C The code matching the relevant part on the bus ;
(2)struct i2c_board_info Structure : Will be used to form struct i2c_client Structure , future I2C The driver of the interface device is I2C When matching devices on the bus , Will match by name ,
Which adapter has the name of the driver will match with which adapter successfully , And will also put struct i2c_board_info The information in the structure is transmitted to I2C drive , such as : Device address 、 Interrupt number ;
(3) Each adapter will register struct i2c_board_info Structure information , future struct i2c_board_info The name in the structure will match I2C Match the name of the driver , I2C The driver and adapter are matched ,
future I2C The driver communicates through the adapter on the matching , That is, hardware I2C Which interface device is connected I2C controller ;

3、 Adapter driven loading process

static struct platform_device_id s3c24xx_driver_ids[] = {
    
	{
    
		.name		= "s3c2410-i2c",
		.driver_data	= TYPE_S3C2410,
	}, {
    
		.name		= "s3c2440-i2c",
		.driver_data	= TYPE_S3C2440,
	}, {
     },
};

static struct platform_driver s3c24xx_i2c_driver = {
    
	.probe		= s3c24xx_i2c_probe,
	.remove		= s3c24xx_i2c_remove,
	.id_table	= s3c24xx_driver_ids,	// stay platform Use when matching devices on the bus 
	.driver		= {
    
		.owner	= THIS_MODULE,
		.name	= "s3c-i2c",
		.pm	= S3C24XX_DEV_PM_OPS,
	},
};

i2c_adap_s3c_init()	// Driver loading function 
	platform_driver_register(&s3c24xx_i2c_driver);	// Use the platform bus to register 
		s3c24xx_i2c_probe()	// Call after matching the device on the platform bus probe function 
			i2c_add_numbered_adapter(&i2c->adap);	// utilize platform_device The transferred data builds the adapter structure , And to I2C Core layer registration 

(1) In the kernel struct machine_desc->init_machine() Function will register plat_device, There will be multiple plat_device and platform Bus driver s3c24xx_i2c_driver On the match ,
Is basically Soc There are several I2C The controller is matched several times , That is to say, I would like to I2C The core layer registers multiple adapters ;
(2) Although it has been matched many times , But every time plat_device The data transmitted are all different , Include I2C Register physical address of the controller 、 Interrupt number 、 Adapter number, etc ;

4、I2C Bus driven description structure

struct s3c24xx_i2c {
    
	spinlock_t		lock;
	wait_queue_head_t	wait;	// In order to synchronize , send i2c->algorithm->master_xfer Function can return when the transmission process in interruption is completed 
	unsigned int		suspended:1;

	// Record the information of the data to be transmitted 
	struct i2c_msg		*msg;	// Message queue 
	unsigned int		msg_num;	// Number of messages in the message queue 
	unsigned int		msg_idx;	// Which message in the sequence is currently transmitted 
	unsigned int		msg_ptr;	// The current number of bytes is transmitted 

	unsigned int		tx_setup;	// Transmission setup delay 
	unsigned int		irq;	// Interrupt number used 

	enum s3c24xx_i2c_state	state;	// Current transmission status , Where to go 
	unsigned long		clkrate;

	void __iomem		*regs;	// Used to access the kernel IO Actual address of memory 
	struct clk		*clk;
	struct device		*dev;
	struct resource		*ioarea;	//IO Memory resources 
	struct i2c_adapter	adap;	// Corresponding adapter 
};

5、 Adapter driven probe Method realization

static int s3c24xx_i2c_probe(struct platform_device *pdev)
{
    
	struct s3c24xx_i2c *i2c;
	struct s3c2410_platform_i2c *pdata;
	struct resource *res;
	int ret;

	// Analysis Division platform Information transmitted by bus devices 
	pdata = pdev->dev.platform_data;

	i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);

	// Set the name of the adapter 
	strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
	
	// Build the adapter structure adap
	i2c->adap.owner   = THIS_MODULE;
	i2c->adap.algo    = &s3c24xx_i2c_algorithm;	// Set the communication method of the adapter 
	i2c->adap.retries = 2;						// The number of retransmissions is 2
	i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
	i2c->tx_setup     = 50;

	// Initialize spinlock and wait queue 
	spin_lock_init(&i2c->lock);
	init_waitqueue_head(&i2c->wait);

	/*  obtain I2C The clock of the controller is not enabled  */
	i2c->dev = &pdev->dev;
	i2c->clk = clk_get(&pdev->dev, "i2c");	// Get the clock system to I2C The clock frequency provided by the controller 
	clk_enable(i2c->clk);	// Can make the clock 

	/*  obtain I2C Controller IO Address resources  */
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	······

	// Apply for the physical address of the register 
	i2c->ioarea = request_mem_region(res->start, resource_size(res),
					 pdev->name);

	// Dynamically map physical addresses 
	i2c->regs = ioremap(res->start, resource_size(res));

	// stay master_xfer And other methods can pass the adapter algo_data Get the corresponding i2c object 
	i2c->adap.algo_data = i2c;
	i2c->adap.dev.parent = &pdev->dev;

	// Initialize the chip I2C controller : To interrupt 、ACK Can make 、 Set the corresponding GPIO、 Initialization clock, etc 
	ret = s3c24xx_i2c_init(i2c);
	if (ret != 0)
		goto err_iomap;

	// Get interrupt number resource 
	i2c->irq = ret = platform_get_irq(pdev, 0);
	if (ret <= 0) {
    
		dev_err(&pdev->dev, "cannot find IRQ\n");
		goto err_iomap;
	}

	// Apply for interrupt number and bind interrupt handler s3c24xx_i2c_irq
	ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,
			  dev_name(&pdev->dev), i2c);

	// Using the kernel notification chain mechanism , When CPU When the frequency changes , when I2C The clock setting can be adjusted 
	ret = s3c24xx_i2c_register_cpufreq(i2c);
	if (ret < 0) {
    
		dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
		goto err_irq;
	}

	// from platform The bus device obtains the bus number of the adapter 
	i2c->adap.nr = pdata->bus_num;

	// towards I2C The core layer registers the adapter 
	ret = i2c_add_numbered_adapter(&i2c->adap);
	if (ret < 0) {
    
		dev_err(&pdev->dev, "failed to add bus to i2c core\n");
		goto err_cpufreq;
	}

	// take i2c Save to pdev->dev->p->driver_data
	platform_set_drvdata(pdev, i2c);

	clk_disable(i2c->clk);

	dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
	return 0;

	······
}

6、I2C Bus communication method

6.1、 Communication method of adapter

static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
    
	.master_xfer		= s3c24xx_i2c_xfer,
	.functionality		= s3c24xx_i2c_func,
};

6.2、 Function call relationship of data communication

s3c24xx_i2c_xfer() //adap->algo->master_xfer
	s3c24xx_i2c_doxfer()
		s3c24xx_i2c_set_master()	// Ensure current I2C Controller is idle , Before continuing the following operation 
		s3c24xx_i2c_enable_irq()	// Can make i2C-Bus Of Tx/Rx interrupt 
		s3c24xx_i2c_message_start()	// Turn on I2C signal communication 
		wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);	// Send function into wait , Until the message is sent or exceeds 5s return 
		
 Wake up the waiting queue in the interrupt program :
	s3c24xx_i2c_irq()	// Adapter bound interrupt handler 
		i2c_s3c_irq_nextbyte()	// send data 
			s3c24xx_i2c_stop()	// Stop this transmission when data transmission and reception is completed or communication error occurs 
				s3c24xx_i2c_master_complete()	// This transmission is completed 
					wake_up(&i2c->wait);	// Wake up waiting line 

(1)I2C Adapter description structure struct i2c_adapter in algo Variables are the communication methods of the adapter , In the driver's prob Function assignment ;
(2) Communication is based on messages (struct i2c_msg) In units , The message description structure will indicate the address of the device to be sent 、 Data transmission direction, etc ;

6.3、 Communication process

(1) First of all I2C The device driver invokes the adapter adap->algo->master_xfer To send a message ,master_xfer Method after some initialization , Open this I2C signal communication , Then enter the waiting queue , Until the message is sent or 5 Return after seconds timeout ;
(2) The specific sending is in probe Method is bound to the interrupt function , The interrupt function is I2C Interrupt handling function of controller , After sending data or making errors , Will wake up before waiting s3c24xx_i2c_doxfer() function ;

原网站

版权声明
本文为[Snail taking off]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/185/202207041558197980.html