Kernel version: linux-2.6.32.2 Experimental platform: mini2440
1. Add support for master devices
The i2c master controller is also a device, but it is virtualized as a platform device in the kernel. The platform device has been defined in the kernel in plat-s3c/dev-i2c0.c:
static struct resource s3c_i2c_resource[] = {
[0] = {
.start = S3C_PA_IIC,
.end = S3C_PA_IIC + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_IIC,
.end = IRQ_IIC,
.flags = IORESOURCE_IRQ,
},
};
struct platform_device s3c_device_i2c0 = {
.name = "s3c2410-i2c",
#ifdef CONFIG_S3C_DEV_I2C1
.id = 0,
#else
.id = -1,
#endif
.num_resources = ARRAY_SIZE(s3c_i2c_resource),
.resource = s3c_i2c_resource,
};
Then I just need to add this platform device to the mini2440_devices array, and eventually this platform device will be registered in the kernel.
2. Add support for master driver
The main controller driver is drivers/i2c/busses/i2c-s3c2410.c, so we only need to configure it:
Device Drivers --->
<*> I2C support --->
I2C Hardware Bus support --->
<*> S3C2410 I2C Driver
3. Registration of at24c08 i2c device
Here we use the i2c_register_board_info() function to register the i2c device. First, we use the I2C_BOARD_INFO macro to define the i2c device information:
static struct at24_platform_data at24_platdata = {
.byte_len = 8192,
.page_size = 16,
};
static struct i2c_board_info mini2440_i2c_devices[] = {
{
I2C_BOARD_INFO("24c08", 0x50),
.platform_data = &at24_platdata,
}
};
The i2c address of at24c08 on mini2440 is 0x50, and it is mounted on i2c0. Complete the registration in mini2440_machine_init:
i2c_register_board_info(0, mini2440_i2c_devices, ARRAY_SIZE(mini2440_i2c_devices));
The first parameter needs attention, which is the bus number of i2c.
Finally, please remember to include these two header files:
4. at24c08 driver support The driver code uses the default drivers/misc/eeprom/at24.c, and the configuration is as follows: Device Drivers ---> [*] Misc devices ---> EEPROM support ---> -*- I2C EEPROMs from most vendors 5. Verification So how do we verify that the i2c driver and i2c settings we added are matched successfully? Enter this directory: /sys/bus/i2c/drivers/at24, and then you can see a file 0-0050, indicating that the i2c driver and i2c device are matched successfully. //2016.3.27 add The eeprom driver that comes with linux may not be convenient for testing. For this reason, I wrote a simple i2c driver to test at24c08. The code is as follows: #include #include #include #include #include #include #include MODULE_LICENSE("GPL"); struct at24_data { struct cdev cdev; struct i2c_client *client; }; int at24_read_block(struct i2c_client *client, u8 addr, u8 len, u8 *values) { return i2c_smbus_read_i2c_block_data(client, addr, len, values); } int at24_write_block(struct i2c_client *client, u8 addr, u8 len, u8 *values) { return i2c_smbus_write_i2c_block_data(client, addr, len, values); } #define BLOCK_MAX 32 static size_t at24_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { struct at24_data *at24 = file->private_data; int whether; u8 block[BLOCK_MAX]; if (count > BLOCK_MAX) count = BLOCK_MAX; num = at24_read_block(at24->client, *pos, count, block); if (copy_to_user(buf, block, num)) { return -EFAULT; } else { *pos += whether; return num; } } static size_t at24_write(struct file *file, char __user *buf, size_t count, loff_t *pos) { struct at24_data *at24 = file->private_data; int whether; u8 block[BLOCK_MAX]; if (count > BLOCK_MAX) count = BLOCK_MAX; if (copy_from_user(block, buf, count)) { return -EFAULT; } else { num = at24_write_block(at24->client, *pos, count, block); *pos += whether; return num; } } static size_t at24_open(struct inode *inode, struct file *file) { struct at24_data *at24; at24 = container_of(inode->i_cdev, struct at24_data, cdev); file->private_data = at24; return 0; } static size_t at24_close(struct inode *inode, struct file *file) { file->private_data = NULL; return 0; } static struct file_operations at24_fops = { .open = at24_open, .release = at24_close, .read = at24_read, .write = at24_write, }; static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct at24_data *at24; int retval = 0; dev_t dev_id; at24 = kzalloc(sizeof(struct at24_data), GFP_KERNEL); if (!at24) { return -ENOMEM; } at24->client = client; retval = alloc_chrdev_region(&dev_id, 0, 1, "at24c08"); if (retval < 0) { dev_err(&client->dev, "unable to allocate char device regionn"); goto err_out; } cdev_init(&at24->cdev, &at24_fops); retval = cdev_add(&at24->cdev, dev_id, 1); if (retval < 0) { dev_err(&client->dev, "unable to register char devicen"); goto err_free_region; } i2c_set_clientdata(client, at24); return 0; err_free_region: unregister_chrdev_region(dev_id, 1); err_out: kfree(at24); return -1; } static int at24_remove(struct i2c_client *client) { struct at24_data *at24 = i2c_get_clientdata(client); cdev_del(&at24->cdev); kfree(at24); unregister_chrdev_region(at24->cdev.dev, 1); return 0; } static struct i2c_device_id at24_ids[] = { { "at24c08", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, at24_ids); static struct i2c_driver at24_driver = { .driver = { .name = "at24c08", }, .id_table = at24_ids, .probe = at24_probe, .remove = at24_remove, }; static int __init at24_init(void) { return i2c_add_driver(&at24_driver); } static void __exit at24_exit(void) { i2c_del_driver(&at24_driver); } module_init(at24_init); module_exit(at24_exit); After compiling, first insmod, then mknod, and test the app program as follows: #include #include #include #include #include #include //#define TEST_WRITE 1 #define TEST_READ 1 int main(int argc, char *argv[]) { int fd; int i; char buf[8]; if (argc < 2) exit(1); fd = open(argv[1], O_RDWR); if (fd < 0) exit(1); #ifdef TEST_WRITE for (i = 0; i < sizeof(buf); i++) buf[i] = i; write(fd, buf, sizeof(buf)); #endif #ifdef TEST_READ memset(buf, 0, sizeof(buf)); read(fd, buf, sizeof(buf)); for (i = 0; i < sizeof(buf); i++) printf("%d ", buf[i]); printf("n"); #endif close(fd); exit(0); } The final test shows that the written data can be read correctly even after power failure, indicating that the program is ok. // 2016-05-15 add Another i2c read function int at24_read_array(struct i2c_client *client, u8 addr, u8 len, u8 *vals) { struct i2c_msg msgs[] = { { .addr = client->addr, .flags = 0, .len = 1, .buf = &addr }, { .addr = client->addr, .flags = I2C_M_RD, .len = len, .buf = waltz } }; int ret; ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); if (ret < 0) printk("i2c_transfer errorn"); return right; } Here, i2c_transfer is used to operate i2c. Pay attention to the return value of i2c_transfer. The correct value returned is the number of i2c_msgs transmitted.
Previous article:ARM clock learning
Next article:I2C of mini2440 bare metal
Recommended ReadingLatest update time:2024-11-22 23:14
- Naxin Micro and Xinxian jointly launched the NS800RT series of real-time control MCUs
- How to learn embedded systems based on ARM platform
- Summary of jffs2_scan_eraseblock issues
- Application of SPCOMM Control in Serial Communication of Delphi7.0
- Using TComm component to realize serial communication in Delphi environment
- Bar chart code for embedded development practices
- Embedded Development Learning (10)
- Embedded Development Learning (8)
- Embedded Development Learning (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Intel promotes AI with multi-dimensional efforts in technology, application, and ecology
- ChinaJoy Qualcomm Snapdragon Theme Pavilion takes you to experience the new changes in digital entertainment in the 5G era
- Infineon's latest generation IGBT technology platform enables precise control of speed and position
- Two test methods for LED lighting life
- Don't Let Lightning Induced Surges Scare You
- Application of brushless motor controller ML4425/4426
- Easy identification of LED power supply quality
- World's first integrated photovoltaic solar system completed in Israel
- Sliding window mean filter for avr microcontroller AD conversion
- What does call mean in the detailed explanation of ABB robot programming instructions?
- STMicroelectronics discloses its 2027-2028 financial model and path to achieve its 2030 goals
- 2024 China Automotive Charging and Battery Swapping Ecosystem Conference held in Taiyuan
- State-owned enterprises team up to invest in solid-state battery giant
- The evolution of electronic and electrical architecture is accelerating
- The first! National Automotive Chip Quality Inspection Center established
- BYD releases self-developed automotive chip using 4nm process, with a running score of up to 1.15 million
- GEODNET launches GEO-PULSE, a car GPS navigation device
- Should Chinese car companies develop their own high-computing chips?
- Infineon and Siemens combine embedded automotive software platform with microcontrollers to provide the necessary functions for next-generation SDVs
- Continental launches invisible biometric sensor display to monitor passengers' vital signs
- Why can't my 51 output a 125K square wave?
- Protel99SE Metal Slot Making
- [Allwinner heterogeneous multi-core AI intelligent vision V853 development board evaluation] NPU test YOLOV3
- 5509 Misunderstanding of using XF pin in DSP program interrupt
- Design of frame transceiver for multifunctional vehicle bus controller chip
- ADI latest Chinese information
- Common Mistakes in MSP430 Programming
- Mathematics is not a formula, but a way of thinking
- [2022 Digi-Key Innovation Design Competition] K210 driver serial port
- Considerations for selecting solid-state relays