/* Time read/write */ static int sunxi_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) { unsigned int have_retried = 0; void __iomem *base = sunxi_rtc_base; unsigned int date_tmp = 0; unsigned int time_tmp = 0; /*only for alarm losc err occur.*/ if(losc_err_flag) { rtc_tm->tm_sec = 0; rtc_tm->tm_min = 0; rtc_tm->tm_hour = 0; rtc_tm->tm_mday = 0; rtc_tm->tm_mon = 0; rtc_tm->tm_year = 0; return -1; } retry_get_time: _dev_info(dev,"sunxi_rtc_gettime\n"); /*first to get the date, then time, because the sec turn to 0 will effect the date;*/ date_tmp = readl(base + SUNXI_RTC_DATE_REG); time_tmp = readl(base + SUNXI_RTC_TIME_REG); rtc_tm->tm_sec = TIME_GET_SEC_VALUE(time_tmp); rtc_tm->tm_min = TIME_GET_MIN_VALUE(time_tmp); rtc_tm->tm_hour = TIME_GET_HOUR_VALUE(time_tmp); rtc_tm->tm_mday = DATE_GET_DAY_VALUE(date_tmp); rtc_tm->tm_mon = DATE_GET_MON_VALUE(date_tmp); rtc_tm->tm_year = DATE_GET_YEAR_VALUE(date_tmp); /* the only way to work out wether the system was mid-update * when we read it is to check the second counter, and if it * is zero, then we re-try the entire read */ if (rtc_tm->tm_sec == 0 && !have_retried) { have_retried = 1; goto retry_get_time; } rtc_tm->tm_year += 110; rtc_tm->tm_mon -= 1; _dev_info(dev,"read time %d-%d-%d %d:%d:%d\n", rtc_tm->tm_year + 1900, rtc_tm->tm_mon + 1, rtc_tm->tm_mday, rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); return 0; }
/* IRQ Handlers, irq no. is shared with timer2 */ static irqreturn_t sunxi_rtc_alarmirq(int irq, void *id) { struct rtc_device *rdev = id; u32 val; #ifdef RTC_ALARM_DEBUG _dev_info(&(rdev->dev), "sunxi_rtc_alarmirq\n"); #endif /*judge the int is whether ours*/ val = readl(sunxi_rtc_base + SUNXI_ALARM_INT_STATUS_REG)&(RTC_ENABLE_WK_IRQ | RTC_ENABLE_CNT_IRQ); if (val) { /*Clear pending count alarm*/ val = readl(sunxi_rtc_base + SUNXI_ALARM_INT_STATUS_REG);//0x11c val |= (RTC_ENABLE_CNT_IRQ); //0x00000001 writel(val, sunxi_rtc_base + SUNXI_ALARM_INT_STATUS_REG); rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF); return IRQ_HANDLED; } else { return IRQ_NONE; } }
static int __devinit sunxi_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; int ret; unsigned int tmp_data; #ifdef BACKUP_PWM unsigned int pwm_ctrl_reg_backup = 0; unsigned int pwm_ch0_period_backup = 0; #endif sunxi_rtc_base = (void __iomem *)(SW_VA_TIMERC_IO_BASE); sunxi_rtc_alarmno = SW_INT_IRQNO_ALARM; /* select RTC clock source * on fpga board, internal 32k clk src is the default, and can not be changed * * RTC CLOCK SOURCE internal 32K HZ */ #ifdef BACKUP_PWM pwm_ctrl_reg_backup = readl(PWM_CTRL_REG_BASE + 0); pwm_ch0_period_backup = readl(PWM_CTRL_REG_BASE + 4); printk("[rtc-pwm] 1 pwm_ctrl_reg_backup = %x pwm_ch0_period_backup = %x", pwm_ctrl_reg_backup, pwm_ch0_period_backup); #endif /* upate by kevin, 2011-9-7 18:23 * step1: set keyfiled,选择外部晶振 */ tmp_data = readl(sunxi_rtc_base + SUNXI_LOSC_CTRL_REG); tmp_data &= (~REG_CLK32K_AUTO_SWT_EN); //disable auto switch,bit-14 tmp_data |= (RTC_SOURCE_EXTERNAL | REG_LOSCCTRL_MAGIC); //external 32768hz osc tmp_data |= (EXT_LOSC_GSM); //external 32768hz osc gsm writel(tmp_data, sunxi_rtc_base + SUNXI_LOSC_CTRL_REG); __udelay(100); _dev_info(&(pdev->dev),"sunxi_rtc_probe tmp_data = %d\n", tmp_data); /*step2: check set result,查询是否设置成功*/ tmp_data = readl(sunxi_rtc_base + SUNXI_LOSC_CTRL_REG); if(!(tmp_data & RTC_SOURCE_EXTERNAL)){ printk("[RTC] ERR: Set LOSC to external failed!!!\n"); printk("[RTC] WARNING: Rtc time will be wrong!!\n"); losc_err_flag = 1; } #ifdef BACKUP_PWM writel(pwm_ctrl_reg_backup, PWM_CTRL_REG_BASE + 0); writel(pwm_ch0_period_backup, PWM_CTRL_REG_BASE + 4); pwm_ctrl_reg_backup = readl(PWM_CTRL_REG_BASE + 0); pwm_ch0_period_backup = readl(PWM_CTRL_REG_BASE + 4); printk("[rtc-pwm] 2 pwm_ctrl_reg_backup = %x pwm_ch0_period_backup = %x", pwm_ctrl_reg_backup, pwm_ch0_period_backup); #endif device_init_wakeup(&pdev->dev, 1); /* register RTC and exit */ rtc = rtc_device_register("rtc", &pdev->dev, &sunxi_rtcops, THIS_MODULE); if (IS_ERR(rtc)) { dev_err(&pdev->dev, "cannot attach rtc\n"); ret = PTR_ERR(rtc); goto err_out; } ret = request_irq(sunxi_rtc_alarmno, sunxi_rtc_alarmirq, IRQF_DISABLED, "sunxi-rtc alarm", rtc); if (ret) { dev_err(&pdev->dev, "IRQ%d error %d\n", sunxi_rtc_alarmno, ret); rtc_device_unregister(rtc); return ret; } sw_rtc_dev = rtc; platform_set_drvdata(pdev, rtc);//设置rtc结构数据为pdev的私有数据 return 0; err_out: return ret; }
static int sunxi_rtc_settime(struct device *dev, struct rtc_time *tm) { void __iomem *base = sunxi_rtc_base; unsigned int date_tmp = 0; unsigned int time_tmp = 0; unsigned int crystal_data = 0; unsigned int timeout = 0; int leap_year = 0; #ifdef BACKUP_PWM unsigned int pwm_ctrl_reg_backup = 0; unsigned int pwm_ch0_period_backup = 0; #endif /*int tm_year; years from 1900 *int tm_mon; months since january 0-11 *the input para tm->tm_year is the offset related 1900; */ leap_year = tm->tm_year + 1900; if(leap_year > 2073 || leap_year < 2010) { dev_err(dev, "rtc only supports 63(2010~2073) years\n"); return -EINVAL; } crystal_data = readl(base + SUNXI_LOSC_CTRL_REG); /*Any bit of [9:7] is set, The time and date * register can`t be written, we re-try the entried read */ { /*check at most 3 times.*/ int times = 3; while((crystal_data & 0x380) && (times--)){ printk(KERN_INFO"[RTC]canot change rtc now!\n"); msleep(500); crystal_data = readl(base + SUNXI_LOSC_CTRL_REG); } } /*sunxi ONLY SYPPORTS 63 YEARS,hardware base time:1900*/ tm->tm_year -= 110; tm->tm_mon += 1; /*prevent the application seting the error time*/ if(tm->tm_mon > 12){ _dev_info(dev, "set time month error:line:%d,%d-%d-%d %d:%d:%d\n",__LINE__, tm->tm_year + 2010, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); switch(tm->tm_mon){ case 1: case 3: case 5: case 7: case 8: case 10: case 12: if(tm->tm_mday > 31){ _dev_info(dev, "set time day error:line:%d,%d-%d-%d %d:%d:%d\n",__LINE__, tm->tm_year + 2010, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); } if((tm->tm_hour > 24)||(tm->tm_min > 59)||(tm->tm_sec > 59)){ _dev_info(dev, "set time error:line:%d,%d-%d-%d %d:%d:%d\n",__LINE__, tm->tm_year + 2010, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); } break; case 4: case 6: case 9: case 11: if(tm->tm_mday > 30){ _dev_info(dev, "set time day error:line:%d,%d-%d-%d %d:%d:%d\n",__LINE__, tm->tm_year + 2010, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); } if((tm->tm_hour > 24)||(tm->tm_min > 59)||(tm->tm_sec > 59)){ _dev_info(dev, "set time error:line:%d,%d-%d-%d %d:%d:%d\n",__LINE__, tm->tm_year + 2010, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); } break; case 2: if((leap_year%400==0) || ((leap_year%100!=0) && (leap_year%4==0))) { if(tm->tm_mday > 28){ _dev_info(dev, "set time day error:line:%d,%d-%d-%d %d:%d:%d\n",__LINE__, tm->tm_year + 2010, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); } if((tm->tm_hour > 24)||(tm->tm_min > 59)||(tm->tm_sec > 59)){ _dev_info(dev, "set time error:line:%d,%d-%d-%d %d:%d:%d\n",__LINE__, tm->tm_year + 2010, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); } }else{ if(tm->tm_mday > 29){ _dev_info(dev, "set time day error:line:%d,%d-%d-%d %d:%d:%d\n",__LINE__, tm->tm_year + 2010, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); } if((tm->tm_hour > 24)||(tm->tm_min > 59)||(tm->tm_sec > 59)){ _dev_info(dev, "set time error:line:%d,%d-%d-%d %d:%d:%d\n",__LINE__, tm->tm_year + 2010, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); } } break; default: break; } tm->tm_sec = 0; tm->tm_min = 0; tm->tm_hour = 0; tm->tm_mday = 0; tm->tm_mon = 0; tm->tm_year = 0; } _dev_info(dev, "set time %d-%d-%d %d:%d:%d\n", tm->tm_year + 2010, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); date_tmp = (DATE_SET_DAY_VALUE(tm->tm_mday)|DATE_SET_MON_VALUE(tm->tm_mon) |DATE_SET_YEAR_VALUE(tm->tm_year)); time_tmp = (TIME_SET_SEC_VALUE(tm->tm_sec)|TIME_SET_MIN_VALUE(tm->tm_min) |TIME_SET_HOUR_VALUE(tm->tm_hour)); #ifdef BACKUP_PWM pwm_ctrl_reg_backup = readl(PWM_CTRL_REG_BASE + 0); pwm_ch0_period_backup = readl(PWM_CTRL_REG_BASE + 4); printk("[rtc-pwm] 1 pwm_ctrl_reg_backup = %x pwm_ch0_period_backup = %x", pwm_ctrl_reg_backup, pwm_ch0_period_backup); #endif writel(time_tmp, base + SUNXI_RTC_TIME_REG); timeout = 0xffff; while((readl(base + SUNXI_LOSC_CTRL_REG)&(RTC_HHMMSS_ACCESS))&&(--timeout)) if (timeout == 0) { dev_err(dev, "fail to set rtc time.\n"); #ifdef BACKUP_PWM writel(pwm_ctrl_reg_backup, PWM_CTRL_REG_BASE + 0); writel(pwm_ch0_period_backup, PWM_CTRL_REG_BASE + 4); pwm_ctrl_reg_backup = readl(PWM_CTRL_REG_BASE + 0); pwm_ch0_period_backup = readl(PWM_CTRL_REG_BASE + 4); printk("[rtc-pwm] 2 pwm_ctrl_reg_backup = %x pwm_ch0_period_backup = %x", pwm_ctrl_reg_backup, pwm_ch0_period_backup); #endif return -1; } if((leap_year%400==0) || ((leap_year%100!=0) && (leap_year%4==0))) { /*Set Leap Year bit*/ date_tmp |= LEAP_SET_VALUE(1); } writel(date_tmp, base + SUNXI_RTC_DATE_REG); timeout = 0xffff; while((readl(base + SUNXI_LOSC_CTRL_REG)&(RTC_YYMMDD_ACCESS))&&(--timeout)) if (timeout == 0) { dev_err(dev, "fail to set rtc date.\n"); #ifdef BACKUP_PWM writel(pwm_ctrl_reg_backup, PWM_CTRL_REG_BASE + 0); writel(pwm_ch0_period_backup, PWM_CTRL_REG_BASE + 4); pwm_ctrl_reg_backup = readl(PWM_CTRL_REG_BASE + 0); pwm_ch0_period_backup = readl(PWM_CTRL_REG_BASE + 4); printk("[rtc-pwm] 5 pwm_ctrl_reg_backup = %x pwm_ch0_period_backup = %x", pwm_ctrl_reg_backup, pwm_ch0_period_backup); #endif return -1; } #ifdef BACKUP_PWM writel(pwm_ctrl_reg_backup, PWM_CTRL_REG_BASE + 0); writel(pwm_ch0_period_backup, PWM_CTRL_REG_BASE + 4); pwm_ctrl_reg_backup = readl(PWM_CTRL_REG_BASE + 0); pwm_ch0_period_backup = readl(PWM_CTRL_REG_BASE + 4); printk("[rtc-pwm] 6 pwm_ctrl_reg_backup = %x pwm_ch0_period_backup = %x", pwm_ctrl_reg_backup, pwm_ch0_period_backup); #endif /*wait about 70us to make sure the the time is really written into target.*/ udelay(70); return 0; }
static int scpi_probe(struct platform_device *pdev) { int count, idx, ret; struct resource res; struct scpi_chan *scpi_chan; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; scpi_info = devm_kzalloc(dev, sizeof(*scpi_info), GFP_KERNEL); if (!scpi_info) { dev_err(dev, "failed to allocate memory for scpi drvinfo\n"); return -ENOMEM; } count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells"); if (count < 0) { dev_err(dev, "no mboxes property in '%s'\n", np->full_name); return -ENODEV; } scpi_chan = devm_kcalloc(dev, count, sizeof(*scpi_chan), GFP_KERNEL); if (!scpi_chan) { dev_err(dev, "failed to allocate memory scpi chaninfo\n"); return -ENOMEM; } for (idx = 0; idx < count; idx++) { resource_size_t size; struct scpi_chan *pchan = scpi_chan + idx; struct mbox_client *cl = &pchan->cl; struct device_node *shmem = of_parse_phandle(np, "shmem", idx); if (of_address_to_resource(shmem, 0, &res)) { dev_err(dev, "failed to get SCPI payload mem resource\n"); ret = -EINVAL; goto err; } size = resource_size(&res); pchan->rx_payload = devm_ioremap(dev, res.start, size); if (!pchan->rx_payload) { dev_err(dev, "failed to ioremap SCPI payload\n"); ret = -EADDRNOTAVAIL; goto err; } pchan->tx_payload = pchan->rx_payload + (size >> 1); cl->dev = dev; cl->rx_callback = scpi_handle_remote_msg; cl->tx_prepare = scpi_tx_prepare; cl->tx_block = true; cl->tx_tout = 50; cl->knows_txdone = false; /* controller can ack */ INIT_LIST_HEAD(&pchan->rx_pending); INIT_LIST_HEAD(&pchan->xfers_list); spin_lock_init(&pchan->rx_lock); mutex_init(&pchan->xfers_lock); ret = scpi_alloc_xfer_list(dev, pchan); if (!ret) { pchan->chan = mbox_request_channel(cl, idx); if (!IS_ERR(pchan->chan)) continue; ret = -EPROBE_DEFER; dev_err(dev, "failed to acquire channel#%d\n", idx); } err: scpi_free_channels(dev, scpi_chan, idx); scpi_info = NULL; return ret; } scpi_info->channels = scpi_chan; scpi_info->num_chans = count; platform_set_drvdata(pdev, scpi_info); ret = scpi_init_versions(scpi_info); if (ret) { dev_err(dev, "incorrect or no SCP firmware found\n"); scpi_remove(pdev); return ret; } _dev_info(dev, "SCP Protocol %d.%d Firmware %d.%d.%d version\n", PROTOCOL_REV_MAJOR(scpi_info->protocol_version), PROTOCOL_REV_MINOR(scpi_info->protocol_version), FW_REV_MAJOR(scpi_info->firmware_version), FW_REV_MINOR(scpi_info->firmware_version), FW_REV_PATCH(scpi_info->firmware_version)); scpi_info->scpi_ops = &scpi_ops; ret = sysfs_create_groups(&dev->kobj, versions_groups); if (ret) dev_err(dev, "unable to create sysfs version group\n"); return of_platform_populate(dev->of_node, NULL, NULL, dev); }
static int __init sunxi_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; int ret; unsigned int tmp_data; sunxi_rtc_base = (void __iomem *)(SUNXI_VA_TIMERC_IO_BASE); sunxi_rtc_alarmno = SUNXI_IRQ_RALARM0; /* * step1: select RTC clock source */ tmp_data = readl(sunxi_rtc_base + SUNXI_LOSC_CTRL_REG); tmp_data &= (~REG_CLK32K_AUTO_SWT_EN); //disable auto switch,bit-14 tmp_data |= (RTC_SOURCE_EXTERNAL | REG_LOSCCTRL_MAGIC); //external 32768hz osc tmp_data |= (EXT_LOSC_GSM); //external 32768hz osc gsm writel(tmp_data, sunxi_rtc_base + SUNXI_LOSC_CTRL_REG); _dev_info(&(pdev->dev),"sunxi_rtc_probe tmp_data = %d\n", tmp_data); /*step2: check set result,��ѯ�Ƿ����óɹ�*/ tmp_data = readl(sunxi_rtc_base + SUNXI_LOSC_CTRL_REG); if(!(tmp_data & RTC_SOURCE_EXTERNAL)){ RTC_ERR("[RTC] WARNING: Rtc time will be wrong!!\n"); losc_err_flag = 1; } device_init_wakeup(&pdev->dev, 1); /* register RTC and exit */ rtc = rtc_device_register("rtc", &pdev->dev, &sunxi_rtcops, THIS_MODULE); if (IS_ERR(rtc)) { dev_err(&pdev->dev, "cannot attach rtc\n"); ret = PTR_ERR(rtc); goto err_out; } #ifdef SUNXI_ALARM ret = request_irq(sunxi_rtc_alarmno, sunxi_rtc_alarmirq, IRQF_DISABLED, "sunxi-rtc alarm", rtc); if (ret) { dev_err(&pdev->dev, "IRQ%d error %d\n", sunxi_rtc_alarmno, ret); rtc_device_unregister(rtc); return ret; } #endif platform_set_drvdata(pdev, rtc); /*clean the alarm count value*/ writel(0x00000000, sunxi_rtc_base + SUNXI_RTC_ALARM_COUNTER_REG);//0x0020 /*clean the alarm current value*/ writel(0x00000000, sunxi_rtc_base + SUNXI_RTC_ALARM_CURRENT_REG);//0x0024 /*disable the alarm0 when init*/ writel(0x00000000, sunxi_rtc_base + SUNXI_ALARM_EN_REG);//0x0028 /*disable the alarm0 irq*/ writel(0x00000000, sunxi_rtc_base + SUNXI_ALARM_INT_CTRL_REG);//0x002c /*Clear pending count alarm*/ writel(0x00000001, sunxi_rtc_base + SUNXI_ALARM_INT_STATUS_REG);//0x0030 writel(0x00000000, sunxi_rtc_base + SUNXI_ALARM_CONFIG); return 0; err_out: return ret; }