#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <asm/delay.h>
#include <linux/delay.h>
void __iomem* reg_gpio_base_va = 0;
#define GPIO_ADRESS_BASE 0x12140000
#define GPIO_CTRL_ADRESS_BASE 0x12040000
#define HI_IO_GPIO_ADDRESS(x) (reg_gpio_base_va + ((x)-(GPIO_ADRESS_BASE)))
#define GPIO9_REG6 HI_IO_GPIO_ADDRESS(GPIO_ADRESS_BASE+(0x9000)+0x100)
#define I2C1_CTRL_REG6 HI_IO_GPIO_ADDRESS(GPIO_CTRL_ADRESS_BASE+0x005C)
#define I2C1_CTRL_REG7 HI_IO_GPIO_ADDRESS(GPIO_CTRL_ADRESS_BASE+0x0060)
#define GPIO9_CTRL_REG6 HI_IO_GPIO_ADDRESS(GPIO_CTRL_ADRESS_BASE+0x0134)
#define GPIO9_IS6 HI_IO_GPIO_ADDRESS(GPIO_ADRESS_BASE+(0x9000)+0x404)
#define GPIO9_IBE6 HI_IO_GPIO_ADDRESS(GPIO_ADRESS_BASE+(0x9000)+0x408)
#define GPIO9_IEV6 HI_IO_GPIO_ADDRESS(GPIO_ADRESS_BASE+(0x9000)+0x40C)
#define GPIO9_IC6 HI_IO_GPIO_ADDRESS(GPIO_ADRESS_BASE+(0x9000)+0x41C)
#define GPIO9_IE6 HI_IO_GPIO_ADDRESS(GPIO_ADRESS_BASE+(0x9000)+0x410)
#define GPIO9_DIR6 HI_IO_GPIO_ADDRESS(GPIO_ADRESS_BASE+(0x9000)+0x400)
#define GPIO_SET(g,r) ((*(volatile unsigned int *)g) |= (1<<(r)))
#define GPIO_RST(g,r) ((*(volatile unsigned int *)g) &= ~(1<<(r)))
#define GPIO_WRITE_REG(Addr, Value) ((*(volatile unsigned int *)(Addr))=(Value))
#define GPIO_READ_REG(Addr) (*(volatile unsigned int *)(Addr))
#define MODULE_VERSION_STRING "RTC-DS3231"
#define DS3232_DRIVER_VERSION "v1.0.0"
#define DS3231_REG_SECONDS 0x00
#define DS3231_REG_MINUTES 0x01
#define DS3231_REG_HOURS 0x02
#define DS3231_REG_AMPM 0x02
#define DS3231_REG_DAY 0x03
#define DS3231_REG_DATE 0x04
#define DS3231_REG_MONTH 0x05
#define DS3231_REG_CENTURY 0x05
#define DS3231_REG_YEAR 0x06
#define DS3231_REG_ALARM1 0x07 /* Alarm 1 BASE */
#define DS3231_REG_ALARM2 0x0B /* Alarm 2 BASE */
#define DS3231_REG_CR 0x0E /* Control register */
#define DS3231_REG_CR_nEOSC 0x80
#define DS3231_REG_CR_INTCN 0x04
#define DS3231_REG_CR_A2IE 0x02
#define DS3231_REG_CR_A1IE 0x01
#define DS3231_REG_SR 0x0F /* control/status register */
#define DS3231_REG_SR_OSF 0x80
#define DS3231_REG_SR_BSY 0x04
#define DS3231_REG_SR_A2F 0x02
#define DS3231_REG_SR_A1F 0x01
#define DEVICE_NAME "ds3231rtc"
#define I2C_ADDR_DS3231 0xD0
#ifdef DS3231_DEBUG
#define HI_MSG(x...) \
do { \
printk("%s->%d: ", __FUNCTION__, __LINE__); \
printk(x); \
printk("\n"); \
} while (0)
#else
#define HI_MSG(args...) do { } while (0)
#endif
#define HI_ERR(x...) \
do { \
printk(KERN_ALERT "%s->%d: ", __FUNCTION__, __LINE__); \
printk(KERN_ALERT x); \
printk(KERN_ALERT "\n"); \
} while (0)
#ifdef DS3231_DEBUG
static void display_rtc_time_in_bcd(struct rtc_time *rtime)
{
printk("tm_sec: %u\n", rtime->tm_sec);
printk("tm_min: %u\n", rtime->tm_min);
printk("tm_hour: %u\n", rtime->tm_hour);
printk("tm_mday: %u\n", rtime->tm_mday);
printk("tm_mon: %u\n", rtime->tm_mon);
printk("tm_year: %u\n", rtime->tm_year);
printk("tm_wday: %u\n", rtime->tm_wday);
printk("tm_yday: %u\n", rtime->tm_yday);
printk("tm_isdst: %u\n", rtime->tm_isdst);
}
#endif
struct rtc_time timess;
struct i2c_client *rtc_client;
struct rtc_device *rtc;
struct device *devicess;
int temp_flag=0;
extern int hi_i2c_dma_read(const struct i2c_client *client, unsigned int data_addr,
unsigned int reg_addr, unsigned int reg_addr_num,
unsigned int length);
extern int hi_i2c_dma_write(const struct i2c_client *client, unsigned int data_addr,
unsigned int reg_addr, unsigned int reg_addr_num,
unsigned int length);
const struct i2c_device_id ds3231_id[]=
{
{"ds3231rtc",2},
{}
};
static struct i2c_board_info i2c_ds3231rtc=
{
//参数一 名称
//参数二 从设备地址
I2C_BOARD_INFO("ds3231rtc", (I2C_ADDR_DS3231>>1)),
};
static void display_rtc_time_in_bcd(struct rtc_time *rtime)
{
printk("tm_sec: %u\n", rtime->tm_sec);
printk("tm_min: %u\n", rtime->tm_min);
printk("tm_hour: %u\n", rtime->tm_hour);
printk("tm_mday: %u\n", rtime->tm_mday);
printk("tm_mon: %u\n", rtime->tm_mon);
printk("tm_year: %u\n", rtime->tm_year);
printk("tm_wday: %u\n", rtime->tm_wday);
// printk("tm_yday: %u\n", rtime->tm_yday);
// printk("tm_isdst: %u\n", rtime->tm_isdst);
}
static int i2cdev_read(char *buf, unsigned int count,
unsigned int reg_addr_num, unsigned int data_byte_num)
{
int ret;
unsigned char tmp_buf0[4];
unsigned char tmp_buf1[4];
struct i2c_msg msg[2];
int idx = 0;
struct i2c_client * client;
client=rtc_client;
msg[0].addr = (I2C_ADDR_DS3231>>1);
msg[0].flags = client->flags & I2C_M_TEN;
msg[0].len = reg_addr_num;
msg[0].buf = tmp_buf0;
if(reg_addr_num == 1)
{
tmp_buf0[idx++] = buf[0]&0xff;
}
else
{
tmp_buf0[idx++] = (buf[0] >> 8)&0xff;
tmp_buf0[idx++] = buf[0]&0xff;
}
msg[1].addr = (I2C_ADDR_DS3231>>1);
msg[1].flags = client->flags & I2C_M_TEN;
msg[1].flags |= I2C_M_RD;
msg[1].len = data_byte_num;
msg[1].buf = tmp_buf1;
ret = i2c_transfer(client->adapter, msg, 2);
if (ret == 2)
{
if (data_byte_num == 2)
{
buf[1] = tmp_buf1[1];
buf[0] = tmp_buf1[0];
}
else
{
buf[0] = tmp_buf1[0];
}
}
else
{
return 0;
}
return 1;
}
static int ds3231_i2c_readbyte(struct i2c_client *client, unsigned char reg_addr)
{
int ret = 0;
unsigned char buf[2];
buf[0] = reg_addr;
ret = i2cdev_read(buf, 1, 1, 1);
if (ret < 0)
{
dev_err(&client->dev, "ds3231_i2c_readbyte fail...\n");
return ret;
}
return buf[0];
}
static int ds3231_i2c_writebyte(struct i2c_client *client,unsigned char reg_addr,
unsigned char value)
{
int ret = 0;
unsigned char buf[2];
buf[0] = reg_addr;
buf[1] = value;
ret = i2c_master_send(client, buf, 2);
return ret;
}
static int ds3231_i2c_dma_read(struct i2c_client *client, unsigned char reg_addr,
unsigned char len, unsigned char *buffer)
{
int ret;
dma_addr_t dma_handle;
unsigned char *p;
printk("enter dma_read...................\n");
p = dma_alloc_coherent(NULL, len, &dma_handle, GFP_KERNEL);
if(p == NULL)
{
printk("dma_alloc_coherent fail\n");
return -1;
}
ret = hi_i2c_dma_read(client, dma_handle, reg_addr, 1, len);
if(ret)
printk("dma_write fail:%d.\n", ret);
memcpy(buffer, p, len);
dma_free_coherent(NULL, len, p, dma_handle);
return 0;
}
static int ds3231_i2c_dma_write(struct i2c_client *client,unsigned char reg_addr,
unsigned char len,unsigned char *buffer)
{
int ret;
dma_addr_t dma_handle;
unsigned char *p;
p = dma_alloc_coherent(NULL, len, &dma_handle, GFP_KERNEL);
if(p == NULL)
{
printk("dma_alloc_coherent fail\n");
return -1;
}
memcpy(p, buffer, len);
ret = hi_i2c_dma_write(client, dma_handle, reg_addr, 1, len);
if(ret)
printk("dma_write fail:%d.\n", ret);
dma_free_coherent(NULL, len, p, dma_handle);
return 0;
}
static int ds3231_read_time(struct device *dev,struct rtc_time *time)
{
struct i2c_client *client = rtc_client;
int ret;
u8 buf[7];
unsigned int year, month, day, hour, minute, second;
unsigned int week, twelve_hr, am_pm;
unsigned int century, add_century = 0;
ret = ds3231_i2c_dma_read(client, DS3231_REG_SECONDS, 7, buf);
if (ret < 0) {
dev_warn(&client->dev, "ds3231_i2c_dma_read read time error!ret = %d\n", ret);
return ret;
}
second = buf[0];
minute = buf[1];
hour = buf[2];
week = buf[3];
day = buf[4];
month = buf[5];
year = buf[6];
/* Extract additional information for AM/PM and century */
twelve_hr = hour & 0x40;
am_pm = hour & 0x20;
century = month & 0x80;
#ifdef DS3231_DEBUG
{
int i;
printk("read from rtc-ds3231m: ");
for (i = 0; i < 7; i++) {
printk("0x%02x ", buf[i]);
}
printk("\n");
}
#endif
/* Write to rtc_time structure */
time->tm_sec = bcd2bin(second);
time->tm_min = bcd2bin(minute);
if (twelve_hr) {
/* Convert to 24 hr */
if (am_pm)
time->tm_hour = bcd2bin(hour & 0x1F) + 12;
else
time->tm_hour = bcd2bin(hour & 0x1F);
} else {
time->tm_hour = bcd2bin(hour);
}
/* Day of the week in linux range is 0~6 while 1~7 in RTC chip */
time->tm_wday = bcd2bin(week) - 1;
time->tm_mday = bcd2bin(day);
/* linux tm_mon range:0~11, while month range is 1~12 in RTC chip */
time->tm_mon = bcd2bin(month & 0x7F) - 1;
if (century)
add_century = 100;
time->tm_year = bcd2bin(year) + add_century;
ret = rtc_valid_tm(time);
if (ret < 0) {
dev_err(&client->dev, "rtc_valid_tm return ret: %d\n", ret);
}
timess.tm_sec=time->tm_sec;
timess.tm_hour=time->tm_hour;
timess.tm_min=time->tm_min;
timess.tm_mon=(time->tm_mon) +1;
timess.tm_mday=time->tm_mday;
timess.tm_wday=time->tm_wday;
timess.tm_year=(time->tm_year)+1900;
return ret;
}
static int ds3231_set_time(struct device *dev, struct rtc_time *time)
{
struct i2c_client *client = to_i2c_client(dev);
u8 buf[7];
int ret;
/* Extract time from rtc_time and load into ds3231*/
buf[0] = bin2bcd(time->tm_sec);
buf[1] = bin2bcd(time->tm_min);
buf[2] = bin2bcd(time->tm_hour);
/* Day of the week in linux range is 0~6 while 1~7 in RTC chip */
buf[3] = bin2bcd(time->tm_wday + 1);
buf[4] = bin2bcd(time->tm_mday); /* Date */
/* linux tm_mon range:0~11, while month range is 1~12 in RTC chip */
buf[5] = bin2bcd(time->tm_mon + 1);
if (time->tm_year >= 100) {
buf[5] |= 0x80;
buf[6] = bin2bcd(time->tm_year - 100);
}
else
{
buf[6] = bin2bcd(time->tm_year);
}
#ifdef DS3231_DEBUG
{
int i = 0;
display_rtc_time_in_bcd(time);
printk("write buffer: ");
for (i = 0; i < 7; i++) {
printk("0x%02x ", buf[i]);
}
printk("\n");
}
#endif
ret = ds3231_i2c_dma_write(client,
DS3231_REG_SECONDS, 7, buf);
if (ret < 0) {
dev_err(&client->dev, "ds3231_i2c_dma_write set time failed, ret: %d\n", ret);
} else {
/* take some sleep to fix bug read immendiately after set */
udelay(500);
}
return ret;
}
static int ds3231_check_rtc_status(struct i2c_client *client)
{
int ret = 0;
int control, stat;
stat = ds3231_i2c_readbyte(client, DS3231_REG_SR);
if (stat < 0) {
dev_err(&client->dev, "ds3231_i2c_readbyte failed!stat = 0x%08x\n", stat);
return stat;
}
if (stat & DS3231_REG_SR_OSF)
dev_warn(&client->dev,
"oscillator discontinuity flagged, "
"time unreliable\n");
stat &= ~(DS3231_REG_SR_OSF | DS3231_REG_SR_A1F | DS3231_REG_SR_A2F);
ret = ds3231_i2c_writebyte(client, DS3231_REG_SR, stat);
if (ret < 0) {
dev_warn(&client->dev, "ds3231_i2c_writebyte error!\n");
return ret;
}
/* If the alarm is pending, clear it before requesting
* the interrupt, so an interrupt event isn't reported
* before everything is initialized.
*/
control = ds3231_i2c_readbyte(client, DS3231_REG_CR);
if (control < 0) {
dev_warn(&client->dev, "ds3231_i2c_readbyte read control error!control = 0x%08x\n", control);
return control;
}
control &= ~(DS3231_REG_CR_A1IE | DS3231_REG_CR_A2IE);
control |= DS3231_REG_CR_INTCN;
ret = ds3231_i2c_writebyte(client, DS3231_REG_CR, control);
if (ret < 0) {
dev_warn(&client->dev, "ds3231_i2c_writebyte write control error!ret = 0x%08x\n", ret);
return control;
}
return ret;
}
void read_ds3231(void)
{
struct i2c_client *client = rtc_client;
int ret;
u8 buf[7];
struct rtc_time rtc_tm ;
unsigned int year, month, day, hour, minute, second;
unsigned int week, twelve_hr, am_pm;
unsigned int century, add_century = 0;
printk("enter ds3231_read\n");
ret = ds3231_i2c_dma_read(client, DS3231_REG_SECONDS, 7, buf);
second = buf[0];
minute = buf[1];
hour = buf[2];
week = buf[3];
day = buf[4];
month = buf[5];
year = buf[6];
/* Extract additional information for AM/PM and century */
twelve_hr = hour & 0x40;
am_pm = hour & 0x20;
century = month & 0x80;
printk("asdasdasadasdasd\n");
/* Write to rtc_time structure */
rtc_tm.tm_sec = bcd2bin(second);
rtc_tm.tm_min = bcd2bin(minute);
if (twelve_hr) {
/* Convert to 24 hr */
if (am_pm)
rtc_tm.tm_hour = bcd2bin(hour & 0x1F) + 12;
else
rtc_tm.tm_hour = bcd2bin(hour & 0x1F);
} else {
rtc_tm.tm_hour = bcd2bin(hour);
}
/* Day of the week in linux range is 0~6 while 1~7 in RTC chip */
rtc_tm.tm_wday = bcd2bin(week) - 1;
rtc_tm.tm_mday = bcd2bin(day);
/* linux tm_mon range:0~11, while month range is 1~12 in RTC chip */
rtc_tm.tm_mon = bcd2bin(month & 0x7F);
if (century)
add_century = 2000;
rtc_tm.tm_year = bcd2bin(year) + add_century;
ret = rtc_valid_tm(&rtc_tm);
if (ret < 0) {
dev_err(&client->dev, "rtc_valid_tm return ret: %d\n", ret);
}
display_rtc_time_in_bcd(&rtc_tm);
}
static const struct rtc_class_ops ds3231_rtc_ops = {
.read_time = ds3231_read_time,
.set_time = ds3231_set_time,
// .read_alarm = ds3231_read_alarm,
// .set_alarm = ds3231_set_alarm,
// .alarm_irq_enable = ds3231_alarm_irq_enable,
};
int ds3231rtc_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
int ret;
printk("enter ds3231_probe\n");
ret = ds3231_check_rtc_status(client);
if (ret < 0) {
dev_err(&client->dev, "ds3231_check_rtc_status failed! ret = %d\n", ret);
return ret;
}
rtc = devm_rtc_device_register(&client->dev, client->name,
&ds3231_rtc_ops, THIS_MODULE);
read_ds3231();
return 0;
}
int ds3231rtc_remove(struct i2c_client *client)
{
return 0;
}
struct i2c_driver ds3231_driver=
{
.driver =
{
.name="ds3231rtc",
.owner=THIS_MODULE,
},
.probe =ds3231rtc_probe,
.remove=ds3231rtc_remove,
/*i2c match 会使用到*/
.id_table=ds3231_id,
};
irqreturn_t ds3231_isr(int irq,void *dev_id)
{
int ret;
int times=0;
printk("occur up key press!\n");
GPIO_READ:
ret=GPIO_READ_REG(GPIO9_REG6);
if(ret==0)
{
times++;
mdelay(100);
goto GPIO_READ;
}
printk("times-> %d ms\n",(times));
display_rtc_time_in_bcd(×s);
return IRQ_HANDLED;
}
int __init ds3231rtc_init(void)
{
int ret;
struct i2c_adapter* i2c_adap;
reg_gpio_base_va = ioremap(GPIO_ADRESS_BASE,0x100);
// GPIO_WRITE_REG(I2C1_CTRL_REG6, 1);//设置GPIO1_6复用
// GPIO_WRITE_REG(I2C1_CTRL_REG7, 1);//设置GPIO1_7复用
GPIO_WRITE_REG(GPIO9_CTRL_REG6, 0);//设置GPIO1_7复用
GPIO_RST(GPIO9_DIR6, 6);//按键为输出
/*配置中断*/
GPIO_RST(GPIO9_IS6, 6);
GPIO_RST(GPIO9_IEV6,6);
GPIO_RST(GPIO9_IBE6,6);
GPIO_SET(GPIO9_IC6, 6);
GPIO_SET(GPIO9_IE6, 6);
/*注册中断*/
ret=request_irq(76,ds3231_isr,IRQF_SHARED,"interrupt_demo",(void*)0x01);
if(ret==0)
{
printk("success\n");
}
else
{
printk("%d",ret);
}
i2c_adap = i2c_get_adapter(2);//I2C2
rtc_client = i2c_new_device(i2c_adap, &i2c_ds3231rtc);
i2c_put_adapter(i2c_adap);
i2c_add_driver(&ds3231_driver);
return 0;
}
void __exit ds3231rtc_exit(void)
{
iounmap(reg_gpio_base_va);
free_irq(76,(void *)0x01);
i2c_unregister_device(rtc_client);
i2c_del_driver(&ds3231_driver);
printk("ds3231 driver unregistered\n");
}
module_init(ds3231rtc_init);
module_exit(ds3231rtc_exit);
MODULE_LICENSE("GPL");