📄 gpio_i2c.c
字号:
/* extdrv/interface/gpio_i2c/gpio_i2c.c
*
*
* Copyright (c) 2006 Hisilicon Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.
*
*
* History:
* 03-Apr-2006 create this file
*
*/
#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/proc_fs.h>
#include <linux/workqueue.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
#include "gpio_i2c.h"
static void __iomem *gpio_map_addr;
unsigned int GPIO_BASE_MMAP;
/* GPIO2_4 */
#define SCL (1 << 0)
/* GPIO2_3 */
#define SDA (1 << 1)
#define GPIO_2_BASE 0x101e6000
#define GPIO_2_DIR (GPIO_BASE_MMAP + 0x400)
#define GPIO_I2C_SDA_REG (GPIO_BASE_MMAP + 0x20)
#define GPIO_I2C_SCL_REG (GPIO_BASE_MMAP + 0x40)
#define GPIO_I2C_SCLSDA_REG (GPIO_BASE_MMAP + 0x60)
#define HW_REG(reg) *((volatile unsigned int *)(reg))
#define DELAY(us) time_delay_us(us)
/*
* I2C by GPIO simulated clear 0 routine.
*
* @param whichline: GPIO control line
*
*/
static void i2c_clr(unsigned char whichline)
{
unsigned char regvalue;
if(whichline == SCL)
{
regvalue = HW_REG(GPIO_2_DIR);
regvalue |= 0x10;
HW_REG(GPIO_2_DIR) = regvalue;
HW_REG(GPIO_I2C_SCL_REG) = 0;
return;
}
else if(whichline == SDA)
{
regvalue = HW_REG(GPIO_2_DIR);
regvalue |= 0x08;
HW_REG(GPIO_2_DIR) = regvalue;
HW_REG(GPIO_I2C_SDA_REG) = 0;
return;
}
else if(whichline == (SDA|SCL))
{
regvalue = HW_REG(GPIO_2_DIR);
regvalue |= 0x18;
HW_REG(GPIO_2_DIR) = regvalue;
HW_REG(GPIO_I2C_SCLSDA_REG) = 0;
return;
}
else
{
printk("Error input.\n");
return;
}
}
/*
* I2C by GPIO simulated set 1 routine.
*
* @param whichline: GPIO control line
*
*/
static void i2c_set(unsigned char whichline)
{
unsigned char regvalue;
if(whichline == SCL)
{
regvalue = HW_REG(GPIO_2_DIR);
regvalue |= 0x10;
HW_REG(GPIO_2_DIR) = regvalue;
HW_REG(GPIO_I2C_SCL_REG) = 0x10;
return;
}
else if(whichline == SDA)
{
regvalue = HW_REG(GPIO_2_DIR);
regvalue |= 0x08;
HW_REG(GPIO_2_DIR) = regvalue;
HW_REG(GPIO_I2C_SDA_REG) = 0x08;
return;
}
else if(whichline == (SDA|SCL))
{
regvalue = HW_REG(GPIO_2_DIR);
regvalue |= 0x18;
HW_REG(GPIO_2_DIR) = regvalue;
HW_REG(GPIO_I2C_SCLSDA_REG) = 0x18;
return;
}
else
{
printk("Error input.\n");
return;
}
}
/*
* delays for a specified number of micro seconds rountine.
*
* @param usec: number of micro seconds to pause for
*
*/
void time_delay_us(unsigned int usec)
{
int i,j;
for(i=0;i<usec * 5;i++)
{
for(j=0;j<47;j++)
{;}
}
}
/*
* I2C by GPIO simulated read data routine.
*
* @return value: a bit for read
*
*/
static unsigned char i2c_data_read(void)
{
unsigned char regvalue;
regvalue = HW_REG(GPIO_2_DIR);
regvalue &= 0xf7;
HW_REG(GPIO_2_DIR) = regvalue;
DELAY(1);
regvalue = HW_REG(GPIO_I2C_SDA_REG);
if((regvalue&0x08) != 0)
return 1;
else
return 0;
}
/*
* sends a start bit via I2C rountine.
*
*/
static void i2c_start_bit(void)
{
DELAY(1);
i2c_set(SDA | SCL);
DELAY(1);
i2c_clr(SDA);
DELAY(1);
}
/*
* sends a stop bit via I2C rountine.
*
*/
static void i2c_stop_bit(void)
{
/* clock the ack */
DELAY(1);
i2c_set(SCL);
DELAY(1);
i2c_clr(SCL);
/* actual stop bit */
DELAY(1);
i2c_clr(SDA);
DELAY(1);
i2c_set(SCL);
DELAY(1);
i2c_set(SDA);
DELAY(1);
}
/*
* sends a character over I2C rountine.
*
* @param c: character to send
*
*/
static void i2c_send_byte(unsigned char c)
{
int i;
for (i=0; i<8; i++)
{
DELAY(1);
i2c_clr(SCL);
DELAY(1);
if (c & (1<<(7-i)))
i2c_set(SDA);
else
i2c_clr(SDA);
DELAY(1);
i2c_set(SCL);
DELAY(1);
i2c_clr(SCL);
}
DELAY(1);
i2c_set(SDA);
DELAY(1);
}
/* receives a character from I2C rountine.
*
* @return value: character received
*
*/
static unsigned char i2c_receive_byte(void)
{
int j=0;
int i;
unsigned char regvalue;
i2c_set(SDA);
for (i=0; i<8; i++)
{
DELAY(1);
i2c_clr(SCL);
DELAY(1);
i2c_set(SCL);
regvalue = HW_REG(GPIO_2_DIR);
regvalue &= 0xf7;
HW_REG(GPIO_2_DIR) = regvalue;
DELAY(1);
if (i2c_data_read())
j+=(1<<(7-i));
DELAY(1);
i2c_clr(SCL);
}
DELAY(1);
i2c_clr(SDA);
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;
unsigned char regvalue;
DELAY(1);
regvalue = HW_REG(GPIO_2_DIR);
regvalue &= 0xf7;
HW_REG(GPIO_2_DIR) = regvalue;
DELAY(1);
i2c_clr(SCL);
DELAY(1);
i2c_set(SCL);
DELAY(1);
nack = i2c_data_read();
DELAY(1);
i2c_clr(SCL);
DELAY(1);
i2c_set(SDA);
DELAY(1);
if (nack == 0)
return 1;
return 0;
}
/*
* sends an acknowledge over I2C rountine.
*
*/
static void i2c_send_ack(void)
{
DELAY(1);
i2c_clr(SCL);
DELAY(1);
i2c_set(SDA);
DELAY(1);
i2c_set(SCL);
DELAY(1);
i2c_clr(SCL);
DELAY(1);
i2c_clr(SDA);
DELAY(1);
}
/*
* 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;
i2c_start_bit();
i2c_send_byte((unsigned char)(devaddress));
i2c_receive_ack();
i2c_send_byte(address);
i2c_receive_ack();
i2c_start_bit();
i2c_send_byte((unsigned char)(devaddress) | 1);
i2c_receive_ack();
rxdata = i2c_receive_byte();
i2c_send_ack();
i2c_stop_bit();
return rxdata;
}
/*
* read data from the I2C bus by GPIO simulated of a digital camera device rountine.
*
* @param devaddress: address of the device
* @param address: address of register within device
*
*/
unsigned char gpio_sccb_read(unsigned char devaddress, unsigned char address)
{
int rxdata;
i2c_start_bit();
i2c_send_byte((unsigned char)(devaddress));
i2c_receive_ack();
i2c_send_byte(address);
i2c_receive_ack();
i2c_stop_bit();
i2c_start_bit();
i2c_send_byte((unsigned char)(devaddress) | 1);
i2c_receive_ack();
rxdata = i2c_receive_byte();
i2c_send_ack();
i2c_stop_bit();
return rxdata;
}
/*
* 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)
{
i2c_start_bit();
i2c_send_byte((unsigned char)(devaddress));
i2c_receive_ack();
i2c_send_byte(address);
i2c_receive_ack();
i2c_send_byte(data);
i2c_stop_bit();
}
static unsigned int gpioinitialized =0;
/*
* initializes I2C interface routine.
*
* @return value:0--success; 1--error.
*
*/
static int __init gpio_i2c_init(void)
{
if(gpioinitialized == 0)
{
printk(KERN_INFO "Hisilicon GPIO control for I2C Driver \n");
gpio_map_addr = (unsigned int*)ioremap(GPIO_2_BASE,PAGE_SIZE);
if(gpio_map_addr<0)
{
printk("NO mem\n");
return -EFAULT;
}
GPIO_BASE_MMAP = (unsigned int)gpio_map_addr;
i2c_clr(SCL | SDA);
gpioinitialized =1;
return 0;
}
else
{
printk("GPIO control for I2C has been initialized.\n");
return 0;
}
}
static void __exit gpio_i2c_exit(void)
{
iounmap((void *)gpio_map_addr);
gpioinitialized =0;
}
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");
EXPORT_SYMBOL(gpio_i2c_read);
EXPORT_SYMBOL(gpio_sccb_read);
EXPORT_SYMBOL(gpio_i2c_write);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -