Cómo utilizar la interfaz iic directamente en Linux
Utilice el subsistema del dispositivo IIC en Linux para trasplantar el controlador del dispositivo IIC.
Descripción básica
El bus IIC se usa ampliamente en sistemas integrados. Los más comunes incluyen eeprom. , rtc. Un procesador general incluirá un controlador IIC para controlar la sincronización del IIC. Por otro lado, debido a que la sincronización del IIC es simple, también es común usar el puerto GPIO para simular la sincronización. Frente a diferentes controladores IIC, varios chips y códigos fuente de Linux, ¿cómo hacer que los controladores de dispositivos IIC sean más rápidos?
Descripción del problema
En nuestra solución, usaremos eeprom, rtc y tw2865. Debido a que hay un problema con el diseño del controlador IIC del Hi3520, no se puede utilizar normalmente. Los pines SDA y SCL del controlador IIC están multiplexados con los dos pines GPIO. Hisi controlará gpio para implementar la sincronización IIC para operar el dispositivo IIC. Este método de diseño es simple y claro, pero el uso del subsistema IIC facilita el trasplante y el mantenimiento de otros controladores de dispositivos.
Análisis del problema
El enfoque de Hisi para el puerto gpio, el chip rtc y tw2865 es el siguiente: el puerto gpio se convierte en un controlador modular, que simula la sincronización IIC y lo envía a el mundo exterior Proporcione algunas interfaces de funciones, como: EXPORT_SYMBOL(gpio_i2c_read_tw2815), etc. Para un chip rtc específico, regístrelo como un dispositivo misceláneo y use las funciones exportadas por el módulo gpio para configurar el chip rtc.
De hecho, podemos hacer uso del código en el directorio linux-2.6.24\drivers\i2c.
La estructura de palabras IIC de Linux se divide en tres componentes:
Núcleo IIC
El núcleo IIC proporciona métodos de registro y cancelación de registro para controladores de bus y controladores de dispositivos IIC. el código de capa superior de IICalgorithm que no tiene nada que ver con el adaptador específico, así como el código de capa superior para detectar dispositivos y detectar direcciones de dispositivos.
Controlador de bus IIC
El controlador de bus IIC es la implementación del lado del adaptador de la arquitectura de hardware IIC.
Controlador de dispositivo IIC
El controlador de dispositivo IIC es la implementación del lado general del dispositivo del sistema de hardware IIC.
Revisemos el makefile y kconfig en este directorio:
obj-$(CONFIG_I2C_BOARDINFO) +=i2c-boardinfo.o
obj-$(CONFIG_I2C ) += i2c-core.o
obj-$(CONFIG_I2C_CHARDEV) +=i2c-dev.o
obj-y +=buses/ chips/ algos/
i2c-core.c es el núcleo IIC. Los archivos en los buses son los controladores de bus para el bus IIC en los procesadores convencionales, mientras que los archivos en los chips son los controladores para los chips de uso común. Los archivos en los algos implementan algunos algoritmos de adaptadores de bus. Esto incluye el archivo i2c-algo-bit.c que queremos usar.
Primero usamos i2c-gpio.c e i2c-algo-bit.c para crear el conductor del autobús.
En i2c-gpio.c, module_init?i2c_gpio_init?platform_driver_probe(&i2c_gpio_driver,i2c_gpio_probe);
Regístrelo como controlador del bus virtual de la plataforma.
En staticint __init i2c_gpio_probe(struct platform_device *pdev),
Se definen las siguientes tres estructuras:
structi2c_gpio_platform_data *pdata;//Configuración de gpio relacionada con la plataforma
structi2c_algo_bit_data *bit_data;//Contiene funciones específicas del algoritmo, setor
obtener SDA y SCL
structi2c_adapter *adap;//Adaptador
p>i2c_gpio_probe hace principalmente las siguientes cosas:
Rellena cada puntero de función de la estructura bit_data y lo asocia con las funciones de operación específicas SDA y SCl.
Rellene la estructura adap, adap->algo_data= bit_data;
pdata= pdev->dev.platform_data;
bit_data->data= pdata;
bit_data->data= pdata;
p>
pdev->dev->driver_data= adap;
Registra el tipo de adaptador en i2c-core .
inti2c_bit_add_numbered_bus(struct i2c_adapter *adap)
En staticint i2c_bit_prepare_bus(struct i2c_adapter *adap)
adap->algo= &i2c_bit_algo;
Asociar i2c_bit_algo con adapt.
estático const structi2c_algorithm i2c_bit_algo = {
.master_xfer = bit_xfer,
.functionality = bit_func,
};
Entre ellos, el puntero de función master_xfer es el puntero de función de transferencia IIC.
I2c-algo-bit.c también implementa la simulación de las condiciones de inicio y finalización de IIC, el envío de bytes, la recepción de bytes y el procesamiento de bits de respuesta.
i2c_gpio_setsda_val y otras funciones en i2c-gpio.c están relacionadas con la plataforma específica gpio.
Modifica varias funciones en gpio.h correspondientes al directorio arch-hi3520v100. Estas funciones controlan la dirección y el valor de gpio mediante registros operativos.
Agrega lo siguiente en platform-devices.c correspondiente a mach-hi3520v100:
static structi2c_gpio_platform_data pdata = {
.sda_pin = 1<<0,
.sda_is_open_drain = 1,
.scl_pin = 1<<1,
.scl_is_open_drain = 1,
.udelay = 4, /* ~100 kHz */
};
estructura estática platform_devicehisilicon_i2c_gpio_device = {
.name = "i2c-gpio",
.id = -1,
.dev.platform_data = &pdata,
};
estructura estática platform_device*hisilicon_plat_devs[] __initdata = { p >
&hisilicon_i2c_gpio_device,
};
int __inithisilicon_register_platform_devices(void)
{
platform_add_devices(hisilicon_plat_devs,ARRAY_SIZE (hisilicon_plat_devs ) );
return 0;
}
Agregue dispositivos y controladores a través de la plataforma para que pdev->dev.platform_data=pdata
Con base en el proceso anterior, completamos el registro del adaptador y asociamos el algoritmo simulado usando el puerto gpio con el adaptador.
De esta manera, en rtc-x1205.c, la función x1205_attach utiliza el núcleo i2c para completar la asociación entre el cliente y el adaptador.
Complete la estructura i2c_client en la función x1205_probe y llame a i2c_attach_client para notificar al núcleo de iic.
Luego registre el controlador rtc.
Finalmente, si queremos leer la hora, necesitamos construir la estructura i2c_msg, como se muestra a continuación:
struct i2c_msg msgs[] = {
{ cliente-> dirección, 0, 2,dt_addr }, /* configuración lectura ptr */
{ cliente->dirección, I2C_M_RD,8, buf }, /* lectura fecha */
} ;
/* leer registros de fecha */
if((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
dev_err(&client->dev,"%s: error de lectura\n", __FUNCTION__);
return -EIO;
}
dt_addr es la dirección del registro, I2C_M_RD representa iicread.