生活随笔
收集整理的這篇文章主要介紹了
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驱动的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。