コード例 #1
0
/* 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;
}
コード例 #2
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;
    }
}
コード例 #3
0
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;
}
コード例 #4
0
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;
}
コード例 #5
0
ファイル: scpi_protocol.c プロジェクト: uDude/linux-1
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);
}
コード例 #6
0
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;
}