/*the init of the hym8563 at first time */ static int hym8563_init_device(struct i2c_client *client) { struct hym8563 *hym8563 = i2c_get_clientdata(client); u8 regs[2]; int sr; mutex_lock(&hym8563->mutex); regs[0]=0; hym8563_i2c_set_regs(client, RTC_CTL1, regs, 1); //disable clkout regs[0] = 0x80; hym8563_i2c_set_regs(client, RTC_CLKOUT, regs, 1); /*enable alarm interrupt*/ hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1); regs[0] = 0x0; regs[0] |= AIE; hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1); hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1); sr = hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1); if (sr < 0) { pr_err("read CTL2 err\n"); } if(regs[0] & (AF|TF)) { regs[0] &= ~(AF|TF); hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1); } mutex_unlock(&hym8563->mutex); return 0; }
int hym8563_enable_count(struct i2c_client *client, int en) { struct hym8563 *hym8563 = i2c_get_clientdata(client); u8 regs[2]; if (!hym8563) return -1; if (en) { hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1); regs[0] |= TIE; hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1); regs[0] = 0; regs[0] |= (TE | TD1); hym8563_i2c_set_regs(client, RTC_T_CTL, regs, 1); } else { hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1); regs[0] &= ~TIE; hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1); regs[0] = 0; regs[0] |= (TD0 | TD1); hym8563_i2c_set_regs(client, RTC_T_CTL, regs, 1); } return 0; }
static void hym8563_work_func(struct work_struct *work) { struct hym8563 *hym8563 = container_of(work, struct hym8563, work); struct i2c_client *client = hym8563->client; struct rtc_time now; u8 data; pr_debug("enter\n"); mutex_lock(&hym8563->mutex); hym8563_i2c_read_regs(client, RTC_CTL2, &data, 1); data &= ~AF; hym8563_i2c_set_regs(client, RTC_CTL2, &data, 1); mutex_unlock(&hym8563->mutex); hym8563_read_datetime(client, &now); mutex_lock(&hym8563->mutex); if (hym8563->alarm.enabled && hym8563->alarm.time.tm_sec > now.tm_sec) { long timeout = hym8563->alarm.time.tm_sec - now.tm_sec + 1; pr_info("stay awake %lds\n", timeout); wake_lock_timeout(&hym8563->wake_lock, timeout * HZ); } if (!hym8563->exiting) enable_irq(hym8563->irq); mutex_unlock(&hym8563->mutex); }
static int hym8563_i2c_close_alarm(struct i2c_client *client) { u8 data; hym8563_i2c_read_regs(client, RTC_CTL2, &data, 1); data &= ~AIE; hym8563_i2c_set_regs(client, RTC_CTL2, &data, 1); return 0; }
static int hym8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) { struct i2c_client *client = to_i2c_client(dev); struct hym8563 *hym8563 = i2c_get_clientdata(client); u8 regs[4] = { 0, }; pr_debug("enter\n"); mutex_lock(&hym8563->mutex); hym8563_i2c_read_regs(client, RTC_A_MIN, regs, 4); regs[0] = 0x0; hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1); mutex_unlock(&hym8563->mutex); return 0; }
int hdmi_get_data(void) { u8 regs=0; if(gClient) hym8563_i2c_read_regs(gClient, RTC_T_COUNT, ®s, 1); else { printk("%s rtc has no init\n",__func__); return -1; } if(regs==0 || regs==0xff){ printk("%s rtc has no hdmi data\n",__func__); return -1; } return (regs-1); }
static irqreturn_t hym8563_wakeup_irq(int irq, void *data) { struct hym8563 *hym8563 = data; struct i2c_client *client = hym8563->client; u8 value; mutex_lock(&hym8563->mutex); hym8563_i2c_read_regs(client, RTC_CTL2, &value, 1); value &= ~(AF|TF); hym8563_i2c_set_regs(client, RTC_CTL2, &value, 1); mutex_unlock(&hym8563->mutex); rtc_update_irq(hym8563->rtc, 1, RTC_IRQF | RTC_AF | RTC_UF); //printk("%s:irq=%d\n",__func__,irq); return IRQ_HANDLED; }
static int hym8563_read_datetime(struct i2c_client *client, struct rtc_time *tm) { struct hym8563 *hym8563 = i2c_get_clientdata(client); u8 regs[HYM8563_RTC_SECTION_LEN] = { 0, }; // u8 i; mutex_lock(&hym8563->mutex); // for (i = 0; i < HYM8563_RTC_SECTION_LEN; i++) { // hym8563_i2c_read_regs(client, RTC_SEC+i, ®s[i], 1); // } hym8563_i2c_read_regs(client, RTC_SEC, regs, HYM8563_RTC_SECTION_LEN); mutex_unlock(&hym8563->mutex); tm->tm_sec = bcd2bin(regs[0x00] & 0x7F); tm->tm_min = bcd2bin(regs[0x01] & 0x7F); tm->tm_hour = bcd2bin(regs[0x02] & 0x3F); tm->tm_mday = bcd2bin(regs[0x03] & 0x3F); tm->tm_wday = bcd2bin(regs[0x04] & 0x07); tm->tm_mon = bcd2bin(regs[0x05] & 0x1F) ; tm->tm_mon -= 1; //inorder to cooperate the systerm time tm->tm_year = bcd2bin(regs[0x06] & 0xFF); if(regs[5] & 0x80) tm->tm_year += 1900; else tm->tm_year += 2000; tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); tm->tm_year -= 1900; //inorder to cooperate the systerm time if(tm->tm_year < 0) tm->tm_year = 0; tm->tm_isdst = 0; pr_debug("%4d-%02d-%02d(%d) %02d:%02d:%02d\n", 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); return 0; }
static int __devinit hym8563_probe(struct i2c_client *client, const struct i2c_device_id *id) { int rc = 0; u8 reg = 0; struct hym8563 *hym8563; struct rtc_device *rtc = NULL; struct rtc_time tm_read, tm = { .tm_wday = 6, .tm_year = 111, .tm_mon = 0, .tm_mday = 1, .tm_hour = 12, .tm_min = 0, .tm_sec = 0, }; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; hym8563 = kzalloc(sizeof(struct hym8563), GFP_KERNEL); if (!hym8563) { return -ENOMEM; } gClient = client; hym8563->client = client; hym8563->alarm.enabled = 0; mutex_init(&hym8563->mutex); wake_lock_init(&hym8563->wake_lock, WAKE_LOCK_SUSPEND, "rtc_hym8563"); i2c_set_clientdata(client, hym8563); hym8563_init_device(client); hym8563_enable_count(client, 0); // check power down hym8563_i2c_read_regs(client,RTC_SEC,®,1); if (reg&0x80) { dev_info(&client->dev, "clock/calendar information is no longer guaranteed\n"); hym8563_set_time(client, &tm); } hym8563_read_datetime(client, &tm_read); //read time from hym8563 if(((tm_read.tm_year < 70) | (tm_read.tm_year > 137 )) | (tm_read.tm_mon == -1) | (rtc_valid_tm(&tm_read) != 0)) //if the hym8563 haven't initialized { hym8563_set_time(client, &tm); //initialize the hym8563 } if(gpio_request(client->irq, "rtc gpio")) { dev_err(&client->dev, "gpio request fail\n"); gpio_free(client->irq); goto exit; } hym8563->irq = gpio_to_irq(client->irq); gpio_pull_updown(client->irq,GPIOPullUp); if (request_threaded_irq(hym8563->irq, NULL, hym8563_wakeup_irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->dev.driver->name, hym8563) < 0) { printk("unable to request rtc irq\n"); goto exit; } enable_irq_wake(hym8563->irq); rtc = rtc_device_register(client->name, &client->dev, &hym8563_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { rc = PTR_ERR(rtc); rtc = NULL; goto exit; } hym8563->rtc = rtc; return 0; exit: if (rtc) rtc_device_unregister(rtc); if (hym8563) { wake_lock_destroy(&hym8563->wake_lock); kfree(hym8563); } return rc; } static int __devexit hym8563_remove(struct i2c_client *client) { struct hym8563 *hym8563 = i2c_get_clientdata(client); if (hym8563->irq > 0) { mutex_lock(&hym8563->mutex); hym8563->exiting = 1; mutex_unlock(&hym8563->mutex); free_irq(hym8563->irq, hym8563); cancel_work_sync(&hym8563->work); } rtc_device_unregister(hym8563->rtc); wake_lock_destroy(&hym8563->wake_lock); kfree(hym8563); hym8563 = NULL; return 0; } void hym8563_shutdown(struct i2c_client * client) { u8 regs[2]; int ret; //disable clkout regs[0] = 0x00; ret=hym8563_i2c_set_regs(client, RTC_CLKOUT, regs, 1); if(ret<0) printk("rtc shutdown is error\n"); }
static int hym8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct i2c_client *client = to_i2c_client(dev); struct hym8563 *hym8563 = i2c_get_clientdata(client); struct rtc_time now, *tm = &alarm->time; u8 regs[4] = { 0, }; u8 mon_day; unsigned long alarm_sec, now_sec; int diff_sec = 0; pr_debug("%4d-%02d-%02d(%d) %02d:%02d:%02d enabled %d\n", 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec, alarm->enabled); hym8563_read_datetime(client, &now); mutex_lock(&hym8563->mutex); rtc_tm_to_time(tm, &alarm_sec); rtc_tm_to_time(&now, &now_sec); diff_sec = alarm_sec - now_sec; if((diff_sec > 0) && (diff_sec < 256)) { printk("%s:diff_sec= %ds , use time\n",__func__, diff_sec); if (alarm->enabled == 1) { hym8563_set_count(client, diff_sec); hym8563_enable_count(client, 1); } else { hym8563_enable_count(client, 0); } } else { printk("%s:diff_sec= %ds , use alarm\n",__func__, diff_sec); hym8563_enable_count(client, 0); if(tm->tm_sec > 0) { rtc_tm_to_time(tm, &alarm_sec); rtc_time_to_tm(alarm_sec, tm); } hym8563->alarm = *alarm; regs[0] = 0x0; hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1); mon_day = rtc_month_days(tm->tm_mon, tm->tm_year + 1900); hym8563_i2c_read_regs(client, RTC_A_MIN, regs, 4); if (tm->tm_min >= 60 || tm->tm_min < 0) //set min regs[0x00] = bin2bcd(0x00) & 0x7f; else regs[0x00] = bin2bcd(tm->tm_min) & 0x7f; if (tm->tm_hour >= 24 || tm->tm_hour < 0) //set hour regs[0x01] = bin2bcd(0x00) & 0x7f; else regs[0x01] = bin2bcd(tm->tm_hour) & 0x7f; regs[0x03] = bin2bcd (tm->tm_wday) & 0x7f; /* if the input month day is bigger than the biggest day of this month, set the biggest day */ if (tm->tm_mday > mon_day) regs[0x02] = bin2bcd(mon_day) & 0x7f; else if (tm->tm_mday > 0) regs[0x02] = bin2bcd(tm->tm_mday) & 0x7f; else if (tm->tm_mday <= 0) regs[0x02] = bin2bcd(0x01) & 0x7f; hym8563_i2c_set_regs(client, RTC_A_MIN, regs, 4); hym8563_i2c_read_regs(client, RTC_A_MIN, regs, 4); hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1); if (alarm->enabled == 1) regs[0] |= AIE; else regs[0] &= 0x0; hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1); hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1); if(diff_sec <= 0) { pr_info("alarm sec <= now sec\n"); } } mutex_unlock(&hym8563->mutex); return 0; }
static int hym8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct i2c_client *client = to_i2c_client(dev); struct hym8563 *hym8563 = i2c_get_clientdata(client); struct rtc_time now, *tm = &alarm->time; u8 regs[4] = { 0, }; u8 mon_day; pr_debug("%4d-%02d-%02d(%d) %02d:%02d:%02d enabled %d\n", 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec, alarm->enabled); hym8563_read_datetime(client, &now); if (alarm->enabled && now.tm_year == tm->tm_year && now.tm_mon == tm->tm_mon && now.tm_mday == tm->tm_mday && now.tm_hour == tm->tm_hour && now.tm_min == tm->tm_min && tm->tm_sec > now.tm_sec) { long timeout = tm->tm_sec - now.tm_sec + 1; pr_info("stay awake %lds\n", timeout); wake_lock_timeout(&hym8563->wake_lock, timeout * HZ); } mutex_lock(&hym8563->mutex); hym8563->alarm = *alarm; regs[0] = 0x0; hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1); mon_day = rtc_month_days(tm->tm_mon, tm->tm_year + 1900); hym8563_i2c_read_regs(client, RTC_A_MIN, regs, 4); if (tm->tm_min >= 60 || tm->tm_min < 0) //set min regs[0x00] = bin2bcd(0x00) & 0x7f; else regs[0x00] = bin2bcd(tm->tm_min) & 0x7f; if (tm->tm_hour >= 24 || tm->tm_hour < 0) //set hour regs[0x01] = bin2bcd(0x00) & 0x7f; else regs[0x01] = bin2bcd(tm->tm_hour) & 0x7f; regs[0x03] = bin2bcd (tm->tm_wday) & 0x7f; /* if the input month day is bigger than the biggest day of this month, set the biggest day */ if (tm->tm_mday > mon_day) regs[0x02] = bin2bcd(mon_day) & 0x7f; else if (tm->tm_mday > 0) regs[0x02] = bin2bcd(tm->tm_mday) & 0x7f; else if (tm->tm_mday <= 0) regs[0x02] = bin2bcd(0x01) & 0x7f; hym8563_i2c_set_regs(client, RTC_A_MIN, regs, 4); hym8563_i2c_read_regs(client, RTC_A_MIN, regs, 4); hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1); if (alarm->enabled == 1) regs[0] |= AIE; else regs[0] &= 0x0; hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1); hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1); mutex_unlock(&hym8563->mutex); return 0; }