기존 이솝 임베디드 포럼의 지식인 서비스가 게시판 형태로 변경되었습니다.
현재 Odroid상에 자이로 센서를 붙일려고 합니다. 그래서 새롭게 추가 할려는 자이로 센서의 I2C device driver를 module
로 작성하여 등록 할려고 합니다. 일단 제가 여기 저기 찾아 보면서 만든 방법과 등록 절차가 맞는지 검토좀 해 주셨으면 합니다. 혼자 하다보니...도무지 물어 볼데도 없고 답답합니다.
이것저것 보고 하다 보니 아래 함수명 들이 좀 맞지는 않지만 좀 봐 주셨으면 합니다.
1. arch/arm/mach-s5pc100/mach-hkdkc100.c 파일에 아래 내용 추가
static struct i2c_board_info i2c_devs0[] __initdata = {
{ I2C_BOARD_INFO("max17040", 0x36), },
{ I2C_BOARD_INFO("max8698c", 0x66), },
{ I2C_BOARD_INFO("atmega8", 0x38), }, //hwang
};
2. 1번에 등록한 atmega8 이라는 device driver 작성
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/gpio.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/leds.h>
#include <asm/mach-types.h>
#include <asm/uaccess.h>
#include <plat/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <plat/gpio-bank-h0.h>
#include <mach/map.h>
#include <asm/mach/irq.h>
///
//#include <linux/module.h>
#include <linux/bug.h>
#include <linux/err.h>
#include <linux/i2c.h>
struct atmega8_chip {
struct device *dev;
struct i2c_client *client;
struct mutex io_lock;
int num_regulators;
struct regulator_dev **rdev;
struct atmega8_platfrom_data *pdata;
};
static struct atmega8_chip *atmega8;
//Global variable
static int atmega8_usage = 0;
static unsigned char ucRegNum;
// define functions...
int atmega8_open (struct inode *minode, struct file *mfile);
ssize_t atmega8_write(struct file *, const char *, size_t, loff_t *);
ssize_t atmega8_read(struct file *, const char *, size_t, loff_t *);
int atmega8_release (struct inode *minode, struct file *mfile);
static const struct file_operations atmega8_fops =
{
.open = atmega8_open,
.write = atmega8_write,
.read = atmega8_read,
.release = atmega8_release,
};
//static int atmega8_write_reg(struct i2c_client *client, u8 reg, u8 value)
static int atmega8_write_reg(u8 reg, u8 value)
{
int ret;
printk("atmega8_write_reg STARTrn");
//ret = i2c_smbus_write_byte_data(client, reg, value);
ret = i2c_smbus_write_byte_data(atmega8->client, reg, value);
if(ret < 0)
//dev_err(&client->dev, "%s:err %dn", __func__, ret);
printk("err : %x rn", ret);
printk("ret : %x rn", ret);
return ret;
}
//static int atmega8_read_reg(struct i2c_client *client, u8 reg)
static int atmega8_read_reg(u8 reg)
{
int ret;
printk("atmega8_read_reg STARTrn");
//ret = i2c_smbus_read_byte_data(client, reg);
ret = i2c_smbus_read_byte_data(atmega8->client, reg);
if(ret < 0)
//dev_err(&client->dev, "%s:err %dn", __func__, ret);
printk("err : %x rn", ret);
printk("ret : %x rn", ret);
return ret;
}
int atmega8_open (struct inode *minode, struct file *mfile)
{
if (atmega8_usage != 0)
return -EBUSY;
atmega8_usage = 1;
return 0;
}
int atmega8_release (struct inode *minode, struct file *mfile)
{
atmega8_usage = 0;
return 0;
}
ssize_t atmega8_write (struct file *file, const char *buffer, size_t length, loff_t * offset)
{
//atmega8_write_reg(buffer[0], buffer[1]);
ucRegNum = buffer[0];
printk("address to read is %x (in write function)n", ucRegNum);
return 0;
}
ssize_t atmega8_read (struct file *file, const char *buffer, size_t length, loff_t * offset)
{
int iTemp;
char *buff;
printk("address to read is %x (in read function)n", ucRegNum);
iTemp = atmega8_read_reg(ucRegNum);
printk("value from i2c is %x n", iTemp);
buff = kmalloc( 1, GFP_KERNEL );
*buff = (unsigned char)iTemp;
copy_to_user( buffer, buff, 1 );
kfree ( buff );
return 0;
}
static int __devinit atmega8_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct atmega8_chip *chip;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
int ret;
printk("atmega8_i2c_probe STARTrn");
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
return -EIO;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if(!chip)
return -ENOMEM;
chip->client = client;
chip->dev = &client->dev;
chip->pdata = client->dev.platform_data;
atmega8 = chip;
//i2c_set_clientdata(client, chip);
//mutex_init(&chip->io_lock);
/* Detect MAX8698C */
//ret = atmega8_read_reg(atmega8->client, 0);
ret = atmega8_read_reg(0);
printk("ret : %x rn", ret);
if( ret < 0) {
dev_err(&chip->dev, "failed to detect device n");
goto err_detect;
}
i2c_set_clientdata(client, chip);
printk("atmega8_i2c_probe OKrn");
return 0;
err_detect:
printk("atmega8_i2c_probe ERRrn");
i2c_set_clientdata(chip, NULL);
kfree(chip);
err:
return ret;
}
static int __devexit atmega8_i2c_remove (struct i2c_client *client)
{
struct atmega8_chip *chip = i2c_get_clientdata(client);
kfree(chip->rdev);
i2c_set_clientdata(chip, NULL);
kfree(chip);
return 0;
}
static const struct i2c_device_id atmega8_id[] = {
{"atmega8", 0},
{ }
};
MODULE_DEVICE_TABLE(i2c, atmega8_id);
static struct i2c_driver atmega8_pmic_driver = {
.driver = {
.name = "atmega8",
.owner = THIS_MODULE,
},
.probe = atmega8_i2c_probe,
//.remove = atmega8_i2c_remove,
.remove = __devexit_p(atmega8_i2c_remove),
.id_table = atmega8_id,
};
static int __init atmega8_pmic_init(void)
{
printk( "init module, HWANG2 n");
i2c_add_driver(&atmega8_pmic_driver);
}
module_init(atmega8_pmic_init);
static void __exit atmega8_pmic_exit(void)
{
i2c_del_driver(&atmega8_pmic_driver);
}
module_exit(atmega8_pmic_exit);
MODULE_AUTHOR("HWANG");
MODULE_LICENSE("GPL");
3. module 컴파일후 insmod 실행하여 모듈 추가
4. App에서 read, write 호출하여 사용
이렇게 4번까지 하려고 하는데 이렇게 하는게 맞는지 잘 모르겠어서요. 일반적으로 char device같은 경우 하나의 디바이스 파일 및에 하나의 device driver가 연결 되는데 지금과 같이 i2c-0 디바이스 파일 및에는 3개의 device driver가 붙은 격이 되는데 그럼.... App단에서 read, write함수를 호출하면 어느 device driver랑 연결이 되는지 애매해 보이거든요...
이렇게 작업을 하는게 맞는 건가요?
전반적인 작업순서는 무난해 보입니다.
하나의 버스에 여러개의 장치가 붙어도 문제는 없습니다.
각 장치마다 고유한 어드레스가 있기 때문이죠...
추가하려는 장치의 I2C 디바이스 어드레스가 기존에 달려있는 다른 장치와 비교해 보세요.
ATMEGA8 MCU의 I2C Slave 주소만 주의하시면 될것 같네요.
사족입니다만, Java에서 디바이스 드라이버 read/write 하시려면, NDK로 JNI 하나 뚫어야 하고요..