/* Currently, the vRTC doesn't support UIE ON/OFF */
static int
mrst_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
	struct mrst_rtc	*mrst = dev_get_drvdata(dev);
	unsigned long	flags;

	switch (cmd) {
	case RTC_AIE_OFF:
	case RTC_AIE_ON:
		if (!is_valid_irq(mrst->irq))
			return -EINVAL;
		break;
	default:
		/* PIE ON/OFF is handled by mrst_irq_set_state() */
		return -ENOIOCTLCMD;
	}

	spin_lock_irqsave(&rtc_lock, flags);
	switch (cmd) {
	case RTC_AIE_OFF:	/* alarm off */
		mrst_irq_disable(mrst, RTC_AIE);
		break;
	case RTC_AIE_ON:	/* alarm on */
		mrst_irq_enable(mrst, RTC_AIE);
		break;
	}
	spin_unlock_irqrestore(&rtc_lock, flags);
	return 0;
}
static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
	struct mrst_rtc	*mrst = dev_get_drvdata(dev);
	unsigned char hrs, min, sec;
	unsigned char wday, mday, mon, year;
	int ret = 0;

	if (!is_valid_irq(mrst->irq))
		return -EIO;

	hrs = t->time.tm_hour;
	min = t->time.tm_min;
	sec = t->time.tm_sec;

	wday = t->time.tm_wday;
	mday = t->time.tm_mday;
	mon = t->time.tm_mon;
	year = t->time.tm_year;

	spin_lock_irq(&rtc_lock);
	/* Next rtc irq must not be from previous alarm setting */
	mrst_irq_disable(mrst, RTC_AIE);

	/* Update alarm */
	vrtc_cmos_write(hrs, RTC_HOURS_ALARM);
	vrtc_cmos_write(min, RTC_MINUTES_ALARM);
	vrtc_cmos_write(sec, RTC_SECONDS_ALARM);

	if ((__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_PENWELL) ||
	    (__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_CLOVERVIEW)) {
		/* Support for date-field in Alarm using OSHOB
		 * Since, vRTC doesn't have Alarm-registers for date-fields,
		 * write date-fields into OSHOB for SCU to sync to MSIC-RTC */
		writeb(wday, oshob_addr+OSHOB_DAYW_OFFSET);
		writeb(mday, oshob_addr+OSHOB_DAYM_OFFSET);
		writeb(mon+1, oshob_addr+OSHOB_MON_OFFSET);
		/* Adjust for the 1972/1900 */
		writeb(year-72, oshob_addr+OSHOB_YEAR_OFFSET);
	}
	spin_unlock_irq(&rtc_lock);

	/* In moorestown vrtc used to be powered off & was not a wake source
	 * in Standby. In penwell vRTC is kept on even during standby.
	 * hence this ipc message need not be sent
	 */
	if (__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_LINCROFT) {
		ret = rpmsg_send_simple_command(vrtc_mrst_instance,
					IPCMSG_VRTC, IPC_CMD_VRTC_SETALARM);
		if (ret)
			return ret;
	}

	spin_lock_irq(&rtc_lock);
	if (t->enabled)
		mrst_irq_enable(mrst, RTC_AIE);

	spin_unlock_irq(&rtc_lock);

	return 0;
}
static int mrst_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
	struct mrst_rtc *mrst = dev_get_drvdata(dev);

	if (enabled)
		mrst_irq_enable(mrst, RTC_AIE);
	else
		mrst_irq_disable(mrst, RTC_AIE);

	return 0;
}
Beispiel #4
0
/* Currently, the vRTC doesn't support UIE ON/OFF */
static int mrst_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
	struct mrst_rtc	*mrst = dev_get_drvdata(dev);
	unsigned long	flags;

	spin_lock_irqsave(&rtc_lock, flags);
	if (enabled)
		mrst_irq_enable(mrst, RTC_AIE);
	else
		mrst_irq_disable(mrst, RTC_AIE);
	spin_unlock_irqrestore(&rtc_lock, flags);
	return 0;
}
static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
	struct mrst_rtc	*mrst = dev_get_drvdata(dev);
	unsigned char hrs, min, sec;
	unsigned char wday, mday, mon, year;
	int ret = 0;

	if (!is_valid_irq(mrst->irq))
		return -EIO;

	hrs = t->time.tm_hour;
	min = t->time.tm_min;
	sec = t->time.tm_sec;

	wday = t->time.tm_wday;
	mday = t->time.tm_mday;
	mon = t->time.tm_mon;
	year = t->time.tm_year;

	spin_lock_irq(&rtc_lock);
	/* Next rtc irq must not be from previous alarm setting */
	mrst_irq_disable(mrst, RTC_AIE);

	/* Update alarm */
	vrtc_cmos_write(hrs, RTC_HOURS_ALARM);
	vrtc_cmos_write(min, RTC_MINUTES_ALARM);
	vrtc_cmos_write(sec, RTC_SECONDS_ALARM);

	if ((__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_PENWELL) ||
	    (__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_CLOVERVIEW)) {
		/* Support for date-field in Alarm using OSHOB
		 * Since, vRTC doesn't have Alarm-registers for date-fields,
		 * write date-fields into OSHOB for SCU to sync to MSIC-RTC */
		writeb(wday, oshob_addr+OSHOB_DAYW_OFFSET);
		writeb(mday, oshob_addr+OSHOB_DAYM_OFFSET);
		writeb(mon+1, oshob_addr+OSHOB_MON_OFFSET);
		/* Adjust for the 1972/1900 */
		writeb(year-72, oshob_addr+OSHOB_YEAR_OFFSET);
	}

	if (t->enabled)
		mrst_irq_enable(mrst, RTC_AIE);

	spin_unlock_irq(&rtc_lock);

	return 0;
}
Beispiel #6
0
static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
	struct mrst_rtc	*mrst = dev_get_drvdata(dev);
	unsigned char hrs, min, sec;
	int ret = 0;

	if (!mrst->irq)
		return -EIO;

	hrs = t->time.tm_hour;
	min = t->time.tm_min;
	sec = t->time.tm_sec;

	spin_lock_irq(&rtc_lock);
	/* Next rtc irq must not be from previous alarm setting */
	mrst_irq_disable(mrst, RTC_AIE);

	/* Update alarm */
	vrtc_cmos_write(hrs, RTC_HOURS_ALARM);
	vrtc_cmos_write(min, RTC_MINUTES_ALARM);
	vrtc_cmos_write(sec, RTC_SECONDS_ALARM);

	spin_unlock_irq(&rtc_lock);

	ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETALARM);
	if (ret)
		return ret;

	spin_lock_irq(&rtc_lock);
	if (t->enabled)
		mrst_irq_enable(mrst, RTC_AIE);

	spin_unlock_irq(&rtc_lock);

	return 0;
}
static int
vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq)
{
	int retval = 0;
	unsigned char rtc_control;
	unsigned char enable_bit_save = 0;

	/* There can be only one ... */
	if (mrst_rtc.dev)
		return -EBUSY;

	if (!iomem)
		return -ENODEV;

	iomem = request_mem_region(iomem->start,
			iomem->end + 1 - iomem->start,
			driver_name);
	if (!iomem) {
		dev_dbg(dev, "i/o mem already in use.\n");
		return -EBUSY;
	}

	mrst_rtc.irq = rtc_irq;
	mrst_rtc.iomem = iomem;
	mrst_rtc.dev = dev;
	dev_set_drvdata(dev, &mrst_rtc);

	mrst_rtc.rtc = rtc_device_register(driver_name, dev,
				&mrst_rtc_ops, THIS_MODULE);
	if (IS_ERR(mrst_rtc.rtc)) {
		retval = PTR_ERR(mrst_rtc.rtc);
		goto cleanup0;
	}

	rename_region(iomem, dev_name(&mrst_rtc.rtc->dev));

	printk(KERN_ALERT"(%s) +------------rtc info-----------+\n",__func__);
	spin_lock_irq(&rtc_lock);
	enable_bit_save = vrtc_cmos_read(RTC_CONTROL);
	enable_bit_save &= (RTC_PIE | RTC_AIE);
	mrst_irq_disable(&mrst_rtc, RTC_PIE | RTC_AIE);
	rtc_control = vrtc_cmos_read(RTC_CONTROL);
	spin_unlock_irq(&rtc_lock);
	printk(KERN_ALERT"read PIE_AIE_save = 0x%02x, then clear. rtc_control = 0x%02x\n",enable_bit_save,rtc_control);

	if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY)))
		dev_dbg(dev, "TODO: support more than 24-hr BCD mode\n");

	if (is_valid_irq(rtc_irq)) {
		retval = request_irq(rtc_irq, mrst_rtc_irq,
				IRQF_NO_SUSPEND, dev_name(&mrst_rtc.rtc->dev),
				mrst_rtc.rtc);
		if (retval < 0) {
			dev_dbg(dev, "IRQ %d is already in use, err %d\n",
				rtc_irq, retval);
			goto cleanup1;
		}
	}

	/* make RTC device wake capable from sleep */
	device_init_wakeup(dev, true);

	if ((__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_PENWELL) ||
	    (__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_CLOVERVIEW)) {
		retval = rpmsg_send_command(vrtc_mrst_instance,
				IPCMSG_GET_HOBADDR, 0, NULL, &oshob_base, 0, 1);
		if (retval < 0) {
			dev_dbg(dev,
				"Unable to get OSHOB base address, err %d\n",
				retval);
			goto cleanup1;
		}

		oshob_addr = ioremap_nocache(oshob_base+OSHOB_ALARM_OFFSET, 4);
		if (!oshob_addr) {
			dev_dbg(dev, "Unable to do ioremap for OSHOB\n");
			retval = -ENOMEM;
			goto cleanup1;
		}
	}

	spin_lock_irq(&rtc_lock);
	if(enable_bit_save)
		mrst_irq_enable(&mrst_rtc, enable_bit_save);//add for power off rtc issue
	spin_unlock_irq(&rtc_lock);
	rtc_control = vrtc_cmos_read(RTC_CONTROL);
	printk(KERN_ALERT"read resume rtc_control = 0x%02x.\n",rtc_control);
	printk(KERN_ALERT"(%s) +-------------------------------+\n",__func__);
	dev_dbg(dev, "vRTC driver initialised\n");
	return 0;

cleanup1:
	rtc_device_unregister(mrst_rtc.rtc);
cleanup0:
	dev_set_drvdata(dev, NULL);
	mrst_rtc.dev = NULL;
	release_mem_region(iomem->start, resource_size(iomem));
	dev_err(dev, "rtc-mrst: unable to initialise\n");
	return retval;
}