Overview
The DS1302 module is a real-time clock chip with trickle current charging capability.
![](/Uploads/Temp/image/20240422/95.png)
Hardware installation
l DS1302 module's VCC terminal is connected to J2 Pin2 of DEBIX Model A I/O board
l DS1302 module's CLK terminal is connected to J2 Pin33 of DEBIX Model A I/O board
l DS1302 module's DAT terminal is connected to J2 Pin31 of DEBIX Model A I/O board
l DS1302 module's RST terminal is connected to J2 Pin32 of DEBIX Model A I/O board
l DS1302 module's GND terminal is connected to J2 Pin39 of DEBIX Model A I/O board
Modify the device tree imx8mp-evk.dts
1.Add DS1302 node under / node:
/ {
DS1302: DS1302 {
compatible = "DS1302";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_DS1302>;
clk-gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
dat-gpios = <&gpio5 4 GPIO_ACTIVE_LOW>;
rst-gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
status = "okay";
};
};
2. Compile and replace the device tree file
l Compile the device tree in the source directory: make ARCH=arm64 CROSS_COMPILE=aarch64-none-linux-gnu- dtbs
l Copy the compiled new device tree file arch/arm64/boot/dts/freescale/imx8mp-evk.dtb to the /boot directory of DEBIX and restart DEBIX.
3. Check whether dts contains the modified device tree node.
Run the command ls/sys/firmware/devicetree/base/
Write and Load DriversThe driver code is as follows:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/of_irq.h>
#include <linux/timer.h>
struct device_node *DS1302_device_node;
struct property *DS1302_node_property;
int DS1302_CLK_gpio_index = 0;
int DS1302_DAT_gpio_index = 0;
int DS1302_RST_gpio_index = 0;
unsigned long flags;
typedef struct{
int year;
int week;
int month;
int day;
int hour;
int minute;
int second;
} DS1302Time_t;
#define RST_L gpio_set_value(DS1302_RST_gpio_index, 0)
#define RST_H gpio_set_value(DS1302_RST_gpio_index, 1)
#define CLK_L gpio_set_value(DS1302_CLK_gpio_index, 0)
#define CLK_H gpio_set_value(DS1302_CLK_gpio_index, 1)
#define DAT_L gpio_set_value(DS1302_DAT_gpio_index, 0)
#define DAT_H gpio_set_value(DS1302_DAT_gpio_index, 1)
void timer_cb_func(struct timer_list *tl);
DEFINE_TIMER(timer, timer_cb_func);
void DS1302_GPIOInit(void){
gpio_direction_output(DS1302_RST_gpio_index, 0);
gpio_direction_output(DS1302_CLK_gpio_index, 0);
}
void DS1302_DATSetOutput(void){
gpio_direction_output(DS1302_DAT_gpio_index, 0);
}
void DS1302_DATSetInput(void){
gpio_direction_input(DS1302_DAT_gpio_index);
}
void DS1302_write_onebyte(u8 data) // 向DS1302发送一字节数据
{
u8 count=0;
DS1302_DATSetOutput();
CLK_L;
for(count=0;count<8;count++)
{
CLK_L;
if(data & 0x01)
DAT_H;
else
DAT_L;
CLK_H;
data>>=1;
}
}
void DS1302_wirte_rig(u8 address, u8 data)
{
u8 temp1 = address;
u8 temp2 = data;
RST_L;
CLK_L;
udelay(1);
RST_H;
udelay(2);
DS1302_write_onebyte(temp1);
DS1302_write_onebyte(temp2);
RST_L;
CLK_L;
udelay(2);
}
u8 ds1302_read_rig(u8 address)
{
u8 temp3 = address;
u8 count = 0;
u8 return_data=0x00;
RST_L;
CLK_L;
udelay(3);
RST_H;
udelay(3);
DS1302_write_onebyte(temp3);
DS1302_DATSetInput();
udelay(2);
for(count=0;count<8;count++)
{
udelay(2);
return_data>>=1;
CLK_H;
udelay(4);
CLK_L;
udelay(14);
if (gpio_get_value(DS1302_DAT_gpio_index)){
return_data=return_data|0x80;
}
}
udelay(2);
RST_L;
DAT_L;
return return_data;
}
void DS1302_Init(void){
DS1302_GPIOInit();
DS1302_wirte_rig(0x8e, 0x00);
DS1302_wirte_rig(0x80,0x30);//seconds 0-59
DS1302_wirte_rig(0x82,0x30);//minutes 0-59
DS1302_wirte_rig(0x84,0x10);//hours 1-12/0-23
DS1302_wirte_rig(0x86,0x15);//date 0-30
DS1302_wirte_rig(0x88,0x03);//months 1-12
DS1302_wirte_rig(0x8a,0x07);//days 1-7
DS1302_wirte_rig(0x8c,0x23);//year 0-99
DS1302_wirte_rig(0x8e,0x80);
}
DS1302Time_t DS1302_ReadTime(void)
{
DS1302Time_t timeNow;
timeNow.second = (ds1302_read_rig(0x81) >> 4) * 10 + (ds1302_read_rig(0x81) & 0x0f);
timeNow.minute = ((ds1302_read_rig(0x83) >> 4) & (0x07)) * 10 + (ds1302_read_rig(0x83) & 0x0f);
timeNow.hour = (ds1302_read_rig(0x85) >> 4) * 10 + (ds1302_read_rig(0x85) & 0x0f);
timeNow.day = (ds1302_read_rig(0x87) >> 4) * 10 + (ds1302_read_rig(0x87)&0x0f);
timeNow.month = (ds1302_read_rig(0x89) >> 4) * 10 + (ds1302_read_rig(0x89)&0x0f);
timeNow.week = ds1302_read_rig(0x8B);
timeNow.year = (ds1302_read_rig(0x8D) >> 4) * 10 + (ds1302_read_rig(0x8D) & 0x0f)+2000;
return timeNow;
}
void timer_cb_func(struct timer_list *tl)
{
DS1302Time_t time;
time = DS1302_ReadTime();
printk("%d-%d-%d %d:%d:%d ..\n",
time.year, time.month, time.day, time.hour, time.minute, time.second);
mod_timer(&timer, jiffies + 1 * HZ);
}
int misc_open (struct inode *inode, struct file *file){
printk("misc_open..\n");
return 0;
}
int misc_release (struct inode *inode, struct file *file){
printk("misc_release..\n");
return 0;
}
static const struct file_operations misc_fops={
.owner = THIS_MODULE,
.open = misc_open,
.release = misc_release,
};
static struct miscdevice misc_dev={
.minor = MISC_DYNAMIC_MINOR,
.name = "DS1302",
.fops = &misc_fops
};
int DS1302_probe(struct platform_device *pd){
int ret;
DS1302_device_node = of_find_node_by_path("/DS1302");
if(DS1302_device_node == NULL){
printk("of_find_node_by_path err..\n");
return -1;
}
DS1302_CLK_gpio_index = of_get_named_gpio(DS1302_device_node, "clk-gpios", 0);
if (DS1302_CLK_gpio_index < 0)
{
printk("of_get_name_gpio gpios err..\n");
return -1;
}
ret = gpio_request(DS1302_CLK_gpio_index, "clk-gpios");
if (ret<0){
printk("gpio_request clk-gpios is error \n");
return -1;
}
DS1302_DAT_gpio_index = of_get_named_gpio(DS1302_device_node, "dat-gpios", 0);
if (DS1302_DAT_gpio_index < 0)
{
printk("of_get_name_gpio gpios err..\n");
return -1;
}
ret = gpio_request(DS1302_DAT_gpio_index, "dat-gpios");
if (ret < 0)
{
printk("gpio_request dat-gpios is error \n");
return -1;
}
DS1302_RST_gpio_index = of_get_named_gpio(DS1302_device_node, "rst-gpios", 0);
if (DS1302_RST_gpio_index < 0)
{
printk("of_get_name_gpio gpios err..\n");
return -1;
}
ret = gpio_request(DS1302_RST_gpio_index, "rst-gpios");
if (ret < 0)
{
printk("gpio_request rst-gpios is error \n");
return -1;
}
DS1302_Init();
ret = misc_register(&misc_dev);
if(ret<0){
printk("misc_register err..\n");
return -1;
}
timer.expires = jiffies + 1 * HZ;
add_timer(&timer);
printk("DS1302_probe..\n");
return 0;
}
int DS1302_remove(struct platform_device *pd){
misc_deregister(&misc_dev);
gpio_free(DS1302_CLK_gpio_index);
gpio_free(DS1302_DAT_gpio_index);
gpio_free(DS1302_RST_gpio_index);
del_timer(&timer);
printk("DS1302_remove..\n");
return 0;
}
static const struct platform_device_id DS1302_idtable[] = {
{.name = "DS1302",},
{}
};
static const struct of_device_id DS1302_data_dt_ids[] = {
{.compatible = "DS1302"},
{/* sentinel */}};
static struct platform_driver DS1302_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "DS1302",
.of_match_table = of_match_ptr(DS1302_data_dt_ids),
},
.probe = DS1302_probe,
.remove = DS1302_remove,
.id_table = DS1302_idtable,
};
module_platform_driver(DS1302_driver);
MODULE_LICENSE("GPL");
1. Run the above command to compile the driver make will get the .ko file
2. Copy the .ko file to DEBIX, run the command sudo insmod DS1302.ko
3. Run the command sudo dmesg | tail -1 , check the driver print information:
![](/Uploads/Temp/image/20240422/97.png)
4. You can see that the probe function matches the device tree successfully.
Test result
Run the command dmesg |tail -20 , you can see the time information printed at 1s interval: