生活随笔
收集整理的這篇文章主要介紹了
                                
BL5372 RTC linux驱动
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
 
                                
                            
                            
                            硬件
 BL5372 RTC
 https://www.belling.com.cn/product_info.html?id=65驅動 
#include <linux/i2c.h>
#include <linux/bcd.h>
#include <linux/rtc.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>#define DEG 0#define DRV_VERSION "0.0.1"#define TIME24 1
#define RS5C_ADDR(R)		(((R) << 4) | 0)
#define RS5C372_REG_SECS	0
#define RS5C372_REG_MINS	1
#define RS5C372_REG_HOURS	2
#define RS5C372_REG_WDAY	3
#define RS5C372_REG_DAY		4
#define RS5C372_REG_MONTH	5
#define RS5C372_REG_YEAR	6
#define RS5C372_REG_TRIM	7
#define RS5C_REG_ALARM_A_MIN	8			
#define RS5C_REG_ALARM_A_HOURS	9
#define RS5C_REG_ALARM_A_WDAY	10#define RS5C_REG_ALARM_B_MIN	11			
#define RS5C_REG_ALARM_B_HOURS	12
#define RS5C_REG_ALARM_B_WDAY	13			
#define RS5C_REG_CTRL1		14
#define RS5C_REG_CTRL2		15
#define DEVICE_ADDR        0x32	#if 0
static unsigned char bin2bcd(unsigned  val
)
{return ((val 
/ 10) << 4) + val 
% 10;
}
static unsigned bcd2bin(unsigned char val
)
{return (val 
& 0x0f) + (val 
>> 4) * 10;
}
#endifstatic unsigned rs5c_reg2hr(unsigned reg
)
{
#if TIME24return bcd2bin(reg 
& 0x3f);
#elseunsigned	hour
;hour 
= bcd2bin(reg 
& 0x1f);if (hour 
== 12)hour 
= 0;if (reg 
& 0x20)hour 
+= 12;return hour
;
#endif
}static unsigned rs5c_hr2reg(unsigned hour
)
{#if TIME24return bin2bcd(hour
);#elseif (hour 
> 12)return 0x20 | bin2bcd(hour 
- 12);if (hour 
== 12)return 0x20 | bin2bcd(12);if (hour 
== 0)return bin2bcd(12);return bin2bcd(hour
);
#endif
}
static struct i2c_driver bl5372_driver
;struct bl5372 
{struct rtc_device 
*rtc
;struct device 
*dev
;int irq
;
};static int i2c_write_bytes(struct i2c_client 
*client
, uint8_t 
*data
, uint16_t len
)
{struct i2c_msg msg
;int ret
=-1;msg
.flags 
= !I2C_M_RD
;msg
.addr 
= client
->addr
;msg
.len 
= len
;msg
.buf 
= data
;ret
=i2c_transfer(client
->adapter
, &msg
,1);return ret
;
}static int bl5372_get_datetime(struct i2c_client 
*client
, struct rtc_time 
*tm
)
{struct bl5372 
*bl5372 
= i2c_get_clientdata(client
);unsigned char buf
[7] = { RS5C_ADDR(RS5C372_REG_SECS
) };struct i2c_msg msgs
[] = {{.addr 
= client
->addr
,.flags 
= 0,.len 
= 1,.buf 
= buf
},{.addr 
= client
->addr
,.flags 
= I2C_M_RD
,.len 
= 7,.buf 
= buf
},};if ((i2c_transfer(client
->adapter
, msgs
, 2)) != 2) {dev_err(&client
->dev
, "%s: read error\n", __func__);return -EIO
;}tm
->tm_sec 
= bcd2bin(buf
[0] & 0x7f);tm
->tm_min 
= bcd2bin(buf
[1] & 0x7f);tm
->tm_hour 
= rs5c_reg2hr(buf
[2]);tm
->tm_mday 
= bcd2bin(buf
[4] & 0x7f);;tm
->tm_wday 
= bcd2bin(buf
[3] & 0x7f);tm
->tm_mon 
= rs5c_reg2hr(buf
[5])-1;tm
->tm_year 
= bcd2bin(buf
[6] & 0x7f)+100;buf
[0]= RS5C_ADDR(RS5C_REG_CTRL2
);struct i2c_msg msgs2
[] = {{.addr 
= client
->addr
,.len 
= 1,.buf 
= buf
},{.addr 
= client
->addr
,.flags 
= I2C_M_RD
,.len 
= 1,.buf 
= buf
},};if ((i2c_transfer(client
->adapter
, msgs2
, 2)) != 2) {dev_err(&client
->dev
, "%s: read error\n", __func__);return -EIO
;}if(buf
[0]&0x20){tm
->tm_hour
= (tm
->tm_hour
<24)? (tm
->tm_hour
):(24-tm
->tm_hour
);}else{tm
->tm_hour
=(tm
->tm_hour
<24-8)? (tm
->tm_hour
+8):(tm
->tm_hour
+8-24);}if (rtc_valid_tm(tm
) < 0)dev_err(&client
->dev
, "retrieved date/time is not valid.\n");return 0;
}static int bl5372_set_datetime(struct i2c_client 
*client
, struct rtc_time 
*tm
)
{struct bl5372 
*bl5372 
= i2c_get_clientdata(client
);int i
, err
;unsigned char buf
[7];buf
[0]= RS5C_ADDR(RS5C_REG_CTRL2
);struct i2c_msg msgs2
[] = {{.addr 
= client
->addr
,.len 
= 1,.buf 
= buf
},{.addr 
= client
->addr
,.flags 
= I2C_M_RD
,.len 
= 1,.buf 
= buf
},};if ((i2c_transfer(client
->adapter
, msgs2
, 2)) != 2) {dev_err(&client
->dev
, "%s: read error\n", __func__);return -EIO
;}if((buf
[0]&0x20)== 0){buf
[0] |= (1<<5); err 
= i2c_master_send(client
, buf
, 1);}
buf
[0] = bin2bcd(tm
->tm_sec
);buf
[1] = bin2bcd(tm
->tm_min
);buf
[2] = rs5c_hr2reg(tm
->tm_hour
);buf
[3] = bin2bcd(tm
->tm_wday 
& 0x07); buf
[4] = bin2bcd(tm
->tm_mday
);buf
[5] = bin2bcd(tm
->tm_mon
)+1;tm
->tm_year 
-= 100;buf
[6] = bin2bcd(tm
->tm_year 
% 100);err 
= i2c_smbus_write_byte_data(client
, RS5C_ADDR(RS5C372_REG_SECS
),   buf
[0]);i2c_smbus_write_byte_data(client
, RS5C_ADDR(RS5C372_REG_MINS
) ,  buf
[1]);i2c_smbus_write_byte_data(client
, RS5C_ADDR(RS5C372_REG_HOURS
) , buf
[2]);i2c_smbus_write_byte_data(client
, RS5C_ADDR(RS5C372_REG_WDAY
) ,  buf
[3]);i2c_smbus_write_byte_data(client
, RS5C_ADDR(RS5C372_REG_DAY
) ,   buf
[4]);i2c_smbus_write_byte_data(client
, RS5C_ADDR(RS5C372_REG_MONTH
) , buf
[5]);i2c_smbus_write_byte_data(client
, RS5C_ADDR(RS5C372_REG_YEAR
) ,  buf
[6]);return 0;
}#ifdef CONFIG_RTC_INTF_DEV
static int bl5372_rtc_ioctl(struct device 
*dev
, unsigned int cmd
, unsigned long arg
)
{struct bl5372 
*bl5372 
= i2c_get_clientdata(to_i2c_client(dev
));struct rtc_time tm
;switch (cmd
) {case RTC_RD_TIME
:return 0;case RTC_SET_TIME
:if (copy_from_user(&tm
, arg
, sizeof(tm
)))return -EFAULT
;bl5372_set_datetime(to_i2c_client(dev
), &tm
);return 0;default:return -ENOIOCTLCMD
;}}
#else
#define bl5372_rtc_ioctl NULL
#endifstatic int bl5372_rtc_read_time(struct device 
*dev
, struct rtc_time 
*tm
)
{return bl5372_get_datetime(to_i2c_client(dev
), tm
);
}static int bl5372_rtc_set_time(struct device 
*dev
, struct rtc_time 
*tm
)
{return bl5372_set_datetime(to_i2c_client(dev
), tm
);
}static int bl5372_rtc_getalarm(struct device 
*dev
, struct rtc_wkalrm 
*wkalrm
)
{struct bl5372 
*bl5372 
= i2c_get_clientdata(to_i2c_client(dev
));return 0;
}static int bl5372_rtc_setalarm(struct device 
*dev
, struct rtc_wkalrm 
*wkalrm
)
{struct bl5372 
*bl5372 
= i2c_get_clientdata(to_i2c_client(dev
));return 0;
}static int bl5372_rtc_alarm_irq_enable(struct device 
*dev
, unsigned int enabled
)
{struct bl5372 
*bl5372 
= i2c_get_clientdata(to_i2c_client(dev
));return 0;
}static const struct rtc_class_ops bl5372_rtc_ops 
= {.ioctl		
= bl5372_rtc_ioctl
,.read_time	
= bl5372_rtc_read_time
,.set_time	
= bl5372_rtc_set_time
,.read_alarm             
= bl5372_rtc_getalarm
,.set_alarm              
= bl5372_rtc_setalarm
,.alarm_irq_enable       
= bl5372_rtc_alarm_irq_enable
};static int bl5372_probe(struct i2c_client 
*client
,const struct i2c_device_id 
*id
)
{struct bl5372 
*bl5372
;if (!i2c_check_functionality(client
->adapter
, I2C_FUNC_I2C
)){return -ENODEV
;}bl5372 
= devm_kzalloc(&client
->dev
, sizeof(struct bl5372
),GFP_KERNEL
);if (!bl5372
){return -ENOMEM
;}device_init_wakeup(&client
->dev
, 1);i2c_set_clientdata(client
, bl5372
);bl5372
->rtc 
= devm_rtc_device_register(&client
->dev
,bl5372_driver
.driver
.name
,&bl5372_rtc_ops
, THIS_MODULE
);if (IS_ERR(bl5372
->rtc
)){return PTR_ERR(bl5372
->rtc
);}return 0;
}static int bl5372_remove(struct i2c_client 
*client
)
{return 0;
}static const struct i2c_device_id bl5372_id
[] = {{ "bl5372", 0 },{ }
};
MODULE_DEVICE_TABLE(i2c
, bl5372_id
);#ifdef CONFIG_OF
static const struct of_device_id bl5372_of_match
[] = {{ .compatible 
= "beilin,bl5372" },{}
};
MODULE_DEVICE_TABLE(of
, bl5372_of_match
);
#endifstatic struct i2c_driver bl5372_driver 
= {.driver		
= {.name	
= "rtc-bl5372",.owner	
= THIS_MODULE
,.of_match_table 
= of_match_ptr(bl5372_of_match
),},.probe		
= bl5372_probe
,.remove		
= bl5372_remove
,.id_table	
= bl5372_id
,
};module_i2c_driver(bl5372_driver
);MODULE_AUTHOR("Zhengweiqing <1548889230@qq.com>");
MODULE_DESCRIPTION("Beilin BL5372 RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION
);
                            總結
                            
                                以上是生活随笔為你收集整理的BL5372 RTC linux驱动的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                            
                                如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。