(Part of the single bus is a single bus, the RTC is part of the RTC, can not be confused)
DS2417 is a time management chip that is connected via a single bus and CPU.
The Linux kernel version uses the 2.6.35,CPU Freescale imx53.
First, the single-bus driver is located in/kernel/drivers/w1, which has two folders, namely Masters and slaves. IMX53CPU single bus controller part of the code under Masters, from the master-slave relationship, Masters is the main part of a single bus, slaves is a single bus from the part. So the slaves contains a variety of chips supported by a single bus. However, our kernel does not support the ds2417 chip, and the relevant code needs to be added by ourselves. The code in Masters we do not need to change, in the W1 driver we just need to add w1_ds2417.c and w1_ds2417.h two files under slaves.
W1_DS2417.C Source:
#include <linux/types.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/
module.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/idr.h> #include ". /w1.h "#include". /w1_int.h "#include". /w1_family.h "#include" w1_ds2417.h "static int w1_ds2417_io (struct device *dev, char *buf, size_t count,int io) {struc
T W1_slave *sl = container_of (dev, struct w1_slave, dev);
if (!dev) return 0;
Mutex_lock (&sl->master->mutex);
W1_reset_bus (Sl->master);
if (!w1_reset_select_slave (SL)) {if (!io) {w1_write_8 (Sl->master, W1_ds2417_read_clock);
Count = W1_read_block (Sl->master, buf, Count);
} else {w1_write_8 (sl->master, W1_ds2417_write_clock);
W1_write_block (Sl->master, buf, Count); /* XXX w1_write_block returns void, not N_written */}} mutex_unlock (&sl-≫master->mutex);
return count;
} int w1_ds2417_read (struct device *dev, char *buf, size_t count) {return w1_ds2417_io (dev, buf, count, 0);}
int w1_ds2417_write (struct device *dev, char *buf, size_t count) {return w1_ds2417_io (dev, buf, count, 1);}
Static DEFINE_IDR (RTC_IDR);
Static Define_mutex (Rtc_idr_lock);
static int new_rtc_id (void) {int ret;
while (1) {int id;
ret = Idr_pre_get (&RTC_IDR, Gfp_kernel);
if (ret = = 0) return-enomem;
Mutex_lock (&rtc_idr_lock);
ret = Idr_get_new (&RTC_IDR, NULL, &id);
Mutex_unlock (&rtc_idr_lock);
if (ret = = 0) {ret = id & max_id_mask;
Break
} else if (ret = =-eagain) {continue;
} else {break;
}} return ret;
} static void release_rtc_id (int id) {mutex_lock (&rtc_idr_lock);
Idr_remove (&RTC_IDR, id);
Mutex_unlock (&rtc_idr_lock);
} static int W1_ds2417_add_slave (struct w1_slave *sl) {int ret;
int id;
struct Platform_device *pdev; id = new_rtC_ID ();
if (ID < 0) {ret = ID;
Goto Noid;
} Pdev = Platform_device_alloc (ds2417_dev_name, id);
if (!pdev) {ret =-enomem;
Goto pdev_alloc_failed;
} pdev->dev.parent = &sl->dev;
ret = Platform_device_add (Pdev);
if (ret) goto pdev_add_failed;
Dev_set_drvdata (&sl->dev, Pdev);
Goto success;
Pdev_add_failed:platform_device_unregister (Pdev);
pdev_alloc_failed:release_rtc_id (ID);
Noid:success:return ret; } static void W1_ds2417_remove_slave (struct w1_slave *sl) {struct Platform_device *pdev = Dev_get_drvdata (&sl->d
EV);
int id = pdev->id;
Platform_device_unregister (Pdev);
release_rtc_id (ID); } static struct W1_family_ops w1_ds2417_fops = {. Add_slave = W1_ds2417_add_slave,. Remove_slave = W1_ds2417_remove_
Slave,};
static struct w1_family w1_family_ds2417 = {. FID = w1_family_ds2417,. fops = &w1_ds2417_fops,};
static int __init w1_ds2417_init (void) {int err;
Idr_init (&RTC_IDR); Err = W1_register_faMily (&w1_family_ds2417);
if (err) return err;
return 0;
} static void __exit W1_ds2417_fini (void) {w1_unregister_family (&w1_family_ds2417);
Idr_destroy (&RTC_IDR);
} export_symbol (W1_ds2417_read);
Export_symbol (W1_ds2417_write);
Module_init (W1_ds2417_init);
Module_exit (W1_ds2417_fini);
Module_license ("GPL");
Module_author ("SS"); Module_description ("1-wire DS2417 family, RTC chip.");
W1_ds2417.h Source:
#ifndef __w1_ds2417_h__
#define __W1_DS2417_H__/
* Known commands to the DS2417 chip */
#define DS2417_DEV_ NAME "DS2417-RTC"
#define W1_ds2417_read_clock 0x66
#define W1_ds2417_write_clock 0x99
# Define W1_ds2417_read_rom 0x33
#define W1_DS2417_MATCH_ROM 0x55
#define W1_ds2417_search_rom 0xF0
#define W1_ds2417_skip_rom 0xCC
extern int w1_ds2417_read (struct device *dev, Char *buf, size_t count);
extern int W1_ds2417_write (struct device *dev, char *buf, size_t count);
#endif
Added before the last endmenu of the/kernel/drivers/w1/slaves/kconfig file:
Config w1_slave_ds2417
tristate "Dallas 2417 SLAVE Support"
At the end of the/kernel/drivers/w1/slaves/makefile file, add:
obj-$ (config_w1_slave_ds2417) + = W1_DS2417.O
The above is the addition of single-bus driver information, the registration of single-bus driver information is through the/kernel/drivers/w1/masters/mxc_w1.c:
static struct Platform_driver Mxc_w1_driver = {
. Driver = {
. Name = "Mxc_w1",
},
. Probe = mxc_w1_probe,
.remove = Mxc_w1_remove,
};
static int __init mxc_w1_init (void)
{
return platform_driver_register (&mxc_w1_driver);
}
Platform_driver_register () function, so the registration of device information should also be hung on the platform bus.
Here is the addition of single-Bus device information (the source file where the device information is registered varies depending on the CPU):
First, make sure that you have the following code in/KERNEL/ARCH/ARM/MACH-MX5/DEVICES.C:
static struct resource mxc_w1_master_resources[] = {
{
. start = Owire_base_addr,
. End = Owire_base_ ADDR + sz_4k-1,
. Flags = Ioresource_mem,
},
{
. start = Mxc_int_owire,
. Flags = IORESOURCE_IRQ,
},
};
struct Platform_device mxc_w1_master_device = {
. Name = "Mxc_w1",
. id = 0,
. num_resources = Array_size ( mxc_w1_master_resources),
. Resource = Mxc_w1_master_resources,
};
The following code is in the/kernel/arch/arm/mach-mx5/devices.h:
extern struct Platform_device mxc_w1_master_device;
The code in DEVICES.C and Devices.h is generally present, so be sure to do so.
Then you need to add the following in the/KERNEL/ARCH/ARM/MACH-MX5/MX53_SMD.C file:
static struct Mxc_w1_config mxcw1_data= {
. search_rom_accelerator = 1,
};
static void __init mxc_board_init (void)
{...
Mxc_register_device (&mxc_w1_master_device,&mxcw1_data);
Here the single-bus section has been completed.
Let's tidy up the RTC part of the Code, the ds2417 implementation is the function of saving time.
Add the Rtc-ds2417.c file under/KERNEL/DRIVERS/RTC, the source code is:
#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/ platform_device.h> #include <linux/rtc.h> #include <linux/io.h> #include <linux/bcd.h> #include <linux/slab.h> #include ". /w1/w1.h "#include".
/w1/slaves/w1_ds2417.h "#define Drv_version" 0.1.1 "struct Rtc_plat_data {struct device *dev;
struct Rtc_device *RTC;
struct device *w1_dev;
spinlock_t lock;
};
static int ds2417_rtc_set_time (struct device *dev, struct rtc_time *tm) {int ret = 0;
unsigned long rtc_cnt = 0;
Char Rtc_wr_buf[5] = {0};
struct Platform_device *pdev = to_platform_device (dev);
struct Rtc_plat_data *pdata = Platform_get_drvdata (Pdev);
Rtc_tm_to_time (TM,&RTC_CNT);
Rtc_wr_buf[0] = 0x0c;
RTC_WR_BUF[1] = rtc_cnt & 0xFF;
RTC_WR_BUF[2] = (rtc_cnt >> 8) & 0xFF;
RTC_WR_BUF[3] = (rtc_cnt >>) & 0xFF;
RTC_WR_BUF[4] = (rtc_cnt >>) & 0xFF; ret = W1_ds2417_write (pdata->W1_dev, Rtc_wr_buf, 5);
return ret;
} static int ds2417_rtc_read_time (struct device *dev, struct rtc_time *tm) {int ret = 0;
unsigned long rtc_cnt = 0;
Char Rtc_time_buf[5] = {0};
struct Platform_device *pdev = to_platform_device (dev);
struct Rtc_plat_data *pdata = Platform_get_drvdata (Pdev);
ret = W1_ds2417_read (Pdata->w1_dev, Rtc_time_buf, 5);
Rtc_cnt + = rtc_time_buf[1] + (rtc_time_buf[2] << 8) + (Rtc_time_buf[3] << +) + (Rtc_time_buf[4] << 24);
Rtc_time_to_tm (RTC_CNT,TM);
return ret; } static const struct Rtc_class_ops ds2417_rtc_ops = {. Read_time = Ds2417_rtc_read_time,. Set_time = ds2417_rtc_set_t
IME,};
static int __devinit ds2417_rtc_probe (struct platform_device *pdev) {int retval = 0;
struct Rtc_device *RTC;
struct Rtc_plat_data *pdata;
pdata = Kzalloc (sizeof (*pdata), Gfp_kernel);
if (!pdata) {retval =-enomem;
Goto pdata_alloc_failed;
} Pdata->dev = &pdev->dev;
Pdata->w1_dev = pdev->dev.parent; Spin_Lock_init (&pdata->lock);
Platform_set_drvdata (Pdev, pdata);
RTC = Rtc_device_register (Pdev->name, &pdev->dev, &ds2417_rtc_ops, this_module);
if (Is_err (RTC)) return Ptr_err (RTC);
PDATA->RTC = RTC;
Pdata_alloc_failed:return retval;
} static int __devexit ds2417_rtc_remove (struct Platform_device *pdev) {return 0;}
static struct Platform_driver ds2417_platform_driver = {. Driver = {. Name = Ds2417_dev_name,. Owner = This_module,
},. Probe = Ds2417_rtc_probe,. Remove = __devexit_p (Ds2417_rtc_remove),};
static int __init ds2417_rtc_init (void) {return platform_driver_register (&ds2417_platform_driver);}
static void __exit ds2417_rtc_exit (void) {platform_driver_unregister (&ds2417_platform_driver);}
Module_init (Ds2417_rtc_init);
Module_exit (Ds2417_rtc_exit);
Module_description ("Dallas DS2417 RTC driver");
Module_version (drv_version);
Module_author ("SS");
Module_license ("GPL v2");
In the/kernel/drivers/rtc/kconfig file, add:
Config rtc_drv_ds2417
tristate "Maxim/dallas DS2417"
In the/kernel/drivers/rtc/makefile file, add:
obj-$ (config_rtc_drv_ds2417) + = RTC-DS2417.O
The RTC driver uses the platform bus, then there is a device corresponding to it, and the registration of the device that is registered in the RTC-DS2417.C is done in/kernel/drivers/w1/slaves/w1_ds2417.c.
Here ds2417 's driver code has been added, do not forget to use make Menuconfig:
Device Drivers--->
<*> Real time Clock--->
<*> Maxim/dallas DS2417
Remove the original RTC option.
Device Drivers--->
{*} Dallas ' s 1-wire support--->
1-wire Bus Masters--->
<*> Freescale MXC 1-wire busmaster
1-wire Slaves--->
<*> Dallas 2417 Slave support