gpio模拟I2C
时间:10-02
整理:3721RD
点击:
开发中经常与i2c打交道,芯片中自带的硬件i2c控制器使用起来并不是很灵活,而且要研究半天的寄存器。所以干脆搞一个软件模拟gpio的通用代码,移植起来也方便,使用灵活
具体代码如下:
-
- #include <linux/module.h>
- #include <linux/config.h>
- #include <linux/errno.h>
- #include <linux/miscdevice.h>
- #include <linux/fcntl.h>
- #include <linux/init.h>
- #include <linux/delay.h>
- #include <linux/version.h>
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <linux/types.h>
- #include <linux/proc_fs.h>
- #include <asm/uaccess.h>
- #include <asm/system.h>
- #include <asm/rt2880/rt_mmap.h>
- #include <asm/system.h>
- #include <asm/io.h>
- #include "gpio_i2c.h"
- #include "../ralink_gpio.h"
- #define DELAY(u) udelay(u*100)
- #define RT2860REG(addr) (*(volatile u32 *)(addr))
- static void gpio_i2c_set_bit(int id, int onoff)
- {
- int tmp;
- if(id<=21&&id>=0)
- {
- tmp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIODIR));
- tmp |= (1<<(id));
- *(volatile u32 *)(RALINK_REG_PIODIR) = tmp;
- tmp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIODATA));
- tmp = (tmp&~(1<<(id)))|(onoff<<(id));
- *(volatile u32 *)(RALINK_REG_PIODATA) = tmp;
- }
- else if(id>=22&&id<=27)
- {
- tmp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIO2722DIR));
- tmp |= (1<<(id-22));
- *(volatile u32 *)(RALINK_REG_PIO2722DIR) = tmp;
- tmp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIO2722DATA));
- tmp = (tmp&~(1<<(id-22)))|(onoff<<(id-22));
- *(volatile u32 *)(RALINK_REG_PIO2722DATA) = tmp;
- }
- else
- {
- printk("####HU#### %s id %d invalid \r\n",__FUNCTION__,id);
- }
- }
- static int gpio_i2c_get_bit(int id)
- {
- int tmp;
- if(id<=21&&id>=0)
- {
- tmp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIODIR));
- tmp &= ~(1<<(id));
- *(volatile u32 *)(RALINK_REG_PIODIR) = tmp;
- tmp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIODATA));
- return (tmp>>id&0x01);
- }
- else if(id>=22&&id<=27)
- {
- tmp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIO2722DIR));
- tmp &= ~(1<<(id-22));
- *(volatile u32 *)(RALINK_REG_PIO2722DIR) = tmp;
- tmp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIO2722DATA));
- return (tmp>>(id-22)&0x01);
- }
- else
- {
- printk("####HU#### %s id %d invalid \r\n",__FUNCTION__,id);
- }
- }
- static void i2c_clk(int onoff)
- {
- gpio_i2c_set_bit(2,onoff);
-
- }
- static void i2c_dat(int onoff)
- {
- gpio_i2c_set_bit(1,onoff);
-
- }
-
- static unsigned char i2c_data_read(void)
- {
- // unsigned char tmp;
-
- // tmp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIODIR));
- // tmp &= ~(1<<(1));
- // *(volatile u32 *)(RALINK_REG_PIODIR) = tmp;
- //
- // //DELAY(1);
- //
- // tmp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIODATA));
- // if((tmp&(1<<1)) != 0)
- // return 1;
- // else
- // return 0;
- return gpio_i2c_get_bit(1);
- }
- /*
- * sends a start bit via I2C rountine.
- *
- */
- static void i2c_start_bit(void)
- {
- DELAY(1);
- i2c_clk(1);
- i2c_dat(1);
- DELAY(1);
- i2c_dat(0);
- DELAY(1);
- }
- /*
- * sends a stop bit via I2C rountine.
- *
- */
- static void i2c_stop_bit(void)
- {
-
- i2c_clk(0);
- i2c_dat(1);
- DELAY(1);
- i2c_clk(1);
- }
- /*
- * sends a character over I2C rountine.
- *
- * @param c: character to send
- *
- */
- static void i2c_send_byte(unsigned char c)
- {
- int i;
- local_irq_disable();
- //i2c_clk(1);
- for (i=0; i<8; i++)
- {
- i2c_clk(0);
- if (c & (1<<(7-i)))
- i2c_dat(1);
- else
- i2c_dat(0);
-
- DELAY(1);
-
- i2c_clk(1);
- DELAY(1);
- }
- // i2c_dat(1);
- local_irq_enable();
- }
- /* receives a character from I2C rountine.
- *
- * [url=home.php?mod=space&uid=1141835]@Return[/url] value: character received
- *
- */
- static unsigned char i2c_receive_byte(void)
- {
- int j=0;
- int i;
- unsigned char regvalue;
- local_irq_disable();
- i2c_data_read();
- for (i=0; i<8; i++)
- {
- i2c_clk(0);
- DELAY(1);
- i2c_clk(1);
-
- i2c_data_read();
- if (i2c_data_read())
- j+=(1<<(7-i));
-
- DELAY(1);
-
-
- }
- local_irq_enable();
- // i2c_dat(0);
- // DELAY(1);
- return j;
- }
- /* receives an acknowledge from I2C rountine.
- *
- * @return value: 0--Ack received; 1--Nack received
- *
- */
- static int i2c_receive_ack(void)
- {
- int nack;
-
- i2c_data_read();
- i2c_clk(0);
- DELAY(1);
- i2c_clk(1);
-
- i2c_data_read();
- nack = i2c_data_read();
- DELAY(1);
- i2c_dat(1);
- if (nack == 0)
- return 1;
- return 0;
- }
- /*
- * sends an acknowledge over I2C rountine.
- *
- */
- static void i2c_send_ack(void)
- {
- i2c_clk(0);
- i2c_dat(0);
- DELAY(1);
-
- i2c_clk(1);
- DELAY(1);
-
- }
- static void si2c_init()
- {
- RT2860REG(RALINK_REG_GPIOMODE)=RT2860REG(RALINK_REG_GPIOMODE)|(1<<0);
- }
- static void si2c_exit()
- {
-
- }
- /*
- * read data from the I2C bus by GPIO simulated of a device rountine.
- *
- * @param devaddress: address of the device
- * @param address: address of register within device
- *
- * @return value: data from the device readed
- *
- */
- unsigned char gpio_i2c_read(unsigned char devaddress, unsigned char address)
- {
- int rxdata;
- si2c_init();
-
- i2c_start_bit();
- i2c_send_byte((unsigned char)((devaddress<<1)|0));
- i2c_receive_ack();
- i2c_send_byte(address);
- i2c_receive_ack();
- i2c_start_bit();
- i2c_send_byte((unsigned char)((devaddress<<1)|1));
- i2c_receive_ack();
- rxdata = i2c_receive_byte();
- i2c_send_ack();
- i2c_stop_bit();
-
- si2c_exit();
- return rxdata;
- }
- EXPORT_SYMBOL(gpio_i2c_read);
- /*
- * writes data to a device on the I2C bus rountine.
- *
- * @param devaddress: address of the device
- * @param address: address of register within device
- * @param data: data for write to device
- *
- */
- void gpio_i2c_write(unsigned char devaddress, unsigned char address, unsigned char data)
- {
- si2c_init();
-
- i2c_start_bit();
- i2c_send_byte((unsigned char)((devaddress<<1)|0));
- i2c_receive_ack();
- i2c_send_byte(address);
- i2c_receive_ack();
- i2c_send_byte(data);
- i2c_receive_ack();
- i2c_stop_bit();
- si2c_exit();
- }
- EXPORT_SYMBOL(gpio_i2c_write);
- /*
- * initializes I2C interface routine.
- *
- * @return value:0--success; 1--error.
- *
- */
- static int __init gpio_i2c_init(void)
- {
- }
- static void __exit gpio_i2c_exit(void)
- {
-
- }
- module_init(gpio_i2c_init);
- module_exit(gpio_i2c_exit);
- #ifdef MODULE
- #include <linux/compile.h>
- #endif
- MODULE_INFO(build, UTS_VERSION);
- MODULE_LICENSE("GPL");
- MODULE_VERSION("HI_VERSION=" OSDRV_MODULE_VERSION_STRING);
gpio_i2c_set_bit与gpio_i2c_get_bit设置gpio高低的,DELAY宏为延时方法,理论只要实现这几个值就能够实现标准的gpio_i2c的功能了