diff options
Diffstat (limited to 'drivers/rtc')
| -rw-r--r-- | drivers/rtc/Kconfig | 46 | ||||
| -rw-r--r-- | drivers/rtc/Makefile | 4 | ||||
| -rw-r--r-- | drivers/rtc/interface.c | 14 | ||||
| -rw-r--r-- | drivers/rtc/rtc-88pm860x.c | 3 | ||||
| -rw-r--r-- | drivers/rtc/rtc-at91rm9200.c | 16 | ||||
| -rw-r--r-- | drivers/rtc/rtc-bfin.c | 16 | ||||
| -rw-r--r-- | drivers/rtc/rtc-cmos.c | 85 | ||||
| -rw-r--r-- | drivers/rtc/rtc-da9052.c | 122 | ||||
| -rw-r--r-- | drivers/rtc/rtc-da9063.c | 333 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ds1343.c | 689 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ds1742.c | 2 | ||||
| -rw-r--r-- | drivers/rtc/rtc-efi.c | 2 | ||||
| -rw-r--r-- | drivers/rtc/rtc-hym8563.c | 8 | ||||
| -rw-r--r-- | drivers/rtc/rtc-isl12057.c | 2 | ||||
| -rw-r--r-- | drivers/rtc/rtc-m41t80.c | 104 | ||||
| -rw-r--r-- | drivers/rtc/rtc-mcp795.c | 199 | ||||
| -rw-r--r-- | drivers/rtc/rtc-mv.c | 2 | ||||
| -rw-r--r-- | drivers/rtc/rtc-omap.c | 138 | ||||
| -rw-r--r-- | drivers/rtc/rtc-palmas.c | 2 | ||||
| -rw-r--r-- | drivers/rtc/rtc-pcf8523.c | 4 | ||||
| -rw-r--r-- | drivers/rtc/rtc-pxa.c | 2 | ||||
| -rw-r--r-- | drivers/rtc/rtc-s5m.c | 381 | ||||
| -rw-r--r-- | drivers/rtc/rtc-sa1100.c | 2 | ||||
| -rw-r--r-- | drivers/rtc/rtc-xgene.c | 278 | 
24 files changed, 2115 insertions, 339 deletions
| diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2e565f8e5165..0754f5c7cb3b 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -386,12 +386,12 @@ config RTC_DRV_PCF8583  	  will be called rtc-pcf8583.  config RTC_DRV_M41T80 -	tristate "ST M41T62/65/M41T80/81/82/83/84/85/87" +	tristate "ST M41T62/65/M41T80/81/82/83/84/85/87 and compatible"  	help  	  If you say Y here you will get support for the ST M41T60  	  and M41T80 RTC chips series. Currently, the following chips are  	  supported: M41T62, M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84, -	  M41ST85, and M41ST87. +	  M41ST85, M41ST87, and MicroCrystal RV4162.  	  This driver can also be built as a module. If so, the module  	  will be called rtc-m41t80. @@ -530,11 +530,11 @@ config RTC_DRV_RV3029C2  	  will be called rtc-rv3029c2.  config RTC_DRV_S5M -	tristate "Samsung S5M series" +	tristate "Samsung S2M/S5M series"  	depends on MFD_SEC_CORE  	help  	  If you say yes here you will get support for the -	  RTC of Samsung S5M PMIC series. +	  RTC of Samsung S2MPS14 and S5M PMIC series.  	  This driver can also be built as a module. If so, the module  	  will be called rtc-s5m. @@ -573,6 +573,17 @@ config RTC_DRV_DS1305  	  This driver can also be built as a module. If so, the module  	  will be called rtc-ds1305. +config RTC_DRV_DS1343 +	select REGMAP_SPI +	tristate "Dallas/Maxim DS1343/DS1344" +	help +	  If you say yes here you get support for the +	  Dallas/Maxim DS1343 and DS1344 real time clock chips. +	  Support for trickle charger, alarm is provided. + +	  This driver can also be built as a module. If so, the module +	  will be called rtc-ds1343. +  config RTC_DRV_DS1347  	tristate "Dallas/Maxim DS1347"  	help @@ -650,6 +661,14 @@ config RTC_DRV_RX4581  	  This driver can also be built as a module. If so the module  	  will be called rtc-rx4581. +config RTC_DRV_MCP795 +	tristate "Microchip MCP795" +	help +	  If you say yes here you will get support for the Microchip MCP795. + +	  This driver can also be built as a module. If so the module +	  will be called rtc-mcp795. +  endif # SPI_MASTER  comment "Platform RTC drivers" @@ -758,6 +777,16 @@ config RTC_DRV_DA9055  	  This driver can also be built as a module. If so, the module  	  will be called rtc-da9055 +config RTC_DRV_DA9063 +	tristate "Dialog Semiconductor DA9063 RTC" +	depends on MFD_DA9063 +	help +	  If you say yes here you will get support for the RTC subsystem +	  of the Dialog Semiconductor DA9063. + +	  This driver can also be built as a module. If so, the module +	  will be called "rtc-da9063". +  config RTC_DRV_EFI  	tristate "EFI RTC"  	depends on IA64 @@ -1327,6 +1356,15 @@ config RTC_DRV_MOXART  	   This driver can also be built as a module. If so, the module  	   will be called rtc-moxart +config RTC_DRV_XGENE +	tristate "APM X-Gene RTC" +	help +	  If you say yes here you get support for the APM X-Gene SoC real time +	  clock. + +	  This driver can also be built as a module, if so, the module +	  will be called "rtc-xgene". +  comment "HID Sensor RTC drivers"  config RTC_DRV_HID_SENSOR_TIME diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 40a09915c8f6..70347d041d10 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_RTC_DRV_CMOS)	+= rtc-cmos.o  obj-$(CONFIG_RTC_DRV_COH901331)	+= rtc-coh901331.o  obj-$(CONFIG_RTC_DRV_DA9052)	+= rtc-da9052.o  obj-$(CONFIG_RTC_DRV_DA9055)	+= rtc-da9055.o +obj-$(CONFIG_RTC_DRV_DA9063)	+= rtc-da9063.o  obj-$(CONFIG_RTC_DRV_DAVINCI)	+= rtc-davinci.o  obj-$(CONFIG_RTC_DRV_DM355EVM)	+= rtc-dm355evm.o  obj-$(CONFIG_RTC_DRV_VRTC)	+= rtc-mrst.o @@ -40,6 +41,7 @@ obj-$(CONFIG_RTC_DRV_DS1286)	+= rtc-ds1286.o  obj-$(CONFIG_RTC_DRV_DS1302)	+= rtc-ds1302.o  obj-$(CONFIG_RTC_DRV_DS1305)	+= rtc-ds1305.o  obj-$(CONFIG_RTC_DRV_DS1307)	+= rtc-ds1307.o +obj-$(CONFIG_RTC_DRV_DS1343)	+= rtc-ds1343.o  obj-$(CONFIG_RTC_DRV_DS1347)	+= rtc-ds1347.o  obj-$(CONFIG_RTC_DRV_DS1374)	+= rtc-ds1374.o  obj-$(CONFIG_RTC_DRV_DS1390)	+= rtc-ds1390.o @@ -80,6 +82,7 @@ obj-$(CONFIG_RTC_DRV_MAX8997)	+= rtc-max8997.o  obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o  obj-$(CONFIG_RTC_DRV_MAX77686)	+= rtc-max77686.o  obj-$(CONFIG_RTC_DRV_MC13XXX)	+= rtc-mc13xxx.o +obj-$(CONFIG_RTC_DRV_MCP795)	+= rtc-mcp795.o  obj-$(CONFIG_RTC_DRV_MSM6242)	+= rtc-msm6242.o  obj-$(CONFIG_RTC_DRV_MPC5121)	+= rtc-mpc5121.o  obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o @@ -135,5 +138,6 @@ obj-$(CONFIG_RTC_DRV_VT8500)	+= rtc-vt8500.o  obj-$(CONFIG_RTC_DRV_WM831X)	+= rtc-wm831x.o  obj-$(CONFIG_RTC_DRV_WM8350)	+= rtc-wm8350.o  obj-$(CONFIG_RTC_DRV_X1205)	+= rtc-x1205.o +obj-$(CONFIG_RTC_DRV_XGENE)	+= rtc-xgene.o  obj-$(CONFIG_RTC_DRV_SIRFSOC)	+= rtc-sirfsoc.o  obj-$(CONFIG_RTC_DRV_MOXART)	+= rtc-moxart.o diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index c2eff6082363..5813fa52c3d4 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -292,7 +292,8 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)  		dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year");  		do {  			alarm->time.tm_year++; -		} while (rtc_valid_tm(&alarm->time) != 0); +		} while (!is_leap_year(alarm->time.tm_year + 1900) +			&& rtc_valid_tm(&alarm->time) != 0);  		break;  	default: @@ -300,7 +301,16 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)  	}  done: -	return 0; +	err = rtc_valid_tm(&alarm->time); + +	if (err) { +		dev_warn(&rtc->dev, "invalid alarm value: %d-%d-%d %d:%d:%d\n", +			alarm->time.tm_year + 1900, alarm->time.tm_mon + 1, +			alarm->time.tm_mday, alarm->time.tm_hour, alarm->time.tm_min, +			alarm->time.tm_sec); +	} + +	return err;  }  int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index 816504846cdd..0c6add1a38dc 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -293,7 +293,7 @@ static int pm860x_rtc_dt_init(struct platform_device *pdev,  	int ret;  	if (!np)  		return -ENODEV; -	np = of_find_node_by_name(np, "rtc"); +	np = of_get_child_by_name(np, "rtc");  	if (!np) {  		dev_err(&pdev->dev, "failed to find rtc node\n");  		return -ENODEV; @@ -301,6 +301,7 @@ static int pm860x_rtc_dt_init(struct platform_device *pdev,  	ret = of_property_read_u32(np, "marvell,88pm860x-vrtc", &info->vrtc);  	if (ret)  		info->vrtc = 0; +	of_node_put(np);  	return 0;  }  #else diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 3281c90691c3..44fe83ee9bee 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -48,6 +48,7 @@ struct at91_rtc_config {  static const struct at91_rtc_config *at91_rtc_config;  static DECLARE_COMPLETION(at91_rtc_updated); +static DECLARE_COMPLETION(at91_rtc_upd_rdy);  static unsigned int at91_alarm_year = AT91_RTC_EPOCH;  static void __iomem *at91_rtc_regs;  static int irq; @@ -161,6 +162,8 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)  		1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,  		tm->tm_hour, tm->tm_min, tm->tm_sec); +	wait_for_completion(&at91_rtc_upd_rdy); +  	/* Stop Time/Calendar from counting */  	cr = at91_rtc_read(AT91_RTC_CR);  	at91_rtc_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM); @@ -183,7 +186,9 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)  	/* Restart Time/Calendar */  	cr = at91_rtc_read(AT91_RTC_CR); +	at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_SECEV);  	at91_rtc_write(AT91_RTC_CR, cr & ~(AT91_RTC_UPDCAL | AT91_RTC_UPDTIM)); +	at91_rtc_write_ier(AT91_RTC_SECEV);  	return 0;  } @@ -290,8 +295,10 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)  	if (rtsr) {		/* this interrupt is shared!  Is it ours? */  		if (rtsr & AT91_RTC_ALARM)  			events |= (RTC_AF | RTC_IRQF); -		if (rtsr & AT91_RTC_SECEV) -			events |= (RTC_UF | RTC_IRQF); +		if (rtsr & AT91_RTC_SECEV) { +			complete(&at91_rtc_upd_rdy); +			at91_rtc_write_idr(AT91_RTC_SECEV); +		}  		if (rtsr & AT91_RTC_ACKUPD)  			complete(&at91_rtc_updated); @@ -413,6 +420,11 @@ static int __init at91_rtc_probe(struct platform_device *pdev)  		return PTR_ERR(rtc);  	platform_set_drvdata(pdev, rtc); +	/* enable SECEV interrupt in order to initialize at91_rtc_upd_rdy +	 * completion. +	 */ +	at91_rtc_write_ier(AT91_RTC_SECEV); +  	dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n");  	return 0;  } diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 0c53f452849d..fe4bdb06a55a 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -346,7 +346,7 @@ static int bfin_rtc_probe(struct platform_device *pdev)  {  	struct bfin_rtc *rtc;  	struct device *dev = &pdev->dev; -	int ret = 0; +	int ret;  	unsigned long timeout = jiffies + HZ;  	dev_dbg_stamp(dev); @@ -361,16 +361,17 @@ static int bfin_rtc_probe(struct platform_device *pdev)  	/* Register our RTC with the RTC framework */  	rtc->rtc_dev = devm_rtc_device_register(dev, pdev->name, &bfin_rtc_ops,  						THIS_MODULE); -	if (unlikely(IS_ERR(rtc->rtc_dev))) { -		ret = PTR_ERR(rtc->rtc_dev); -		goto err; -	} +	if (unlikely(IS_ERR(rtc->rtc_dev))) +		return PTR_ERR(rtc->rtc_dev);  	/* Grab the IRQ and init the hardware */  	ret = devm_request_irq(dev, IRQ_RTC, bfin_rtc_interrupt, 0,  				pdev->name, dev);  	if (unlikely(ret)) -		goto err; +		dev_err(&pdev->dev, +			"unable to request IRQ; alarm won't work, " +			"and writes will be delayed\n"); +  	/* sometimes the bootloader touched things, but the write complete was not  	 * enabled, so let's just do a quick timeout here since the IRQ will not fire ...  	 */ @@ -381,9 +382,6 @@ static int bfin_rtc_probe(struct platform_device *pdev)  	bfin_write_RTC_SWCNT(0);  	return 0; - -err: -	return ret;  }  static int bfin_rtc_remove(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 0963c9309c74..b0e4a3eb33c7 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -647,6 +647,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)  	int				retval = 0;  	unsigned char			rtc_control;  	unsigned			address_space; +	u32				flags = 0;  	/* there can be only one ... */  	if (cmos_rtc.dev) @@ -660,9 +661,12 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)  	 * REVISIT non-x86 systems may instead use memory space resources  	 * (needing ioremap etc), not i/o space resources like this ...  	 */ -	ports = request_region(ports->start, -			resource_size(ports), -			driver_name); +	if (RTC_IOMAPPED) +		ports = request_region(ports->start, resource_size(ports), +				       driver_name); +	else +		ports = request_mem_region(ports->start, resource_size(ports), +					   driver_name);  	if (!ports) {  		dev_dbg(dev, "i/o registers already in use\n");  		return -EBUSY; @@ -699,6 +703,11 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)  	 * expect CMOS_READ and friends to handle.  	 */  	if (info) { +		if (info->flags) +			flags = info->flags; +		if (info->address_space) +			address_space = info->address_space; +  		if (info->rtc_day_alarm && info->rtc_day_alarm < 128)  			cmos_rtc.day_alrm = info->rtc_day_alarm;  		if (info->rtc_mon_alarm && info->rtc_mon_alarm < 128) @@ -726,18 +735,21 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)  	spin_lock_irq(&rtc_lock); -	/* force periodic irq to CMOS reset default of 1024Hz; -	 * -	 * REVISIT it's been reported that at least one x86_64 ALI mobo -	 * doesn't use 32KHz here ... for portability we might need to -	 * do something about other clock frequencies. -	 */ -	cmos_rtc.rtc->irq_freq = 1024; -	hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq); -	CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT); +	if (!(flags & CMOS_RTC_FLAGS_NOFREQ)) { +		/* force periodic irq to CMOS reset default of 1024Hz; +		 * +		 * REVISIT it's been reported that at least one x86_64 ALI +		 * mobo doesn't use 32KHz here ... for portability we might +		 * need to do something about other clock frequencies. +		 */ +		cmos_rtc.rtc->irq_freq = 1024; +		hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq); +		CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT); +	}  	/* disable irqs */ -	cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE); +	if (is_valid_irq(rtc_irq)) +		cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE);  	rtc_control = CMOS_READ(RTC_CONTROL); @@ -802,14 +814,18 @@ cleanup1:  	cmos_rtc.dev = NULL;  	rtc_device_unregister(cmos_rtc.rtc);  cleanup0: -	release_region(ports->start, resource_size(ports)); +	if (RTC_IOMAPPED) +		release_region(ports->start, resource_size(ports)); +	else +		release_mem_region(ports->start, resource_size(ports));  	return retval;  } -static void cmos_do_shutdown(void) +static void cmos_do_shutdown(int rtc_irq)  {  	spin_lock_irq(&rtc_lock); -	cmos_irq_disable(&cmos_rtc, RTC_IRQMASK); +	if (is_valid_irq(rtc_irq)) +		cmos_irq_disable(&cmos_rtc, RTC_IRQMASK);  	spin_unlock_irq(&rtc_lock);  } @@ -818,7 +834,7 @@ static void __exit cmos_do_remove(struct device *dev)  	struct cmos_rtc	*cmos = dev_get_drvdata(dev);  	struct resource *ports; -	cmos_do_shutdown(); +	cmos_do_shutdown(cmos->irq);  	sysfs_remove_bin_file(&dev->kobj, &nvram); @@ -831,7 +847,10 @@ static void __exit cmos_do_remove(struct device *dev)  	cmos->rtc = NULL;  	ports = cmos->iomem; -	release_region(ports->start, resource_size(ports)); +	if (RTC_IOMAPPED) +		release_region(ports->start, resource_size(ports)); +	else +		release_mem_region(ports->start, resource_size(ports));  	cmos->iomem = NULL;  	cmos->dev = NULL; @@ -1065,10 +1084,13 @@ static void __exit cmos_pnp_remove(struct pnp_dev *pnp)  static void cmos_pnp_shutdown(struct pnp_dev *pnp)  { -	if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pnp->dev)) +	struct device *dev = &pnp->dev; +	struct cmos_rtc	*cmos = dev_get_drvdata(dev); + +	if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev))  		return; -	cmos_do_shutdown(); +	cmos_do_shutdown(cmos->irq);  }  static const struct pnp_device_id rtc_ids[] = { @@ -1143,11 +1165,21 @@ static inline void cmos_of_init(struct platform_device *pdev) {}  static int __init cmos_platform_probe(struct platform_device *pdev)  { +	struct resource *resource; +	int irq; +  	cmos_of_init(pdev);  	cmos_wake_setup(&pdev->dev); -	return cmos_do_probe(&pdev->dev, -			platform_get_resource(pdev, IORESOURCE_IO, 0), -			platform_get_irq(pdev, 0)); + +	if (RTC_IOMAPPED) +		resource = platform_get_resource(pdev, IORESOURCE_IO, 0); +	else +		resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	irq = platform_get_irq(pdev, 0); +	if (irq < 0) +		irq = -1; + +	return cmos_do_probe(&pdev->dev, resource, irq);  }  static int __exit cmos_platform_remove(struct platform_device *pdev) @@ -1158,10 +1190,13 @@ static int __exit cmos_platform_remove(struct platform_device *pdev)  static void cmos_platform_shutdown(struct platform_device *pdev)  { -	if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pdev->dev)) +	struct device *dev = &pdev->dev; +	struct cmos_rtc	*cmos = dev_get_drvdata(dev); + +	if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev))  		return; -	cmos_do_shutdown(); +	cmos_do_shutdown(cmos->irq);  }  /* work with hotplug and coldplug */ diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c index a1cbf64242a5..e5c9486cf452 100644 --- a/drivers/rtc/rtc-da9052.c +++ b/drivers/rtc/rtc-da9052.c @@ -20,28 +20,28 @@  #include <linux/mfd/da9052/da9052.h>  #include <linux/mfd/da9052/reg.h> -#define rtc_err(da9052, fmt, ...) \ -		dev_err(da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__) +#define rtc_err(rtc, fmt, ...) \ +		dev_err(rtc->da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__)  struct da9052_rtc {  	struct rtc_device *rtc;  	struct da9052 *da9052;  }; -static int da9052_rtc_enable_alarm(struct da9052 *da9052, bool enable) +static int da9052_rtc_enable_alarm(struct da9052_rtc *rtc, bool enable)  {  	int ret;  	if (enable) { -		ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG, -					DA9052_ALARM_Y_ALARM_ON, -					DA9052_ALARM_Y_ALARM_ON); +		ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG, +				DA9052_ALARM_Y_ALARM_ON|DA9052_ALARM_Y_TICK_ON, +				DA9052_ALARM_Y_ALARM_ON);  		if (ret != 0) -			rtc_err(da9052, "Failed to enable ALM: %d\n", ret); +			rtc_err(rtc, "Failed to enable ALM: %d\n", ret);  	} else { -		ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG, -					DA9052_ALARM_Y_ALARM_ON, 0); +		ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG, +			DA9052_ALARM_Y_ALARM_ON|DA9052_ALARM_Y_TICK_ON, 0);  		if (ret != 0) -			rtc_err(da9052, "Write error: %d\n", ret); +			rtc_err(rtc, "Write error: %d\n", ret);  	}  	return ret;  } @@ -49,31 +49,20 @@ static int da9052_rtc_enable_alarm(struct da9052 *da9052, bool enable)  static irqreturn_t da9052_rtc_irq(int irq, void *data)  {  	struct da9052_rtc *rtc = data; -	int ret; -	ret = da9052_reg_read(rtc->da9052, DA9052_ALARM_MI_REG); -	if (ret < 0) { -		rtc_err(rtc->da9052, "Read error: %d\n", ret); -		return IRQ_NONE; -	} - -	if (ret & DA9052_ALARMMI_ALARMTYPE) { -		da9052_rtc_enable_alarm(rtc->da9052, 0); -		rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); -	} else -		rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_PF); +	rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);  	return IRQ_HANDLED;  } -static int da9052_read_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm) +static int da9052_read_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm)  {  	int ret;  	uint8_t v[5]; -	ret = da9052_group_read(da9052, DA9052_ALARM_MI_REG, 5, v); +	ret = da9052_group_read(rtc->da9052, DA9052_ALARM_MI_REG, 5, v);  	if (ret != 0) { -		rtc_err(da9052, "Failed to group read ALM: %d\n", ret); +		rtc_err(rtc, "Failed to group read ALM: %d\n", ret);  		return ret;  	} @@ -84,23 +73,33 @@ static int da9052_read_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm)  	rtc_tm->tm_min  = v[0] & DA9052_RTC_MIN;  	ret = rtc_valid_tm(rtc_tm); -	if (ret != 0) -		return ret;  	return ret;  } -static int da9052_set_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm) +static int da9052_set_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm)  { +	struct da9052 *da9052 = rtc->da9052; +	unsigned long alm_time;  	int ret;  	uint8_t v[3]; +	ret = rtc_tm_to_time(rtc_tm, &alm_time); +	if (ret != 0) +		return ret; + +	if (rtc_tm->tm_sec > 0) { +		alm_time += 60 - rtc_tm->tm_sec; +		rtc_time_to_tm(alm_time, rtc_tm); +	} +	BUG_ON(rtc_tm->tm_sec); /* it will cause repeated irqs if not zero */ +  	rtc_tm->tm_year -= 100;  	rtc_tm->tm_mon += 1;  	ret = da9052_reg_update(da9052, DA9052_ALARM_MI_REG,  				DA9052_RTC_MIN, rtc_tm->tm_min);  	if (ret != 0) { -		rtc_err(da9052, "Failed to write ALRM MIN: %d\n", ret); +		rtc_err(rtc, "Failed to write ALRM MIN: %d\n", ret);  		return ret;  	} @@ -115,22 +114,22 @@ static int da9052_set_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm)  	ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG,  				DA9052_RTC_YEAR, rtc_tm->tm_year);  	if (ret != 0) -		rtc_err(da9052, "Failed to write ALRM YEAR: %d\n", ret); +		rtc_err(rtc, "Failed to write ALRM YEAR: %d\n", ret);  	return ret;  } -static int da9052_rtc_get_alarm_status(struct da9052 *da9052) +static int da9052_rtc_get_alarm_status(struct da9052_rtc *rtc)  {  	int ret; -	ret = da9052_reg_read(da9052, DA9052_ALARM_Y_REG); +	ret = da9052_reg_read(rtc->da9052, DA9052_ALARM_Y_REG);  	if (ret < 0) { -		rtc_err(da9052, "Failed to read ALM: %d\n", ret); +		rtc_err(rtc, "Failed to read ALM: %d\n", ret);  		return ret;  	} -	ret &= DA9052_ALARM_Y_ALARM_ON; -	return (ret > 0) ? 1 : 0; + +	return !!(ret&DA9052_ALARM_Y_ALARM_ON);  }  static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) @@ -141,7 +140,7 @@ static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)  	ret = da9052_group_read(rtc->da9052, DA9052_COUNT_S_REG, 6, v);  	if (ret < 0) { -		rtc_err(rtc->da9052, "Failed to read RTC time : %d\n", ret); +		rtc_err(rtc, "Failed to read RTC time : %d\n", ret);  		return ret;  	} @@ -153,18 +152,14 @@ static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)  	rtc_tm->tm_sec  = v[0] & DA9052_RTC_SEC;  	ret = rtc_valid_tm(rtc_tm); -	if (ret != 0) { -		rtc_err(rtc->da9052, "rtc_valid_tm failed: %d\n", ret); -		return ret; -	} - -	return 0; +	return ret;  }  static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm)  {  	struct da9052_rtc *rtc;  	uint8_t v[6]; +	int ret;  	rtc = dev_get_drvdata(dev); @@ -175,7 +170,10 @@ static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm)  	v[4] = tm->tm_mon + 1;  	v[5] = tm->tm_year - 100; -	return da9052_group_write(rtc->da9052, DA9052_COUNT_S_REG, 6, v); +	ret = da9052_group_write(rtc->da9052, DA9052_COUNT_S_REG, 6, v); +	if (ret < 0) +		rtc_err(rtc, "failed to set RTC time: %d\n", ret); +	return ret;  }  static int da9052_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -184,13 +182,13 @@ static int da9052_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)  	struct rtc_time *tm = &alrm->time;  	struct da9052_rtc *rtc = dev_get_drvdata(dev); -	ret = da9052_read_alarm(rtc->da9052, tm); - -	if (ret) +	ret = da9052_read_alarm(rtc, tm); +	if (ret < 0) { +		rtc_err(rtc, "failed to read RTC alarm: %d\n", ret);  		return ret; +	} -	alrm->enabled = da9052_rtc_get_alarm_status(rtc->da9052); - +	alrm->enabled = da9052_rtc_get_alarm_status(rtc);  	return 0;  } @@ -200,16 +198,15 @@ static int da9052_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)  	struct rtc_time *tm = &alrm->time;  	struct da9052_rtc *rtc = dev_get_drvdata(dev); -	ret = da9052_rtc_enable_alarm(rtc->da9052, 0); +	ret = da9052_rtc_enable_alarm(rtc, 0);  	if (ret < 0)  		return ret; -	ret = da9052_set_alarm(rtc->da9052, tm); -	if (ret) +	ret = da9052_set_alarm(rtc, tm); +	if (ret < 0)  		return ret; -	ret = da9052_rtc_enable_alarm(rtc->da9052, 1); - +	ret = da9052_rtc_enable_alarm(rtc, 1);  	return ret;  } @@ -217,7 +214,7 @@ static int da9052_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)  {  	struct da9052_rtc *rtc = dev_get_drvdata(dev); -	return da9052_rtc_enable_alarm(rtc->da9052, enabled); +	return da9052_rtc_enable_alarm(rtc, enabled);  }  static const struct rtc_class_ops da9052_rtc_ops = { @@ -239,10 +236,23 @@ static int da9052_rtc_probe(struct platform_device *pdev)  	rtc->da9052 = dev_get_drvdata(pdev->dev.parent);  	platform_set_drvdata(pdev, rtc); + +	ret = da9052_reg_write(rtc->da9052, DA9052_BBAT_CONT_REG, 0xFE); +	if (ret < 0) { +		rtc_err(rtc, +			"Failed to setup RTC battery charging: %d\n", ret); +		return ret; +	} + +	ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG, +				DA9052_ALARM_Y_TICK_ON, 0); +	if (ret != 0) +		rtc_err(rtc, "Failed to disable TICKS: %d\n", ret); +  	ret = da9052_request_irq(rtc->da9052, DA9052_IRQ_ALARM, "ALM",  				da9052_rtc_irq, rtc);  	if (ret != 0) { -		rtc_err(rtc->da9052, "irq registration failed: %d\n", ret); +		rtc_err(rtc, "irq registration failed: %d\n", ret);  		return ret;  	} @@ -261,7 +271,7 @@ static struct platform_driver da9052_rtc_driver = {  module_platform_driver(da9052_rtc_driver); -MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); +MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>");  MODULE_DESCRIPTION("RTC driver for Dialog DA9052 PMIC");  MODULE_LICENSE("GPL");  MODULE_ALIAS("platform:da9052-rtc"); diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c new file mode 100644 index 000000000000..595393098b09 --- /dev/null +++ b/drivers/rtc/rtc-da9063.c @@ -0,0 +1,333 @@ +/* rtc-da9063.c - Real time clock device driver for DA9063 + * Copyright (C) 2013-14  Dialog Semiconductor Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Library General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/rtc.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/regmap.h> +#include <linux/mfd/da9063/registers.h> +#include <linux/mfd/da9063/core.h> + +#define YEARS_TO_DA9063(year)		((year) - 100) +#define MONTHS_TO_DA9063(month)		((month) + 1) +#define YEARS_FROM_DA9063(year)		((year) + 100) +#define MONTHS_FROM_DA9063(month)	((month) - 1) + +#define RTC_DATA_LEN	(DA9063_REG_COUNT_Y - DA9063_REG_COUNT_S + 1) +#define RTC_SEC		0 +#define RTC_MIN		1 +#define RTC_HOUR	2 +#define RTC_DAY		3 +#define RTC_MONTH	4 +#define RTC_YEAR	5 + +struct da9063_rtc { +	struct rtc_device	*rtc_dev; +	struct da9063		*hw; +	struct rtc_time		alarm_time; +	bool			rtc_sync; +}; + +static void da9063_data_to_tm(u8 *data, struct rtc_time *tm) +{ +	tm->tm_sec  = data[RTC_SEC]  & DA9063_COUNT_SEC_MASK; +	tm->tm_min  = data[RTC_MIN]  & DA9063_COUNT_MIN_MASK; +	tm->tm_hour = data[RTC_HOUR] & DA9063_COUNT_HOUR_MASK; +	tm->tm_mday = data[RTC_DAY]  & DA9063_COUNT_DAY_MASK; +	tm->tm_mon  = MONTHS_FROM_DA9063(data[RTC_MONTH] & +					 DA9063_COUNT_MONTH_MASK); +	tm->tm_year = YEARS_FROM_DA9063(data[RTC_YEAR] & +					DA9063_COUNT_YEAR_MASK); +} + +static void da9063_tm_to_data(struct rtc_time *tm, u8 *data) +{ +	data[RTC_SEC] &= ~DA9063_COUNT_SEC_MASK; +	data[RTC_SEC] |= tm->tm_sec & DA9063_COUNT_SEC_MASK; + +	data[RTC_MIN] &= ~DA9063_COUNT_MIN_MASK; +	data[RTC_MIN] |= tm->tm_min & DA9063_COUNT_MIN_MASK; + +	data[RTC_HOUR] &= ~DA9063_COUNT_HOUR_MASK; +	data[RTC_HOUR] |= tm->tm_hour & DA9063_COUNT_HOUR_MASK; + +	data[RTC_DAY] &= ~DA9063_COUNT_DAY_MASK; +	data[RTC_DAY] |= tm->tm_mday & DA9063_COUNT_DAY_MASK; + +	data[RTC_MONTH] &= ~DA9063_COUNT_MONTH_MASK; +	data[RTC_MONTH] |= MONTHS_TO_DA9063(tm->tm_mon) & +				DA9063_COUNT_MONTH_MASK; + +	data[RTC_YEAR] &= ~DA9063_COUNT_YEAR_MASK; +	data[RTC_YEAR] |= YEARS_TO_DA9063(tm->tm_year) & +				DA9063_COUNT_YEAR_MASK; +} + +static int da9063_rtc_stop_alarm(struct device *dev) +{ +	struct da9063_rtc *rtc = dev_get_drvdata(dev); + +	return regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y, +				  DA9063_ALARM_ON, 0); +} + +static int da9063_rtc_start_alarm(struct device *dev) +{ +	struct da9063_rtc *rtc = dev_get_drvdata(dev); + +	return regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y, +				  DA9063_ALARM_ON, DA9063_ALARM_ON); +} + +static int da9063_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ +	struct da9063_rtc *rtc = dev_get_drvdata(dev); +	unsigned long tm_secs; +	unsigned long al_secs; +	u8 data[RTC_DATA_LEN]; +	int ret; + +	ret = regmap_bulk_read(rtc->hw->regmap, DA9063_REG_COUNT_S, +			       data, RTC_DATA_LEN); +	if (ret < 0) { +		dev_err(dev, "Failed to read RTC time data: %d\n", ret); +		return ret; +	} + +	if (!(data[RTC_SEC] & DA9063_RTC_READ)) { +		dev_dbg(dev, "RTC not yet ready to be read by the host\n"); +		return -EINVAL; +	} + +	da9063_data_to_tm(data, tm); + +	rtc_tm_to_time(tm, &tm_secs); +	rtc_tm_to_time(&rtc->alarm_time, &al_secs); + +	/* handle the rtc synchronisation delay */ +	if (rtc->rtc_sync == true && al_secs - tm_secs == 1) +		memcpy(tm, &rtc->alarm_time, sizeof(struct rtc_time)); +	else +		rtc->rtc_sync = false; + +	return rtc_valid_tm(tm); +} + +static int da9063_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ +	struct da9063_rtc *rtc = dev_get_drvdata(dev); +	u8 data[RTC_DATA_LEN]; +	int ret; + +	da9063_tm_to_data(tm, data); +	ret = regmap_bulk_write(rtc->hw->regmap, DA9063_REG_COUNT_S, +				data, RTC_DATA_LEN); +	if (ret < 0) +		dev_err(dev, "Failed to set RTC time data: %d\n", ret); + +	return ret; +} + +static int da9063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	struct da9063_rtc *rtc = dev_get_drvdata(dev); +	u8 data[RTC_DATA_LEN]; +	int ret; +	unsigned int val; + +	ret = regmap_bulk_read(rtc->hw->regmap, DA9063_REG_ALARM_S, +			       &data[RTC_SEC], RTC_DATA_LEN); +	if (ret < 0) +		return ret; + +	da9063_data_to_tm(data, &alrm->time); + +	alrm->enabled = !!(data[RTC_YEAR] & DA9063_ALARM_ON); + +	ret = regmap_read(rtc->hw->regmap, DA9063_REG_EVENT_A, &val); +	if (ret < 0) +		return ret; + +	if (val & (DA9063_E_ALARM)) +		alrm->pending = 1; +	else +		alrm->pending = 0; + +	return 0; +} + +static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	struct da9063_rtc *rtc = dev_get_drvdata(dev); +	u8 data[RTC_DATA_LEN]; +	int ret; + +	da9063_tm_to_data(&alrm->time, data); + +	ret = da9063_rtc_stop_alarm(dev); +	if (ret < 0) { +		dev_err(dev, "Failed to stop alarm: %d\n", ret); +		return ret; +	} + +	ret = regmap_bulk_write(rtc->hw->regmap, DA9063_REG_ALARM_S, +				data, RTC_DATA_LEN); +	if (ret < 0) { +		dev_err(dev, "Failed to write alarm: %d\n", ret); +		return ret; +	} + +	rtc->alarm_time = alrm->time; + +	if (alrm->enabled) { +		ret = da9063_rtc_start_alarm(dev); +		if (ret < 0) { +			dev_err(dev, "Failed to start alarm: %d\n", ret); +			return ret; +		} +	} + +	return ret; +} + +static int da9063_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ +	if (enabled) +		return da9063_rtc_start_alarm(dev); +	else +		return da9063_rtc_stop_alarm(dev); +} + +static irqreturn_t da9063_alarm_event(int irq, void *data) +{ +	struct da9063_rtc *rtc = data; + +	regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y, +			   DA9063_ALARM_ON, 0); + +	rtc->rtc_sync = true; +	rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF); + +	return IRQ_HANDLED; +} + +static const struct rtc_class_ops da9063_rtc_ops = { +	.read_time = da9063_rtc_read_time, +	.set_time = da9063_rtc_set_time, +	.read_alarm = da9063_rtc_read_alarm, +	.set_alarm = da9063_rtc_set_alarm, +	.alarm_irq_enable = da9063_rtc_alarm_irq_enable, +}; + +static int da9063_rtc_probe(struct platform_device *pdev) +{ +	struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); +	struct da9063_rtc *rtc; +	int irq_alarm; +	u8 data[RTC_DATA_LEN]; +	int ret; + +	ret = regmap_update_bits(da9063->regmap, DA9063_REG_CONTROL_E, +				 DA9063_RTC_EN, DA9063_RTC_EN); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to enable RTC\n"); +		goto err; +	} + +	ret = regmap_update_bits(da9063->regmap, DA9063_REG_EN_32K, +				 DA9063_CRYSTAL, DA9063_CRYSTAL); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to run 32kHz oscillator\n"); +		goto err; +	} + +	ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_S, +			DA9063_ALARM_STATUS_TICK | DA9063_ALARM_STATUS_ALARM, +			0); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to access RTC alarm register\n"); +		goto err; +	} + +	ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_S, +				 DA9063_ALARM_STATUS_ALARM, +				 DA9063_ALARM_STATUS_ALARM); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to access RTC alarm register\n"); +		goto err; +	} + +	ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_Y, +				 DA9063_TICK_ON, 0); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to disable TICKs\n"); +		goto err; +	} + +	ret = regmap_bulk_read(da9063->regmap, DA9063_REG_ALARM_S, +			       data, RTC_DATA_LEN); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to read initial alarm data: %d\n", +			ret); +		goto err; +	} + +	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); +	if (!rtc) +		return -ENOMEM; + +	platform_set_drvdata(pdev, rtc); + +	irq_alarm = platform_get_irq_byname(pdev, "ALARM"); +	ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL, +					da9063_alarm_event, +					IRQF_TRIGGER_LOW | IRQF_ONESHOT, +					"ALARM", rtc); +	if (ret) { +		dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n", +			irq_alarm, ret); +		goto err; +	} + +	rtc->hw = da9063; +	rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC, +					   &da9063_rtc_ops, THIS_MODULE); +	if (IS_ERR(rtc->rtc_dev)) +		return PTR_ERR(rtc->rtc_dev); + +	da9063_data_to_tm(data, &rtc->alarm_time); +	rtc->rtc_sync = false; +err: +	return ret; +} + +static struct platform_driver da9063_rtc_driver = { +	.probe		= da9063_rtc_probe, +	.driver		= { +		.name	= DA9063_DRVNAME_RTC, +		.owner	= THIS_MODULE, +	}, +}; + +module_platform_driver(da9063_rtc_driver); + +MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>"); +MODULE_DESCRIPTION("Real time clock device driver for Dialog DA9063"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DA9063_DRVNAME_RTC); diff --git a/drivers/rtc/rtc-ds1343.c b/drivers/rtc/rtc-ds1343.c new file mode 100644 index 000000000000..c3719189dd96 --- /dev/null +++ b/drivers/rtc/rtc-ds1343.c @@ -0,0 +1,689 @@ +/* rtc-ds1343.c + * + * Driver for Dallas Semiconductor DS1343 Low Current, SPI Compatible + * Real Time Clock + * + * Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/spi/spi.h> +#include <linux/regmap.h> +#include <linux/rtc.h> +#include <linux/bcd.h> +#include <linux/pm.h> +#include <linux/slab.h> + +#define DS1343_DRV_VERSION	"01.00" +#define DALLAS_MAXIM_DS1343	0 +#define DALLAS_MAXIM_DS1344	1 + +/* RTC DS1343 Registers */ +#define DS1343_SECONDS_REG	0x00 +#define DS1343_MINUTES_REG	0x01 +#define DS1343_HOURS_REG	0x02 +#define DS1343_DAY_REG		0x03 +#define DS1343_DATE_REG		0x04 +#define DS1343_MONTH_REG	0x05 +#define DS1343_YEAR_REG		0x06 +#define DS1343_ALM0_SEC_REG	0x07 +#define DS1343_ALM0_MIN_REG	0x08 +#define DS1343_ALM0_HOUR_REG	0x09 +#define DS1343_ALM0_DAY_REG	0x0A +#define DS1343_ALM1_SEC_REG	0x0B +#define DS1343_ALM1_MIN_REG	0x0C +#define DS1343_ALM1_HOUR_REG	0x0D +#define DS1343_ALM1_DAY_REG	0x0E +#define DS1343_CONTROL_REG	0x0F +#define DS1343_STATUS_REG	0x10 +#define DS1343_TRICKLE_REG	0x11 + +/* DS1343 Control Registers bits */ +#define DS1343_EOSC		0x80 +#define DS1343_DOSF		0x20 +#define DS1343_EGFIL		0x10 +#define DS1343_SQW		0x08 +#define DS1343_INTCN		0x04 +#define DS1343_A1IE		0x02 +#define DS1343_A0IE		0x01 + +/* DS1343 Status Registers bits */ +#define DS1343_OSF		0x80 +#define DS1343_IRQF1		0x02 +#define DS1343_IRQF0		0x01 + +/* DS1343 Trickle Charger Registers bits */ +#define DS1343_TRICKLE_MAGIC	0xa0 +#define DS1343_TRICKLE_DS1	0x08 +#define DS1343_TRICKLE_1K	0x01 +#define DS1343_TRICKLE_2K	0x02 +#define DS1343_TRICKLE_4K	0x03 + +static const struct spi_device_id ds1343_id[] = { +	{ "ds1343", DALLAS_MAXIM_DS1343 }, +	{ "ds1344", DALLAS_MAXIM_DS1344 }, +	{ } +}; +MODULE_DEVICE_TABLE(spi, ds1343_id); + +struct ds1343_priv { +	struct spi_device *spi; +	struct rtc_device *rtc; +	struct regmap *map; +	struct mutex mutex; +	unsigned int irqen; +	int irq; +	int alarm_sec; +	int alarm_min; +	int alarm_hour; +	int alarm_mday; +}; + +static int ds1343_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ +	switch (cmd) { +#ifdef RTC_SET_CHARGE +	case RTC_SET_CHARGE: +	{ +		int val; + +		if (copy_from_user(&val, (int __user *)arg, sizeof(int))) +			return -EFAULT; + +		return regmap_write(priv->map, DS1343_TRICKLE_REG, val); +	} +	break; +#endif +	} + +	return -ENOIOCTLCMD; +} + +static ssize_t ds1343_show_glitchfilter(struct device *dev, +				struct device_attribute *attr, char *buf) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int glitch_filt_status, data; + +	regmap_read(priv->map, DS1343_CONTROL_REG, &data); + +	glitch_filt_status = !!(data & DS1343_EGFIL); + +	if (glitch_filt_status) +		return sprintf(buf, "enabled\n"); +	else +		return sprintf(buf, "disabled\n"); +} + +static ssize_t ds1343_store_glitchfilter(struct device *dev, +					struct device_attribute *attr, +					const char *buf, size_t count) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int data; + +	regmap_read(priv->map, DS1343_CONTROL_REG, &data); + +	if (strncmp(buf, "enabled", 7) == 0) +		data |= DS1343_EGFIL; + +	else if (strncmp(buf, "disabled", 8) == 0) +		data &= ~(DS1343_EGFIL); + +	else +		return -EINVAL; + +	regmap_write(priv->map, DS1343_CONTROL_REG, data); + +	return count; +} + +static DEVICE_ATTR(glitch_filter, S_IRUGO | S_IWUSR, ds1343_show_glitchfilter, +			ds1343_store_glitchfilter); + +static ssize_t ds1343_show_alarmstatus(struct device *dev, +				struct device_attribute *attr, char *buf) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int alarmstatus, data; + +	regmap_read(priv->map, DS1343_CONTROL_REG, &data); + +	alarmstatus = !!(data & DS1343_A0IE); + +	if (alarmstatus) +		return sprintf(buf, "enabled\n"); +	else +		return sprintf(buf, "disabled\n"); +} + +static DEVICE_ATTR(alarm_status, S_IRUGO, ds1343_show_alarmstatus, NULL); + +static ssize_t ds1343_show_alarmmode(struct device *dev, +				struct device_attribute *attr, char *buf) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int alarm_mode, data; +	char *alarm_str; + +	regmap_read(priv->map, DS1343_ALM0_SEC_REG, &data); +	alarm_mode = (data & 0x80) >> 4; + +	regmap_read(priv->map, DS1343_ALM0_MIN_REG, &data); +	alarm_mode |= (data & 0x80) >> 5; + +	regmap_read(priv->map, DS1343_ALM0_HOUR_REG, &data); +	alarm_mode |= (data & 0x80) >> 6; + +	regmap_read(priv->map, DS1343_ALM0_DAY_REG, &data); +	alarm_mode |= (data & 0x80) >> 7; + +	switch (alarm_mode) { +	case 15: +		alarm_str = "each second"; +		break; + +	case 7: +		alarm_str = "seconds match"; +		break; + +	case 3: +		alarm_str = "minutes and seconds match"; +		break; + +	case 1: +		alarm_str = "hours, minutes and seconds match"; +		break; + +	case 0: +		alarm_str = "day, hours, minutes and seconds match"; +		break; + +	default: +		alarm_str = "invalid"; +		break; +	} + +	return sprintf(buf, "%s\n", alarm_str); +} + +static DEVICE_ATTR(alarm_mode, S_IRUGO, ds1343_show_alarmmode, NULL); + +static ssize_t ds1343_show_tricklecharger(struct device *dev, +				struct device_attribute *attr, char *buf) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int data; +	char *diodes = "disabled", *resistors = " "; + +	regmap_read(priv->map, DS1343_TRICKLE_REG, &data); + +	if ((data & 0xf0) == DS1343_TRICKLE_MAGIC) { +		switch (data & 0x0c) { +		case DS1343_TRICKLE_DS1: +			diodes = "one diode,"; +			break; + +		default: +			diodes = "no diode,"; +			break; +		} + +		switch (data & 0x03) { +		case DS1343_TRICKLE_1K: +			resistors = "1k Ohm"; +			break; + +		case DS1343_TRICKLE_2K: +			resistors = "2k Ohm"; +			break; + +		case DS1343_TRICKLE_4K: +			resistors = "4k Ohm"; +			break; + +		default: +			diodes = "disabled"; +			break; +		} +	} + +	return sprintf(buf, "%s %s\n", diodes, resistors); +} + +static DEVICE_ATTR(trickle_charger, S_IRUGO, ds1343_show_tricklecharger, NULL); + +static int ds1343_sysfs_register(struct device *dev) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int err; + +	err = device_create_file(dev, &dev_attr_glitch_filter); +	if (err) +		return err; + +	err = device_create_file(dev, &dev_attr_trickle_charger); +	if (err) +		goto error1; + +	if (priv->irq <= 0) +		return err; + +	err = device_create_file(dev, &dev_attr_alarm_mode); +	if (err) +		goto error2; + +	err = device_create_file(dev, &dev_attr_alarm_status); +	if (!err) +		return err; + +	device_remove_file(dev, &dev_attr_alarm_mode); + +error2: +	device_remove_file(dev, &dev_attr_trickle_charger); + +error1: +	device_remove_file(dev, &dev_attr_glitch_filter); + +	return err; +} + +static void ds1343_sysfs_unregister(struct device *dev) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); + +	device_remove_file(dev, &dev_attr_glitch_filter); +	device_remove_file(dev, &dev_attr_trickle_charger); + +	if (priv->irq <= 0) +		return; + +	device_remove_file(dev, &dev_attr_alarm_status); +	device_remove_file(dev, &dev_attr_alarm_mode); +} + +static int ds1343_read_time(struct device *dev, struct rtc_time *dt) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	unsigned char buf[7]; +	int res; + +	res = regmap_bulk_read(priv->map, DS1343_SECONDS_REG, buf, 7); +	if (res) +		return res; + +	dt->tm_sec	= bcd2bin(buf[0]); +	dt->tm_min	= bcd2bin(buf[1]); +	dt->tm_hour	= bcd2bin(buf[2] & 0x3F); +	dt->tm_wday	= bcd2bin(buf[3]) - 1; +	dt->tm_mday	= bcd2bin(buf[4]); +	dt->tm_mon	= bcd2bin(buf[5] & 0x1F) - 1; +	dt->tm_year	= bcd2bin(buf[6]) + 100; /* year offset from 1900 */ + +	return rtc_valid_tm(dt); +} + +static int ds1343_set_time(struct device *dev, struct rtc_time *dt) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int res; + +	res = regmap_write(priv->map, DS1343_SECONDS_REG, +				bin2bcd(dt->tm_sec)); +	if (res) +		return res; + +	res = regmap_write(priv->map, DS1343_MINUTES_REG, +				bin2bcd(dt->tm_min)); +	if (res) +		return res; + +	res = regmap_write(priv->map, DS1343_HOURS_REG, +				bin2bcd(dt->tm_hour) & 0x3F); +	if (res) +		return res; + +	res = regmap_write(priv->map, DS1343_DAY_REG, +				bin2bcd(dt->tm_wday + 1)); +	if (res) +		return res; + +	res = regmap_write(priv->map, DS1343_DATE_REG, +				bin2bcd(dt->tm_mday)); +	if (res) +		return res; + +	res = regmap_write(priv->map, DS1343_MONTH_REG, +				bin2bcd(dt->tm_mon + 1)); +	if (res) +		return res; + +	dt->tm_year %= 100; + +	res = regmap_write(priv->map, DS1343_YEAR_REG, +				bin2bcd(dt->tm_year)); +	if (res) +		return res; + +	return 0; +} + +static int ds1343_update_alarm(struct device *dev) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	unsigned int control, stat; +	unsigned char buf[4]; +	int res = 0; + +	res = regmap_read(priv->map, DS1343_CONTROL_REG, &control); +	if (res) +		return res; + +	res = regmap_read(priv->map, DS1343_STATUS_REG, &stat); +	if (res) +		return res; + +	control &= ~(DS1343_A0IE); +	stat &= ~(DS1343_IRQF0); + +	res = regmap_write(priv->map, DS1343_CONTROL_REG, control); +	if (res) +		return res; + +	res = regmap_write(priv->map, DS1343_STATUS_REG, stat); +	if (res) +		return res; + +	buf[0] = priv->alarm_sec < 0 || (priv->irqen & RTC_UF) ? +		0x80 : bin2bcd(priv->alarm_sec) & 0x7F; +	buf[1] = priv->alarm_min < 0 || (priv->irqen & RTC_UF) ? +		0x80 : bin2bcd(priv->alarm_min) & 0x7F; +	buf[2] = priv->alarm_hour < 0 || (priv->irqen & RTC_UF) ? +		0x80 : bin2bcd(priv->alarm_hour) & 0x3F; +	buf[3] = priv->alarm_mday < 0 || (priv->irqen & RTC_UF) ? +		0x80 : bin2bcd(priv->alarm_mday) & 0x7F; + +	res = regmap_bulk_write(priv->map, DS1343_ALM0_SEC_REG, buf, 4); +	if (res) +		return res; + +	if (priv->irqen) { +		control |= DS1343_A0IE; +		res = regmap_write(priv->map, DS1343_CONTROL_REG, control); +	} + +	return res; +} + +static int ds1343_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int res = 0; +	unsigned int stat; + +	if (priv->irq <= 0) +		return -EINVAL; + +	mutex_lock(&priv->mutex); + +	res = regmap_read(priv->map, DS1343_STATUS_REG, &stat); +	if (res) +		goto out; + +	alarm->enabled = !!(priv->irqen & RTC_AF); +	alarm->pending = !!(stat & DS1343_IRQF0); + +	alarm->time.tm_sec = priv->alarm_sec < 0 ? 0 : priv->alarm_sec; +	alarm->time.tm_min = priv->alarm_min < 0 ? 0 : priv->alarm_min; +	alarm->time.tm_hour = priv->alarm_hour < 0 ? 0 : priv->alarm_hour; +	alarm->time.tm_mday = priv->alarm_mday < 0 ? 0 : priv->alarm_mday; + +	alarm->time.tm_mon = -1; +	alarm->time.tm_year = -1; +	alarm->time.tm_wday = -1; +	alarm->time.tm_yday = -1; +	alarm->time.tm_isdst = -1; + +out: +	mutex_unlock(&priv->mutex); +	return res; +} + +static int ds1343_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int res = 0; + +	if (priv->irq <= 0) +		return -EINVAL; + +	mutex_lock(&priv->mutex); + +	priv->alarm_sec = alarm->time.tm_sec; +	priv->alarm_min = alarm->time.tm_min; +	priv->alarm_hour = alarm->time.tm_hour; +	priv->alarm_mday = alarm->time.tm_mday; + +	if (alarm->enabled) +		priv->irqen |= RTC_AF; + +	res = ds1343_update_alarm(dev); + +	mutex_unlock(&priv->mutex); + +	return res; +} + +static int ds1343_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int res = 0; + +	if (priv->irq <= 0) +		return -EINVAL; + +	mutex_lock(&priv->mutex); + +	if (enabled) +		priv->irqen |= RTC_AF; +	else +		priv->irqen &= ~RTC_AF; + +	res = ds1343_update_alarm(dev); + +	mutex_unlock(&priv->mutex); + +	return res; +} + +static irqreturn_t ds1343_thread(int irq, void *dev_id) +{ +	struct ds1343_priv *priv = dev_id; +	unsigned int stat, control; +	int res = 0; + +	mutex_lock(&priv->mutex); + +	res = regmap_read(priv->map, DS1343_STATUS_REG, &stat); +	if (res) +		goto out; + +	if (stat & DS1343_IRQF0) { +		stat &= ~DS1343_IRQF0; +		regmap_write(priv->map, DS1343_STATUS_REG, stat); + +		res = regmap_read(priv->map, DS1343_CONTROL_REG, &control); +		if (res) +			goto out; + +		control &= ~DS1343_A0IE; +		regmap_write(priv->map, DS1343_CONTROL_REG, control); + +		rtc_update_irq(priv->rtc, 1, RTC_AF | RTC_IRQF); +	} + +out: +	mutex_unlock(&priv->mutex); +	return IRQ_HANDLED; +} + +static const struct rtc_class_ops ds1343_rtc_ops = { +	.ioctl		= ds1343_ioctl, +	.read_time	= ds1343_read_time, +	.set_time	= ds1343_set_time, +	.read_alarm	= ds1343_read_alarm, +	.set_alarm	= ds1343_set_alarm, +	.alarm_irq_enable = ds1343_alarm_irq_enable, +}; + +static int ds1343_probe(struct spi_device *spi) +{ +	struct ds1343_priv *priv; +	struct regmap_config config; +	unsigned int data; +	int res; + +	memset(&config, 0, sizeof(config)); +	config.reg_bits = 8; +	config.val_bits = 8; +	config.write_flag_mask = 0x80; + +	priv = devm_kzalloc(&spi->dev, sizeof(struct ds1343_priv), GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	priv->spi = spi; +	mutex_init(&priv->mutex); + +	/* RTC DS1347 works in spi mode 3 and +	 * its chip select is active high +	 */ +	spi->mode = SPI_MODE_3 | SPI_CS_HIGH; +	spi->bits_per_word = 8; +	res = spi_setup(spi); +	if (res) +		return res; + +	spi_set_drvdata(spi, priv); + +	priv->map = devm_regmap_init_spi(spi, &config); + +	if (IS_ERR(priv->map)) { +		dev_err(&spi->dev, "spi regmap init failed for rtc ds1343\n"); +		return PTR_ERR(priv->map); +	} + +	res = regmap_read(priv->map, DS1343_SECONDS_REG, &data); +	if (res) +		return res; + +	regmap_read(priv->map, DS1343_CONTROL_REG, &data); +	data |= DS1343_INTCN; +	data &= ~(DS1343_EOSC | DS1343_A1IE | DS1343_A0IE); +	regmap_write(priv->map, DS1343_CONTROL_REG, data); + +	regmap_read(priv->map, DS1343_STATUS_REG, &data); +	data &= ~(DS1343_OSF | DS1343_IRQF1 | DS1343_IRQF0); +	regmap_write(priv->map, DS1343_STATUS_REG, data); + +	priv->rtc = devm_rtc_device_register(&spi->dev, "ds1343", +					&ds1343_rtc_ops, THIS_MODULE); +	if (IS_ERR(priv->rtc)) { +		dev_err(&spi->dev, "unable to register rtc ds1343\n"); +		return PTR_ERR(priv->rtc); +	} + +	priv->irq = spi->irq; + +	if (priv->irq >= 0) { +		res = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, +						ds1343_thread, +						IRQF_NO_SUSPEND | IRQF_ONESHOT, +						"ds1343", priv); +		if (res) { +			priv->irq = -1; +			dev_err(&spi->dev, +				"unable to request irq for rtc ds1343\n"); +		} else { +			device_set_wakeup_capable(&spi->dev, 1); +		} +	} + +	res = ds1343_sysfs_register(&spi->dev); +	if (res) +		dev_err(&spi->dev, +			"unable to create sysfs entries for rtc ds1343\n"); + +	return 0; +} + +static int ds1343_remove(struct spi_device *spi) +{ +	struct ds1343_priv *priv = spi_get_drvdata(spi); + +	if (spi->irq) { +		mutex_lock(&priv->mutex); +		priv->irqen &= ~RTC_AF; +		mutex_unlock(&priv->mutex); + +		devm_free_irq(&spi->dev, spi->irq, priv); +	} + +	spi_set_drvdata(spi, NULL); + +	ds1343_sysfs_unregister(&spi->dev); + +	return 0; +} + +#ifdef CONFIG_PM_SLEEP + +static int ds1343_suspend(struct device *dev) +{ +	struct spi_device *spi = to_spi_device(dev); + +	if (spi->irq >= 0 && device_may_wakeup(dev)) +		enable_irq_wake(spi->irq); + +	return 0; +} + +static int ds1343_resume(struct device *dev) +{ +	struct spi_device *spi = to_spi_device(dev); + +	if (spi->irq >= 0 && device_may_wakeup(dev)) +		disable_irq_wake(spi->irq); + +	return 0; +} + +#endif + +static SIMPLE_DEV_PM_OPS(ds1343_pm, ds1343_suspend, ds1343_resume); + +static struct spi_driver ds1343_driver = { +	.driver = { +		.name = "ds1343", +		.owner = THIS_MODULE, +		.pm = &ds1343_pm, +	}, +	.probe = ds1343_probe, +	.remove = ds1343_remove, +	.id_table = ds1343_id, +}; + +module_spi_driver(ds1343_driver); + +MODULE_DESCRIPTION("DS1343 RTC SPI Driver"); +MODULE_AUTHOR("Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(DS1343_DRV_VERSION); diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 942103dac30f..c6b2191a4128 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -219,7 +219,7 @@ static int ds1742_rtc_remove(struct platform_device *pdev)  	return 0;  } -static struct of_device_id __maybe_unused ds1742_rtc_of_match[] = { +static const struct of_device_id __maybe_unused ds1742_rtc_of_match[] = {  	{ .compatible = "maxim,ds1742", },  	{ }  }; diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index 797aa0252ba9..c4c38431012e 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -35,7 +35,7 @@ static inline int  compute_yday(efi_time_t *eft)  {  	/* efi_time_t.month is in the [1-12] so, we need -1 */ -	return rtc_year_days(eft->day - 1, eft->month - 1, eft->year); +	return rtc_year_days(eft->day, eft->month - 1, eft->year);  }  /*   * returns day of the week [0-6] 0=Sunday diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c index bd628a6f981d..b936bb4096b5 100644 --- a/drivers/rtc/rtc-hym8563.c +++ b/drivers/rtc/rtc-hym8563.c @@ -418,6 +418,9 @@ static struct clk *hym8563_clkout_register_clk(struct hym8563 *hym8563)  	init.num_parents = 0;  	hym8563->clkout_hw.init = &init; +	/* optional override of the clockname */ +	of_property_read_string(node, "clock-output-names", &init.name); +  	/* register the clock */  	clk = clk_register(&client->dev, &hym8563->clkout_hw); @@ -569,6 +572,9 @@ static int hym8563_probe(struct i2c_client *client,  	if (IS_ERR(hym8563->rtc))  		return PTR_ERR(hym8563->rtc); +	/* the hym8563 alarm only supports a minute accuracy */ +	hym8563->rtc->uie_unsupported = 1; +  #ifdef CONFIG_COMMON_CLK  	hym8563_clkout_register_clk(hym8563);  #endif @@ -582,7 +588,7 @@ static const struct i2c_device_id hym8563_id[] = {  };  MODULE_DEVICE_TABLE(i2c, hym8563_id); -static struct of_device_id hym8563_dt_idtable[] = { +static const struct of_device_id hym8563_dt_idtable[] = {  	{ .compatible = "haoyu,hym8563" },  	{},  }; diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c index 41bd76aaff76..455b601d731d 100644 --- a/drivers/rtc/rtc-isl12057.c +++ b/drivers/rtc/rtc-isl12057.c @@ -278,7 +278,7 @@ static int isl12057_probe(struct i2c_client *client,  }  #ifdef CONFIG_OF -static struct of_device_id isl12057_dt_match[] = { +static const struct of_device_id isl12057_dt_match[] = {  	{ .compatible = "isl,isl12057" },  	{ },  }; diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index a5248aa1abf1..7ff7427c2e6a 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -66,8 +66,6 @@  #define M41T80_FEATURE_WD	(1 << 3)	/* Extra watchdog resolution */  #define M41T80_FEATURE_SQ_ALT	(1 << 4)	/* RSx bits are in reg 4 */ -#define DRV_VERSION "0.05" -  static DEFINE_MUTEX(m41t80_rtc_mutex);  static const struct i2c_device_id m41t80_id[] = {  	{ "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT }, @@ -80,6 +78,7 @@ static const struct i2c_device_id m41t80_id[] = {  	{ "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },  	{ "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },  	{ "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ }, +	{ "rv4162", M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT },  	{ }  };  MODULE_DEVICE_TABLE(i2c, m41t80_id); @@ -232,7 +231,7 @@ static ssize_t m41t80_sysfs_show_flags(struct device *dev,  	val = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);  	if (val < 0) -		return -EIO; +		return val;  	return sprintf(buf, "%#x\n", val);  }  static DEVICE_ATTR(flags, S_IRUGO, m41t80_sysfs_show_flags, NULL); @@ -252,7 +251,7 @@ static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev,  		reg_sqw = M41T80_REG_WDAY;  	val = i2c_smbus_read_byte_data(client, reg_sqw);  	if (val < 0) -		return -EIO; +		return val;  	val = (val >> 4) & 0xf;  	switch (val) {  	case 0: @@ -271,7 +270,7 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,  {  	struct i2c_client *client = to_i2c_client(dev);  	struct m41t80_data *clientdata = i2c_get_clientdata(client); -	int almon, sqw, reg_sqw; +	int almon, sqw, reg_sqw, rc;  	int val = simple_strtoul(buf, NULL, 0);  	if (!(clientdata->features & M41T80_FEATURE_SQ)) @@ -291,21 +290,30 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,  	/* disable SQW, set SQW frequency & re-enable */  	almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);  	if (almon < 0) -		return -EIO; +		return almon;  	reg_sqw = M41T80_REG_SQW;  	if (clientdata->features & M41T80_FEATURE_SQ_ALT)  		reg_sqw = M41T80_REG_WDAY;  	sqw = i2c_smbus_read_byte_data(client, reg_sqw);  	if (sqw < 0) -		return -EIO; +		return sqw;  	sqw = (sqw & 0x0f) | (val << 4); -	if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, -				      almon & ~M41T80_ALMON_SQWE) < 0 || -	    i2c_smbus_write_byte_data(client, reg_sqw, sqw) < 0) -		return -EIO; -	if (val && i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, -					     almon | M41T80_ALMON_SQWE) < 0) -		return -EIO; + +	rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, +				      almon & ~M41T80_ALMON_SQWE); +	if (rc < 0) +		return rc; + +	if (val) { +		rc = i2c_smbus_write_byte_data(client, reg_sqw, sqw); +		if (rc < 0) +			return rc; + +		rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, +					     almon | M41T80_ALMON_SQWE); +		if (rc <0) +			return rc; +	}  	return count;  }  static DEVICE_ATTR(sqwfreq, S_IRUGO | S_IWUSR, @@ -629,40 +637,28 @@ static int m41t80_probe(struct i2c_client *client,  	struct m41t80_data *clientdata = NULL;  	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C -				     | I2C_FUNC_SMBUS_BYTE_DATA)) { -		rc = -ENODEV; -		goto exit; -	} - -	dev_info(&client->dev, -		 "chip found, driver version " DRV_VERSION "\n"); +				     | I2C_FUNC_SMBUS_BYTE_DATA)) +		return -ENODEV;  	clientdata = devm_kzalloc(&client->dev, sizeof(*clientdata),  				GFP_KERNEL); -	if (!clientdata) { -		rc = -ENOMEM; -		goto exit; -	} +	if (!clientdata) +		return -ENOMEM;  	clientdata->features = id->driver_data;  	i2c_set_clientdata(client, clientdata);  	rtc = devm_rtc_device_register(&client->dev, client->name,  					&m41t80_rtc_ops, THIS_MODULE); -	if (IS_ERR(rtc)) { -		rc = PTR_ERR(rtc); -		rtc = NULL; -		goto exit; -	} +	if (IS_ERR(rtc)) +		return PTR_ERR(rtc);  	clientdata->rtc = rtc;  	/* Make sure HT (Halt Update) bit is cleared */  	rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR); -	if (rc < 0) -		goto ht_err; -	if (rc & M41T80_ALHOUR_HT) { +	if (rc >= 0 && rc & M41T80_ALHOUR_HT) {  		if (clientdata->features & M41T80_FEATURE_HT) {  			m41t80_get_datetime(client, &tm);  			dev_info(&client->dev, "HT bit was set!\n"); @@ -673,53 +669,44 @@ static int m41t80_probe(struct i2c_client *client,  				 tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,  				 tm.tm_min, tm.tm_sec);  		} -		if (i2c_smbus_write_byte_data(client, -					      M41T80_REG_ALARM_HOUR, -					      rc & ~M41T80_ALHOUR_HT) < 0) -			goto ht_err; +		rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_HOUR, +					      rc & ~M41T80_ALHOUR_HT); +	} + +	if (rc < 0) { +		dev_err(&client->dev, "Can't clear HT bit\n"); +		return rc;  	}  	/* Make sure ST (stop) bit is cleared */  	rc = i2c_smbus_read_byte_data(client, M41T80_REG_SEC); -	if (rc < 0) -		goto st_err; -	if (rc & M41T80_SEC_ST) { -		if (i2c_smbus_write_byte_data(client, M41T80_REG_SEC, -					      rc & ~M41T80_SEC_ST) < 0) -			goto st_err; +	if (rc >= 0 && rc & M41T80_SEC_ST) +		rc = i2c_smbus_write_byte_data(client, M41T80_REG_SEC, +					      rc & ~M41T80_SEC_ST); +	if (rc < 0) { +		dev_err(&client->dev, "Can't clear ST bit\n"); +		return rc;  	}  	rc = m41t80_sysfs_register(&client->dev);  	if (rc) -		goto exit; +		return rc;  #ifdef CONFIG_RTC_DRV_M41T80_WDT  	if (clientdata->features & M41T80_FEATURE_HT) {  		save_client = client;  		rc = misc_register(&wdt_dev);  		if (rc) -			goto exit; +			return rc;  		rc = register_reboot_notifier(&wdt_notifier);  		if (rc) {  			misc_deregister(&wdt_dev); -			goto exit; +			return rc;  		}  	}  #endif  	return 0; - -st_err: -	rc = -EIO; -	dev_err(&client->dev, "Can't clear ST bit\n"); -	goto exit; -ht_err: -	rc = -EIO; -	dev_err(&client->dev, "Can't clear HT bit\n"); -	goto exit; - -exit: -	return rc;  }  static int m41t80_remove(struct i2c_client *client) @@ -750,4 +737,3 @@ module_i2c_driver(m41t80_driver);  MODULE_AUTHOR("Alexander Bigga <ab@mycable.de>");  MODULE_DESCRIPTION("ST Microelectronics M41T80 series RTC I2C Client Driver");  MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c new file mode 100644 index 000000000000..34295bf00416 --- /dev/null +++ b/drivers/rtc/rtc-mcp795.c @@ -0,0 +1,199 @@ +/* + * SPI Driver for Microchip MCP795 RTC + * + * Copyright (C) Josef Gajdusek <atx@atx.name> + * + * based on other Linux RTC drivers + * + * Device datasheet: + * http://ww1.microchip.com/downloads/en/DeviceDoc/22280A.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/printk.h> +#include <linux/spi/spi.h> +#include <linux/rtc.h> + +/* MCP795 Instructions, see datasheet table 3-1 */ +#define MCP795_EEREAD	0x03 +#define MCP795_EEWRITE	0x02 +#define MCP795_EEWRDI	0x04 +#define MCP795_EEWREN	0x06 +#define MCP795_SRREAD	0x05 +#define MCP795_SRWRITE	0x01 +#define MCP795_READ		0x13 +#define MCP795_WRITE	0x12 +#define MCP795_UNLOCK	0x14 +#define MCP795_IDWRITE	0x32 +#define MCP795_IDREAD	0x33 +#define MCP795_CLRWDT	0x44 +#define MCP795_CLRRAM	0x54 + +#define MCP795_ST_BIT	0x80 +#define MCP795_24_BIT	0x40 + +static int mcp795_rtcc_read(struct device *dev, u8 addr, u8 *buf, u8 count) +{ +	struct spi_device *spi = to_spi_device(dev); +	int ret; +	u8 tx[2]; + +	tx[0] = MCP795_READ; +	tx[1] = addr; +	ret = spi_write_then_read(spi, tx, sizeof(tx), buf, count); + +	if (ret) +		dev_err(dev, "Failed reading %d bytes from address %x.\n", +					count, addr); + +	return ret; +} + +static int mcp795_rtcc_write(struct device *dev, u8 addr, u8 *data, u8 count) +{ +	struct spi_device *spi = to_spi_device(dev); +	int ret; +	u8 tx[2 + count]; + +	tx[0] = MCP795_WRITE; +	tx[1] = addr; +	memcpy(&tx[2], data, count); + +	ret = spi_write(spi, tx, 2 + count); + +	if (ret) +		dev_err(dev, "Failed to write %d bytes to address %x.\n", +					count, addr); + +	return ret; +} + +static int mcp795_rtcc_set_bits(struct device *dev, u8 addr, u8 mask, u8 state) +{ +	int ret; +	u8 tmp; + +	ret = mcp795_rtcc_read(dev, addr, &tmp, 1); +	if (ret) +		return ret; + +	if ((tmp & mask) != state) { +		tmp = (tmp & ~mask) | state; +		ret = mcp795_rtcc_write(dev, addr, &tmp, 1); +	} + +	return ret; +} + +static int mcp795_set_time(struct device *dev, struct rtc_time *tim) +{ +	int ret; +	u8 data[7]; + +	/* Read first, so we can leave config bits untouched */ +	ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data)); + +	if (ret) +		return ret; + +	data[0] = (data[0] & 0x80) | ((tim->tm_sec / 10) << 4) | (tim->tm_sec % 10); +	data[1] = (data[1] & 0x80) | ((tim->tm_min / 10) << 4) | (tim->tm_min % 10); +	data[2] = ((tim->tm_hour / 10) << 4) | (tim->tm_hour % 10); +	data[4] = ((tim->tm_mday / 10) << 4) | ((tim->tm_mday) % 10); +	data[5] = (data[5] & 0x10) | (tim->tm_mon / 10) | (tim->tm_mon % 10); + +	if (tim->tm_year > 100) +		tim->tm_year -= 100; + +	data[6] = ((tim->tm_year / 10) << 4) | (tim->tm_year % 10); + +	ret = mcp795_rtcc_write(dev, 0x01, data, sizeof(data)); + +	if (ret) +		return ret; + +	dev_dbg(dev, "Set mcp795: %04d-%02d-%02d %02d:%02d:%02d\n", +			tim->tm_year + 1900, tim->tm_mon, tim->tm_mday, +			tim->tm_hour, tim->tm_min, tim->tm_sec); + +	return 0; +} + +static int mcp795_read_time(struct device *dev, struct rtc_time *tim) +{ +	int ret; +	u8 data[7]; + +	ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data)); + +	if (ret) +		return ret; + +	tim->tm_sec		= ((data[0] & 0x70) >> 4) * 10 + (data[0] & 0x0f); +	tim->tm_min		= ((data[1] & 0x70) >> 4) * 10 + (data[1] & 0x0f); +	tim->tm_hour	= ((data[2] & 0x30) >> 4) * 10 + (data[2] & 0x0f); +	tim->tm_mday	= ((data[4] & 0x30) >> 4) * 10 + (data[4] & 0x0f); +	tim->tm_mon		= ((data[5] & 0x10) >> 4) * 10 + (data[5] & 0x0f); +	tim->tm_year	= ((data[6] & 0xf0) >> 4) * 10 + (data[6] & 0x0f) + 100; /* Assume we are in 20xx */ + +	dev_dbg(dev, "Read from mcp795: %04d-%02d-%02d %02d:%02d:%02d\n", +				tim->tm_year + 1900, tim->tm_mon, tim->tm_mday, +				tim->tm_hour, tim->tm_min, tim->tm_sec); + +	return rtc_valid_tm(tim); +} + +static struct rtc_class_ops mcp795_rtc_ops = { +		.read_time = mcp795_read_time, +		.set_time = mcp795_set_time +}; + +static int mcp795_probe(struct spi_device *spi) +{ +	struct rtc_device *rtc; +	int ret; + +	spi->mode = SPI_MODE_0; +	spi->bits_per_word = 8; +	ret = spi_setup(spi); +	if (ret) { +		dev_err(&spi->dev, "Unable to setup SPI\n"); +		return ret; +	} + +	/* Start the oscillator */ +	mcp795_rtcc_set_bits(&spi->dev, 0x01, MCP795_ST_BIT, MCP795_ST_BIT); +	/* Clear the 12 hour mode flag*/ +	mcp795_rtcc_set_bits(&spi->dev, 0x03, MCP795_24_BIT, 0); + +	rtc = devm_rtc_device_register(&spi->dev, "rtc-mcp795", +								&mcp795_rtc_ops, THIS_MODULE); +	if (IS_ERR(rtc)) +		return PTR_ERR(rtc); + +	spi_set_drvdata(spi, rtc); + +	return 0; +} + +static struct spi_driver mcp795_driver = { +		.driver = { +				.name = "rtc-mcp795", +				.owner = THIS_MODULE, +		}, +		.probe = mcp795_probe, +}; + +module_spi_driver(mcp795_driver); + +MODULE_DESCRIPTION("MCP795 RTC SPI Driver"); +MODULE_AUTHOR("Josef Gajdusek <atx@atx.name>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:mcp795"); diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index d15a999363fc..6aaec2fc7c0d 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -319,7 +319,7 @@ static int __exit mv_rtc_remove(struct platform_device *pdev)  }  #ifdef CONFIG_OF -static struct of_device_id rtc_mv_of_match_table[] = { +static const struct of_device_id rtc_mv_of_match_table[] = {  	{ .compatible = "marvell,orion-rtc", },  	{}  }; diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 26de5f8c2ae4..21142e6574a9 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -73,43 +73,52 @@  #define OMAP_RTC_IRQWAKEEN		0x7c  /* OMAP_RTC_CTRL_REG bit fields: */ -#define OMAP_RTC_CTRL_SPLIT		(1<<7) -#define OMAP_RTC_CTRL_DISABLE		(1<<6) -#define OMAP_RTC_CTRL_SET_32_COUNTER	(1<<5) -#define OMAP_RTC_CTRL_TEST		(1<<4) -#define OMAP_RTC_CTRL_MODE_12_24	(1<<3) -#define OMAP_RTC_CTRL_AUTO_COMP		(1<<2) -#define OMAP_RTC_CTRL_ROUND_30S		(1<<1) -#define OMAP_RTC_CTRL_STOP		(1<<0) +#define OMAP_RTC_CTRL_SPLIT		BIT(7) +#define OMAP_RTC_CTRL_DISABLE		BIT(6) +#define OMAP_RTC_CTRL_SET_32_COUNTER	BIT(5) +#define OMAP_RTC_CTRL_TEST		BIT(4) +#define OMAP_RTC_CTRL_MODE_12_24	BIT(3) +#define OMAP_RTC_CTRL_AUTO_COMP		BIT(2) +#define OMAP_RTC_CTRL_ROUND_30S		BIT(1) +#define OMAP_RTC_CTRL_STOP		BIT(0)  /* OMAP_RTC_STATUS_REG bit fields: */ -#define OMAP_RTC_STATUS_POWER_UP        (1<<7) -#define OMAP_RTC_STATUS_ALARM           (1<<6) -#define OMAP_RTC_STATUS_1D_EVENT        (1<<5) -#define OMAP_RTC_STATUS_1H_EVENT        (1<<4) -#define OMAP_RTC_STATUS_1M_EVENT        (1<<3) -#define OMAP_RTC_STATUS_1S_EVENT        (1<<2) -#define OMAP_RTC_STATUS_RUN             (1<<1) -#define OMAP_RTC_STATUS_BUSY            (1<<0) +#define OMAP_RTC_STATUS_POWER_UP	BIT(7) +#define OMAP_RTC_STATUS_ALARM		BIT(6) +#define OMAP_RTC_STATUS_1D_EVENT	BIT(5) +#define OMAP_RTC_STATUS_1H_EVENT	BIT(4) +#define OMAP_RTC_STATUS_1M_EVENT	BIT(3) +#define OMAP_RTC_STATUS_1S_EVENT	BIT(2) +#define OMAP_RTC_STATUS_RUN		BIT(1) +#define OMAP_RTC_STATUS_BUSY		BIT(0)  /* OMAP_RTC_INTERRUPTS_REG bit fields: */ -#define OMAP_RTC_INTERRUPTS_IT_ALARM    (1<<3) -#define OMAP_RTC_INTERRUPTS_IT_TIMER    (1<<2) +#define OMAP_RTC_INTERRUPTS_IT_ALARM	BIT(3) +#define OMAP_RTC_INTERRUPTS_IT_TIMER	BIT(2) + +/* OMAP_RTC_OSC_REG bit fields: */ +#define OMAP_RTC_OSC_32KCLK_EN		BIT(6)  /* OMAP_RTC_IRQWAKEEN bit fields: */ -#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN    (1<<1) +#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN	BIT(1)  /* OMAP_RTC_KICKER values */  #define	KICK0_VALUE			0x83e70b13  #define	KICK1_VALUE			0x95a4f1e0 -#define	OMAP_RTC_HAS_KICKER		0x1 +#define	OMAP_RTC_HAS_KICKER		BIT(0)  /*   * Few RTC IP revisions has special WAKE-EN Register to enable Wakeup   * generation for event Alarm.   */ -#define	OMAP_RTC_HAS_IRQWAKEEN		0x2 +#define	OMAP_RTC_HAS_IRQWAKEEN		BIT(1) + +/* + * Some RTC IP revisions (like those in AM335x and DRA7x) need + * the 32KHz clock to be explicitly enabled. + */ +#define OMAP_RTC_HAS_32KCLK_EN		BIT(2)  static void __iomem	*rtc_base; @@ -162,17 +171,28 @@ static irqreturn_t rtc_irq(int irq, void *rtc)  static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)  { -	u8 reg; +	u8 reg, irqwake_reg = 0; +	struct platform_device *pdev = to_platform_device(dev); +	const struct platform_device_id *id_entry = +					platform_get_device_id(pdev);  	local_irq_disable();  	rtc_wait_not_busy();  	reg = rtc_read(OMAP_RTC_INTERRUPTS_REG); -	if (enabled) +	if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) +		irqwake_reg = rtc_read(OMAP_RTC_IRQWAKEEN); + +	if (enabled) {  		reg |= OMAP_RTC_INTERRUPTS_IT_ALARM; -	else +		irqwake_reg |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; +	} else {  		reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM; +		irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; +	}  	rtc_wait_not_busy();  	rtc_write(reg, OMAP_RTC_INTERRUPTS_REG); +	if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) +		rtc_write(irqwake_reg, OMAP_RTC_IRQWAKEEN);  	local_irq_enable();  	return 0; @@ -272,7 +292,10 @@ static int omap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)  static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)  { -	u8 reg; +	u8 reg, irqwake_reg = 0; +	struct platform_device *pdev = to_platform_device(dev); +	const struct platform_device_id *id_entry = +					platform_get_device_id(pdev);  	if (tm2bcd(&alm->time) < 0)  		return -EINVAL; @@ -288,11 +311,19 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)  	rtc_write(alm->time.tm_sec, OMAP_RTC_ALARM_SECONDS_REG);  	reg = rtc_read(OMAP_RTC_INTERRUPTS_REG); -	if (alm->enabled) +	if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) +		irqwake_reg = rtc_read(OMAP_RTC_IRQWAKEEN); + +	if (alm->enabled) {  		reg |= OMAP_RTC_INTERRUPTS_IT_ALARM; -	else +		irqwake_reg |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; +	} else {  		reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM; +		irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; +	}  	rtc_write(reg, OMAP_RTC_INTERRUPTS_REG); +	if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) +		rtc_write(irqwake_reg, OMAP_RTC_IRQWAKEEN);  	local_irq_enable(); @@ -319,7 +350,8 @@ static struct platform_device_id omap_rtc_devtype[] = {  	},  	[OMAP_RTC_DATA_AM3352_IDX] = {  		.name	= "am3352-rtc", -		.driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN, +		.driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN | +			       OMAP_RTC_HAS_32KCLK_EN,  	},  	[OMAP_RTC_DATA_DA830_IDX] = {  		.name	= "da830-rtc", @@ -352,6 +384,12 @@ static int __init omap_rtc_probe(struct platform_device *pdev)  	if (of_id)  		pdev->id_entry = of_id->data; +	id_entry = platform_get_device_id(pdev); +	if (!id_entry) { +		dev_err(&pdev->dev, "no matching device entry\n"); +		return -ENODEV; +	} +  	omap_rtc_timer = platform_get_irq(pdev, 0);  	if (omap_rtc_timer <= 0) {  		pr_debug("%s: no update irq?\n", pdev->name); @@ -373,8 +411,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev)  	pm_runtime_enable(&pdev->dev);  	pm_runtime_get_sync(&pdev->dev); -	id_entry = platform_get_device_id(pdev); -	if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) { +	if (id_entry->driver_data & OMAP_RTC_HAS_KICKER) {  		rtc_writel(KICK0_VALUE, OMAP_RTC_KICK0_REG);  		rtc_writel(KICK1_VALUE, OMAP_RTC_KICK1_REG);  	} @@ -393,6 +430,10 @@ static int __init omap_rtc_probe(struct platform_device *pdev)  	 */  	rtc_write(0, OMAP_RTC_INTERRUPTS_REG); +	/* enable RTC functional clock */ +	if (id_entry->driver_data & OMAP_RTC_HAS_32KCLK_EN) +		rtc_writel(OMAP_RTC_OSC_32KCLK_EN, OMAP_RTC_OSC_REG); +  	/* clear old status */  	reg = rtc_read(OMAP_RTC_STATUS_REG);  	if (reg & (u8) OMAP_RTC_STATUS_POWER_UP) { @@ -452,7 +493,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev)  	return 0;  fail0: -	if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) +	if (id_entry->driver_data & OMAP_RTC_HAS_KICKER)  		rtc_writel(0, OMAP_RTC_KICK0_REG);  	pm_runtime_put_sync(&pdev->dev);  	pm_runtime_disable(&pdev->dev); @@ -469,7 +510,7 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)  	/* leave rtc running, but disable irqs */  	rtc_write(0, OMAP_RTC_INTERRUPTS_REG); -	if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) +	if (id_entry->driver_data & OMAP_RTC_HAS_KICKER)  		rtc_writel(0, OMAP_RTC_KICK0_REG);  	/* Disable the clock/module */ @@ -484,28 +525,16 @@ static u8 irqstat;  static int omap_rtc_suspend(struct device *dev)  { -	u8 irqwake_stat; -	struct platform_device *pdev = to_platform_device(dev); -	const struct platform_device_id *id_entry = -					platform_get_device_id(pdev); -  	irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG);  	/* FIXME the RTC alarm is not currently acting as a wakeup event  	 * source on some platforms, and in fact this enable() call is just  	 * saving a flag that's never used...  	 */ -	if (device_may_wakeup(dev)) { +	if (device_may_wakeup(dev))  		enable_irq_wake(omap_rtc_alarm); - -		if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) { -			irqwake_stat = rtc_read(OMAP_RTC_IRQWAKEEN); -			irqwake_stat |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; -			rtc_write(irqwake_stat, OMAP_RTC_IRQWAKEEN); -		} -	} else { +	else  		rtc_write(0, OMAP_RTC_INTERRUPTS_REG); -	}  	/* Disable the clock/module */  	pm_runtime_put_sync(dev); @@ -515,25 +544,14 @@ static int omap_rtc_suspend(struct device *dev)  static int omap_rtc_resume(struct device *dev)  { -	u8 irqwake_stat; -	struct platform_device *pdev = to_platform_device(dev); -	const struct platform_device_id *id_entry = -				platform_get_device_id(pdev); -  	/* Enable the clock/module so that we can access the registers */  	pm_runtime_get_sync(dev); -	if (device_may_wakeup(dev)) { +	if (device_may_wakeup(dev))  		disable_irq_wake(omap_rtc_alarm); - -		if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) { -			irqwake_stat = rtc_read(OMAP_RTC_IRQWAKEEN); -			irqwake_stat &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; -			rtc_write(irqwake_stat, OMAP_RTC_IRQWAKEEN); -		} -	} else { +	else  		rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG); -	} +  	return 0;  }  #endif diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c index c360d62fb3f6..4dfe2d793fa3 100644 --- a/drivers/rtc/rtc-palmas.c +++ b/drivers/rtc/rtc-palmas.c @@ -352,7 +352,7 @@ static SIMPLE_DEV_PM_OPS(palmas_rtc_pm_ops, palmas_rtc_suspend,  			 palmas_rtc_resume);  #ifdef CONFIG_OF -static struct of_device_id of_palmas_rtc_match[] = { +static const struct of_device_id of_palmas_rtc_match[] = {  	{ .compatible = "ti,palmas-rtc"},  	{ },  }; diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 5c8f8226c848..4cdb64be061b 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -206,7 +206,7 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm)  	tm->tm_hour = bcd2bin(regs[2] & 0x3f);  	tm->tm_mday = bcd2bin(regs[3] & 0x3f);  	tm->tm_wday = regs[4] & 0x7; -	tm->tm_mon = bcd2bin(regs[5] & 0x1f); +	tm->tm_mon = bcd2bin(regs[5] & 0x1f) - 1;  	tm->tm_year = bcd2bin(regs[6]) + 100;  	return rtc_valid_tm(tm); @@ -229,7 +229,7 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm)  	regs[3] = bin2bcd(tm->tm_hour);  	regs[4] = bin2bcd(tm->tm_mday);  	regs[5] = tm->tm_wday; -	regs[6] = bin2bcd(tm->tm_mon); +	regs[6] = bin2bcd(tm->tm_mon + 1);  	regs[7] = bin2bcd(tm->tm_year - 100);  	msg.addr = client->addr; diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index cccbf9d89729..4561f375327d 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -389,7 +389,7 @@ static int __exit pxa_rtc_remove(struct platform_device *pdev)  }  #ifdef CONFIG_OF -static struct of_device_id pxa_rtc_dt_ids[] = { +static const struct of_device_id pxa_rtc_dt_ids[] = {  	{ .compatible = "marvell,pxa-rtc" },  	{}  }; diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 476af93543f6..8f06250a0389 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 2013 Samsung Electronics Co., Ltd + * Copyright (c) 2013-2014 Samsung Electronics Co., Ltd   *	http://www.samsung.com   *   *  Copyright (C) 2013 Google, Inc @@ -17,29 +17,79 @@  #include <linux/module.h>  #include <linux/i2c.h> -#include <linux/slab.h>  #include <linux/bcd.h> -#include <linux/bitops.h>  #include <linux/regmap.h>  #include <linux/rtc.h> -#include <linux/delay.h>  #include <linux/platform_device.h>  #include <linux/mfd/samsung/core.h>  #include <linux/mfd/samsung/irq.h>  #include <linux/mfd/samsung/rtc.h> +#include <linux/mfd/samsung/s2mps14.h>  /*   * Maximum number of retries for checking changes in UDR field - * of SEC_RTC_UDR_CON register (to limit possible endless loop). + * of S5M_RTC_UDR_CON register (to limit possible endless loop).   *   * After writing to RTC registers (setting time or alarm) read the UDR field - * in SEC_RTC_UDR_CON register. UDR is auto-cleared when data have + * in S5M_RTC_UDR_CON register. UDR is auto-cleared when data have   * been transferred.   */  #define UDR_READ_RETRY_CNT	5 +/* Registers used by the driver which are different between chipsets. */ +struct s5m_rtc_reg_config { +	/* Number of registers used for setting time/alarm0/alarm1 */ +	unsigned int regs_count; +	/* First register for time, seconds */ +	unsigned int time; +	/* RTC control register */ +	unsigned int ctrl; +	/* First register for alarm 0, seconds */ +	unsigned int alarm0; +	/* First register for alarm 1, seconds */ +	unsigned int alarm1; +	/* SMPL/WTSR register */ +	unsigned int smpl_wtsr; +	/* +	 * Register for update flag (UDR). Typically setting UDR field to 1 +	 * will enable update of time or alarm register. Then it will be +	 * auto-cleared after successful update. +	 */ +	unsigned int rtc_udr_update; +	/* Mask for UDR field in 'rtc_udr_update' register */ +	unsigned int rtc_udr_mask; +}; + +/* Register map for S5M8763 and S5M8767 */ +static const struct s5m_rtc_reg_config s5m_rtc_regs = { +	.regs_count		= 8, +	.time			= S5M_RTC_SEC, +	.ctrl			= S5M_ALARM1_CONF, +	.alarm0			= S5M_ALARM0_SEC, +	.alarm1			= S5M_ALARM1_SEC, +	.smpl_wtsr		= S5M_WTSR_SMPL_CNTL, +	.rtc_udr_update		= S5M_RTC_UDR_CON, +	.rtc_udr_mask		= S5M_RTC_UDR_MASK, +}; + +/* + * Register map for S2MPS14. + * It may be also suitable for S2MPS11 but this was not tested. + */ +static const struct s5m_rtc_reg_config s2mps_rtc_regs = { +	.regs_count		= 7, +	.time			= S2MPS_RTC_SEC, +	.ctrl			= S2MPS_RTC_CTRL, +	.alarm0			= S2MPS_ALARM0_SEC, +	.alarm1			= S2MPS_ALARM1_SEC, +	.smpl_wtsr		= S2MPS_WTSR_SMPL_CNTL, +	.rtc_udr_update		= S2MPS_RTC_UDR_CON, +	.rtc_udr_mask		= S2MPS_RTC_WUDR_MASK, +}; +  struct s5m_rtc_info {  	struct device *dev; +	struct i2c_client *i2c;  	struct sec_pmic_dev *s5m87xx;  	struct regmap *regmap;  	struct rtc_device *rtc_dev; @@ -47,6 +97,21 @@ struct s5m_rtc_info {  	int device_type;  	int rtc_24hr_mode;  	bool wtsr_smpl; +	const struct s5m_rtc_reg_config	*regs; +}; + +static const struct regmap_config s5m_rtc_regmap_config = { +	.reg_bits = 8, +	.val_bits = 8, + +	.max_register = S5M_RTC_REG_MAX, +}; + +static const struct regmap_config s2mps14_rtc_regmap_config = { +	.reg_bits = 8, +	.val_bits = 8, + +	.max_register = S2MPS_RTC_REG_MAX,  };  static void s5m8767_data_to_tm(u8 *data, struct rtc_time *tm, @@ -104,8 +169,9 @@ static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info)  	unsigned int data;  	do { -		ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &data); -	} while (--retry && (data & RTC_UDR_MASK) && !ret); +		ret = regmap_read(info->regmap, info->regs->rtc_udr_update, +				&data); +	} while (--retry && (data & info->regs->rtc_udr_mask) && !ret);  	if (!retry)  		dev_err(info->dev, "waiting for UDR update, reached max number of retries\n"); @@ -113,21 +179,53 @@ static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info)  	return ret;  } +static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, +		struct rtc_wkalrm *alarm) +{ +	int ret; +	unsigned int val; + +	switch (info->device_type) { +	case S5M8767X: +	case S5M8763X: +		ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val); +		val &= S5M_ALARM0_STATUS; +		break; +	case S2MPS14X: +		ret = regmap_read(info->s5m87xx->regmap_pmic, S2MPS14_REG_ST2, +				&val); +		val &= S2MPS_ALARM0_STATUS; +		break; +	default: +		return -EINVAL; +	} +	if (ret < 0) +		return ret; + +	if (val) +		alarm->pending = 1; +	else +		alarm->pending = 0; + +	return 0; +} +  static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info)  {  	int ret;  	unsigned int data; -	ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &data); +	ret = regmap_read(info->regmap, info->regs->rtc_udr_update, &data);  	if (ret < 0) {  		dev_err(info->dev, "failed to read update reg(%d)\n", ret);  		return ret;  	} -	data |= RTC_TIME_EN_MASK; -	data |= RTC_UDR_MASK; +	data |= info->regs->rtc_udr_mask; +	if (info->device_type == S5M8763X || info->device_type == S5M8767X) +		data |= S5M_RTC_TIME_EN_MASK; -	ret = regmap_write(info->regmap, SEC_RTC_UDR_CON, data); +	ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data);  	if (ret < 0) {  		dev_err(info->dev, "failed to write update reg(%d)\n", ret);  		return ret; @@ -143,17 +241,27 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info)  	int ret;  	unsigned int data; -	ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &data); +	ret = regmap_read(info->regmap, info->regs->rtc_udr_update, &data);  	if (ret < 0) {  		dev_err(info->dev, "%s: fail to read update reg(%d)\n",  			__func__, ret);  		return ret;  	} -	data &= ~RTC_TIME_EN_MASK; -	data |= RTC_UDR_MASK; +	data |= info->regs->rtc_udr_mask; +	switch (info->device_type) { +	case S5M8763X: +	case S5M8767X: +		data &= ~S5M_RTC_TIME_EN_MASK; +		break; +	case S2MPS14X: +		data |= S2MPS_RTC_RUDR_MASK; +		break; +	default: +		return -EINVAL; +	} -	ret = regmap_write(info->regmap, SEC_RTC_UDR_CON, data); +	ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data);  	if (ret < 0) {  		dev_err(info->dev, "%s: fail to write update reg(%d)\n",  			__func__, ret); @@ -200,10 +308,22 @@ static void s5m8763_tm_to_data(struct rtc_time *tm, u8 *data)  static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm)  {  	struct s5m_rtc_info *info = dev_get_drvdata(dev); -	u8 data[8]; +	u8 data[info->regs->regs_count];  	int ret; -	ret = regmap_bulk_read(info->regmap, SEC_RTC_SEC, data, 8); +	if (info->device_type == S2MPS14X) { +		ret = regmap_update_bits(info->regmap, +				info->regs->rtc_udr_update, +				S2MPS_RTC_RUDR_MASK, S2MPS_RTC_RUDR_MASK); +		if (ret) { +			dev_err(dev, +				"Failed to prepare registers for time reading: %d\n", +				ret); +			return ret; +		} +	} +	ret = regmap_bulk_read(info->regmap, info->regs->time, data, +			info->regs->regs_count);  	if (ret < 0)  		return ret; @@ -213,6 +333,7 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm)  		break;  	case S5M8767X: +	case S2MPS14X:  		s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode);  		break; @@ -230,7 +351,7 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm)  static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm)  {  	struct s5m_rtc_info *info = dev_get_drvdata(dev); -	u8 data[8]; +	u8 data[info->regs->regs_count];  	int ret = 0;  	switch (info->device_type) { @@ -238,6 +359,7 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm)  		s5m8763_tm_to_data(tm, data);  		break;  	case S5M8767X: +	case S2MPS14X:  		ret = s5m8767_tm_to_data(tm, data);  		break;  	default: @@ -251,7 +373,8 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm)  		1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday,  		tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); -	ret = regmap_raw_write(info->regmap, SEC_RTC_SEC, data, 8); +	ret = regmap_raw_write(info->regmap, info->regs->time, data, +			info->regs->regs_count);  	if (ret < 0)  		return ret; @@ -263,70 +386,60 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm)  static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)  {  	struct s5m_rtc_info *info = dev_get_drvdata(dev); -	u8 data[8]; +	u8 data[info->regs->regs_count];  	unsigned int val;  	int ret, i; -	ret = regmap_bulk_read(info->regmap, SEC_ALARM0_SEC, data, 8); +	ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, +			info->regs->regs_count);  	if (ret < 0)  		return ret;  	switch (info->device_type) {  	case S5M8763X:  		s5m8763_data_to_tm(data, &alrm->time); -		ret = regmap_read(info->regmap, SEC_ALARM0_CONF, &val); +		ret = regmap_read(info->regmap, S5M_ALARM0_CONF, &val);  		if (ret < 0)  			return ret;  		alrm->enabled = !!val; - -		ret = regmap_read(info->regmap, SEC_RTC_STATUS, &val); -		if (ret < 0) -			return ret; -  		break;  	case S5M8767X: +	case S2MPS14X:  		s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); -		dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, -			1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon, -			alrm->time.tm_mday, alrm->time.tm_hour, -			alrm->time.tm_min, alrm->time.tm_sec, -			alrm->time.tm_wday); -  		alrm->enabled = 0; -		for (i = 0; i < 7; i++) { +		for (i = 0; i < info->regs->regs_count; i++) {  			if (data[i] & ALARM_ENABLE_MASK) {  				alrm->enabled = 1;  				break;  			}  		} - -		alrm->pending = 0; -		ret = regmap_read(info->regmap, SEC_RTC_STATUS, &val); -		if (ret < 0) -			return ret;  		break;  	default:  		return -EINVAL;  	} -	if (val & ALARM0_STATUS) -		alrm->pending = 1; -	else -		alrm->pending = 0; +	dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, +		1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon, +		alrm->time.tm_mday, alrm->time.tm_hour, +		alrm->time.tm_min, alrm->time.tm_sec, +		alrm->time.tm_wday); + +	ret = s5m_check_peding_alarm_interrupt(info, alrm);  	return 0;  }  static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info)  { -	u8 data[8]; +	u8 data[info->regs->regs_count];  	int ret, i;  	struct rtc_time tm; -	ret = regmap_bulk_read(info->regmap, SEC_ALARM0_SEC, data, 8); +	ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, +			info->regs->regs_count);  	if (ret < 0)  		return ret; @@ -337,14 +450,16 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info)  	switch (info->device_type) {  	case S5M8763X: -		ret = regmap_write(info->regmap, SEC_ALARM0_CONF, 0); +		ret = regmap_write(info->regmap, S5M_ALARM0_CONF, 0);  		break;  	case S5M8767X: -		for (i = 0; i < 7; i++) +	case S2MPS14X: +		for (i = 0; i < info->regs->regs_count; i++)  			data[i] &= ~ALARM_ENABLE_MASK; -		ret = regmap_raw_write(info->regmap, SEC_ALARM0_SEC, data, 8); +		ret = regmap_raw_write(info->regmap, info->regs->alarm0, data, +				info->regs->regs_count);  		if (ret < 0)  			return ret; @@ -362,11 +477,12 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info)  static int s5m_rtc_start_alarm(struct s5m_rtc_info *info)  {  	int ret; -	u8 data[8]; +	u8 data[info->regs->regs_count];  	u8 alarm0_conf;  	struct rtc_time tm; -	ret = regmap_bulk_read(info->regmap, SEC_ALARM0_SEC, data, 8); +	ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, +			info->regs->regs_count);  	if (ret < 0)  		return ret; @@ -378,10 +494,11 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info)  	switch (info->device_type) {  	case S5M8763X:  		alarm0_conf = 0x77; -		ret = regmap_write(info->regmap, SEC_ALARM0_CONF, alarm0_conf); +		ret = regmap_write(info->regmap, S5M_ALARM0_CONF, alarm0_conf);  		break;  	case S5M8767X: +	case S2MPS14X:  		data[RTC_SEC] |= ALARM_ENABLE_MASK;  		data[RTC_MIN] |= ALARM_ENABLE_MASK;  		data[RTC_HOUR] |= ALARM_ENABLE_MASK; @@ -393,7 +510,8 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info)  		if (data[RTC_YEAR1] & 0x7f)  			data[RTC_YEAR1] |= ALARM_ENABLE_MASK; -		ret = regmap_raw_write(info->regmap, SEC_ALARM0_SEC, data, 8); +		ret = regmap_raw_write(info->regmap, info->regs->alarm0, data, +				info->regs->regs_count);  		if (ret < 0)  			return ret;  		ret = s5m8767_rtc_set_alarm_reg(info); @@ -410,7 +528,7 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info)  static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)  {  	struct s5m_rtc_info *info = dev_get_drvdata(dev); -	u8 data[8]; +	u8 data[info->regs->regs_count];  	int ret;  	switch (info->device_type) { @@ -419,6 +537,7 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)  		break;  	case S5M8767X: +	case S2MPS14X:  		s5m8767_tm_to_data(&alrm->time, data);  		break; @@ -435,7 +554,8 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)  	if (ret < 0)  		return ret; -	ret = regmap_raw_write(info->regmap, SEC_ALARM0_SEC, data, 8); +	ret = regmap_raw_write(info->regmap, info->regs->alarm0, data, +			info->regs->regs_count);  	if (ret < 0)  		return ret; @@ -480,7 +600,7 @@ static const struct rtc_class_ops s5m_rtc_ops = {  static void s5m_rtc_enable_wtsr(struct s5m_rtc_info *info, bool enable)  {  	int ret; -	ret = regmap_update_bits(info->regmap, SEC_WTSR_SMPL_CNTL, +	ret = regmap_update_bits(info->regmap, info->regs->smpl_wtsr,  				 WTSR_ENABLE_MASK,  				 enable ? WTSR_ENABLE_MASK : 0);  	if (ret < 0) @@ -491,7 +611,7 @@ static void s5m_rtc_enable_wtsr(struct s5m_rtc_info *info, bool enable)  static void s5m_rtc_enable_smpl(struct s5m_rtc_info *info, bool enable)  {  	int ret; -	ret = regmap_update_bits(info->regmap, SEC_WTSR_SMPL_CNTL, +	ret = regmap_update_bits(info->regmap, info->regs->smpl_wtsr,  				 SMPL_ENABLE_MASK,  				 enable ? SMPL_ENABLE_MASK : 0);  	if (ret < 0) @@ -502,50 +622,41 @@ static void s5m_rtc_enable_smpl(struct s5m_rtc_info *info, bool enable)  static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info)  {  	u8 data[2]; -	unsigned int tp_read;  	int ret; -	struct rtc_time tm; -	ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &tp_read); -	if (ret < 0) { -		dev_err(info->dev, "%s: fail to read control reg(%d)\n", -			__func__, ret); -		return ret; -	} +	switch (info->device_type) { +	case S5M8763X: +	case S5M8767X: +		/* UDR update time. Default of 7.32 ms is too long. */ +		ret = regmap_update_bits(info->regmap, S5M_RTC_UDR_CON, +				S5M_RTC_UDR_T_MASK, S5M_RTC_UDR_T_450_US); +		if (ret < 0) +			dev_err(info->dev, "%s: fail to change UDR time: %d\n", +					__func__, ret); -	/* Set RTC control register : Binary mode, 24hour mode */ -	data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); -	data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); +		/* Set RTC control register : Binary mode, 24hour mode */ +		data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); +		data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); + +		ret = regmap_raw_write(info->regmap, S5M_ALARM0_CONF, data, 2); +		break; + +	case S2MPS14X: +		data[0] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); +		ret = regmap_write(info->regmap, info->regs->ctrl, data[0]); +		break; + +	default: +		return -EINVAL; +	}  	info->rtc_24hr_mode = 1; -	ret = regmap_raw_write(info->regmap, SEC_ALARM0_CONF, data, 2);  	if (ret < 0) {  		dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",  			__func__, ret);  		return ret;  	} -	/* In first boot time, Set rtc time to 1/1/2012 00:00:00(SUN) */ -	if ((tp_read & RTC_TCON_MASK) == 0) { -		dev_dbg(info->dev, "rtc init\n"); -		tm.tm_sec = 0; -		tm.tm_min = 0; -		tm.tm_hour = 0; -		tm.tm_wday = 0; -		tm.tm_mday = 1; -		tm.tm_mon = 0; -		tm.tm_year = 112; -		tm.tm_yday = 0; -		tm.tm_isdst = 0; -		ret = s5m_rtc_set_time(info->dev, &tm); -	} - -	ret = regmap_update_bits(info->regmap, SEC_RTC_UDR_CON, -				 RTC_TCON_MASK, tp_read | RTC_TCON_MASK); -	if (ret < 0) -		dev_err(info->dev, "%s: fail to update TCON reg(%d)\n", -			__func__, ret); -  	return ret;  } @@ -554,7 +665,8 @@ static int s5m_rtc_probe(struct platform_device *pdev)  	struct sec_pmic_dev *s5m87xx = dev_get_drvdata(pdev->dev.parent);  	struct sec_platform_data *pdata = s5m87xx->pdata;  	struct s5m_rtc_info *info; -	int ret; +	const struct regmap_config *regmap_cfg; +	int ret, alarm_irq;  	if (!pdata) {  		dev_err(pdev->dev.parent, "Platform data not supplied\n"); @@ -565,27 +677,52 @@ static int s5m_rtc_probe(struct platform_device *pdev)  	if (!info)  		return -ENOMEM; -	info->dev = &pdev->dev; -	info->s5m87xx = s5m87xx; -	info->regmap = s5m87xx->regmap_rtc; -	info->device_type = s5m87xx->device_type; -	info->wtsr_smpl = s5m87xx->wtsr_smpl; -  	switch (pdata->device_type) { +	case S2MPS14X: +		regmap_cfg = &s2mps14_rtc_regmap_config; +		info->regs = &s2mps_rtc_regs; +		alarm_irq = S2MPS14_IRQ_RTCA0; +		break;  	case S5M8763X: -		info->irq = regmap_irq_get_virq(s5m87xx->irq_data, -				S5M8763_IRQ_ALARM0); +		regmap_cfg = &s5m_rtc_regmap_config; +		info->regs = &s5m_rtc_regs; +		alarm_irq = S5M8763_IRQ_ALARM0;  		break; -  	case S5M8767X: -		info->irq = regmap_irq_get_virq(s5m87xx->irq_data, -				S5M8767_IRQ_RTCA1); +		regmap_cfg = &s5m_rtc_regmap_config; +		info->regs = &s5m_rtc_regs; +		alarm_irq = S5M8767_IRQ_RTCA1;  		break; -  	default: +		dev_err(&pdev->dev, "Device type is not supported by RTC driver\n"); +		return -ENODEV; +	} + +	info->i2c = i2c_new_dummy(s5m87xx->i2c->adapter, RTC_I2C_ADDR); +	if (!info->i2c) { +		dev_err(&pdev->dev, "Failed to allocate I2C for RTC\n"); +		return -ENODEV; +	} + +	info->regmap = devm_regmap_init_i2c(info->i2c, regmap_cfg); +	if (IS_ERR(info->regmap)) { +		ret = PTR_ERR(info->regmap); +		dev_err(&pdev->dev, "Failed to allocate RTC register map: %d\n", +				ret); +		goto err; +	} + +	info->dev = &pdev->dev; +	info->s5m87xx = s5m87xx; +	info->device_type = s5m87xx->device_type; +	info->wtsr_smpl = s5m87xx->wtsr_smpl; + +	info->irq = regmap_irq_get_virq(s5m87xx->irq_data, alarm_irq); +	if (info->irq <= 0) {  		ret = -EINVAL; -		dev_err(&pdev->dev, "Unsupported device type: %d\n", ret); -		return ret; +		dev_err(&pdev->dev, "Failed to get virtual IRQ %d\n", +				alarm_irq); +		goto err;  	}  	platform_set_drvdata(pdev, info); @@ -602,15 +739,24 @@ static int s5m_rtc_probe(struct platform_device *pdev)  	info->rtc_dev = devm_rtc_device_register(&pdev->dev, "s5m-rtc",  						 &s5m_rtc_ops, THIS_MODULE); -	if (IS_ERR(info->rtc_dev)) -		return PTR_ERR(info->rtc_dev); +	if (IS_ERR(info->rtc_dev)) { +		ret = PTR_ERR(info->rtc_dev); +		goto err; +	}  	ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,  					s5m_rtc_alarm_irq, 0, "rtc-alarm0",  					info); -	if (ret < 0) +	if (ret < 0) {  		dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",  			info->irq, ret); +		goto err; +	} + +	return 0; + +err: +	i2c_unregister_device(info->i2c);  	return ret;  } @@ -623,7 +769,7 @@ static void s5m_rtc_shutdown(struct platform_device *pdev)  	if (info->wtsr_smpl) {  		for (i = 0; i < 3; i++) {  			s5m_rtc_enable_wtsr(info, false); -			regmap_read(info->regmap, SEC_WTSR_SMPL_CNTL, &val); +			regmap_read(info->regmap, info->regs->smpl_wtsr, &val);  			pr_debug("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val);  			if (val & WTSR_ENABLE_MASK)  				pr_emerg("%s: fail to disable WTSR\n", @@ -639,6 +785,17 @@ static void s5m_rtc_shutdown(struct platform_device *pdev)  	s5m_rtc_enable_smpl(info, false);  } +static int s5m_rtc_remove(struct platform_device *pdev) +{ +	struct s5m_rtc_info *info = platform_get_drvdata(pdev); + +	/* Perform also all shutdown steps when removing */ +	s5m_rtc_shutdown(pdev); +	i2c_unregister_device(info->i2c); + +	return 0; +} +  #ifdef CONFIG_PM_SLEEP  static int s5m_rtc_resume(struct device *dev)  { @@ -666,7 +823,8 @@ static int s5m_rtc_suspend(struct device *dev)  static SIMPLE_DEV_PM_OPS(s5m_rtc_pm_ops, s5m_rtc_suspend, s5m_rtc_resume);  static const struct platform_device_id s5m_rtc_id[] = { -	{ "s5m-rtc", 0 }, +	{ "s5m-rtc",		S5M8767X }, +	{ "s2mps14-rtc",	S2MPS14X },  };  static struct platform_driver s5m_rtc_driver = { @@ -676,6 +834,7 @@ static struct platform_driver s5m_rtc_driver = {  		.pm	= &s5m_rtc_pm_ops,  	},  	.probe		= s5m_rtc_probe, +	.remove		= s5m_rtc_remove,  	.shutdown	= s5m_rtc_shutdown,  	.id_table	= s5m_rtc_id,  }; @@ -684,6 +843,6 @@ module_platform_driver(s5m_rtc_driver);  /* Module information */  MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); -MODULE_DESCRIPTION("Samsung S5M RTC driver"); +MODULE_DESCRIPTION("Samsung S5M/S2MPS14 RTC driver");  MODULE_LICENSE("GPL");  MODULE_ALIAS("platform:s5m-rtc"); diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 0f7adeb1944a..b6e1ca08c2c0 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -338,7 +338,7 @@ static SIMPLE_DEV_PM_OPS(sa1100_rtc_pm_ops, sa1100_rtc_suspend,  			sa1100_rtc_resume);  #ifdef CONFIG_OF -static struct of_device_id sa1100_rtc_dt_ids[] = { +static const struct of_device_id sa1100_rtc_dt_ids[] = {  	{ .compatible = "mrvl,sa1100-rtc", },  	{ .compatible = "mrvl,mmp-rtc", },  	{} diff --git a/drivers/rtc/rtc-xgene.c b/drivers/rtc/rtc-xgene.c new file mode 100644 index 000000000000..14129cc85bdb --- /dev/null +++ b/drivers/rtc/rtc-xgene.c @@ -0,0 +1,278 @@ +/* + * APM X-Gene SoC Real Time Clock Driver + * + * Copyright (c) 2014, Applied Micro Circuits Corporation + * Author: Rameshwar Prasad Sahu <rsahu@apm.com> + *         Loc Ho <lho@apm.com> + * + * This program is free software; you can redistribute  it and/or modify it + * under  the terms of  the GNU General  Public License as published by the + * Free Software Foundation;  either version 2 of the  License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/rtc.h> + +/* RTC CSR Registers */ +#define RTC_CCVR		0x00 +#define RTC_CMR			0x04 +#define RTC_CLR			0x08 +#define RTC_CCR			0x0C +#define  RTC_CCR_IE		BIT(0) +#define  RTC_CCR_MASK		BIT(1) +#define  RTC_CCR_EN		BIT(2) +#define  RTC_CCR_WEN		BIT(3) +#define RTC_STAT		0x10 +#define  RTC_STAT_BIT		BIT(0) +#define RTC_RSTAT		0x14 +#define RTC_EOI			0x18 +#define RTC_VER			0x1C + +struct xgene_rtc_dev { +	struct rtc_device *rtc; +	struct device *dev; +	unsigned long alarm_time; +	void __iomem *csr_base; +	struct clk *clk; +	unsigned int irq_wake; +}; + +static int xgene_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ +	struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); + +	rtc_time_to_tm(readl(pdata->csr_base + RTC_CCVR), tm); +	return rtc_valid_tm(tm); +} + +static int xgene_rtc_set_mmss(struct device *dev, unsigned long secs) +{ +	struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); + +	/* +	 * NOTE: After the following write, the RTC_CCVR is only reflected +	 *       after the update cycle of 1 seconds. +	 */ +	writel((u32) secs, pdata->csr_base + RTC_CLR); +	readl(pdata->csr_base + RTC_CLR); /* Force a barrier */ + +	return 0; +} + +static int xgene_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); + +	rtc_time_to_tm(pdata->alarm_time, &alrm->time); +	alrm->enabled = readl(pdata->csr_base + RTC_CCR) & RTC_CCR_IE; + +	return 0; +} + +static int xgene_rtc_alarm_irq_enable(struct device *dev, u32 enabled) +{ +	struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); +	u32 ccr; + +	ccr = readl(pdata->csr_base + RTC_CCR); +	if (enabled) { +		ccr &= ~RTC_CCR_MASK; +		ccr |= RTC_CCR_IE; +	} else { +		ccr &= ~RTC_CCR_IE; +		ccr |= RTC_CCR_MASK; +	} +	writel(ccr, pdata->csr_base + RTC_CCR); + +	return 0; +} + +static int xgene_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); +	unsigned long rtc_time; +	unsigned long alarm_time; + +	rtc_time = readl(pdata->csr_base + RTC_CCVR); +	rtc_tm_to_time(&alrm->time, &alarm_time); + +	pdata->alarm_time = alarm_time; +	writel((u32) pdata->alarm_time, pdata->csr_base + RTC_CMR); + +	xgene_rtc_alarm_irq_enable(dev, alrm->enabled); + +	return 0; +} + +static const struct rtc_class_ops xgene_rtc_ops = { +	.read_time	= xgene_rtc_read_time, +	.set_mmss	= xgene_rtc_set_mmss, +	.read_alarm	= xgene_rtc_read_alarm, +	.set_alarm	= xgene_rtc_set_alarm, +	.alarm_irq_enable = xgene_rtc_alarm_irq_enable, +}; + +static irqreturn_t xgene_rtc_interrupt(int irq, void *id) +{ +	struct xgene_rtc_dev *pdata = (struct xgene_rtc_dev *) id; + +	/* Check if interrupt asserted */ +	if (!(readl(pdata->csr_base + RTC_STAT) & RTC_STAT_BIT)) +		return IRQ_NONE; + +	/* Clear interrupt */ +	readl(pdata->csr_base + RTC_EOI); + +	rtc_update_irq(pdata->rtc, 1, RTC_IRQF | RTC_AF); + +	return IRQ_HANDLED; +} + +static int xgene_rtc_probe(struct platform_device *pdev) +{ +	struct xgene_rtc_dev *pdata; +	struct resource *res; +	int ret; +	int irq; + +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); +	if (!pdata) +		return -ENOMEM; +	platform_set_drvdata(pdev, pdata); +	pdata->dev = &pdev->dev; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	pdata->csr_base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(pdata->csr_base)) +		return PTR_ERR(pdata->csr_base); + +	irq = platform_get_irq(pdev, 0); +	if (irq < 0) { +		dev_err(&pdev->dev, "No IRQ resource\n"); +		return irq; +	} +	ret = devm_request_irq(&pdev->dev, irq, xgene_rtc_interrupt, 0, +			       dev_name(&pdev->dev), pdata); +	if (ret) { +		dev_err(&pdev->dev, "Could not request IRQ\n"); +		return ret; +	} + +	pdata->clk = devm_clk_get(&pdev->dev, NULL); +	if (IS_ERR(pdata->clk)) { +		dev_err(&pdev->dev, "Couldn't get the clock for RTC\n"); +		return -ENODEV; +	} +	clk_prepare_enable(pdata->clk); + +	/* Turn on the clock and the crystal */ +	writel(RTC_CCR_EN, pdata->csr_base + RTC_CCR); + +	device_init_wakeup(&pdev->dev, 1); + +	pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, +					 &xgene_rtc_ops, THIS_MODULE); +	if (IS_ERR(pdata->rtc)) { +		clk_disable_unprepare(pdata->clk); +		return PTR_ERR(pdata->rtc); +	} + +	/* HW does not support update faster than 1 seconds */ +	pdata->rtc->uie_unsupported = 1; + +	return 0; +} + +static int xgene_rtc_remove(struct platform_device *pdev) +{ +	struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev); + +	xgene_rtc_alarm_irq_enable(&pdev->dev, 0); +	device_init_wakeup(&pdev->dev, 0); +	clk_disable_unprepare(pdata->clk); +	return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int xgene_rtc_suspend(struct device *dev) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev); +	int irq; + +	irq = platform_get_irq(pdev, 0); +	if (device_may_wakeup(&pdev->dev)) { +		if (!enable_irq_wake(irq)) +			pdata->irq_wake = 1; +	} else { +		xgene_rtc_alarm_irq_enable(dev, 0); +		clk_disable(pdata->clk); +	} + +	return 0; +} + +static int xgene_rtc_resume(struct device *dev) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev); +	int irq; + +	irq = platform_get_irq(pdev, 0); +	if (device_may_wakeup(&pdev->dev)) { +		if (pdata->irq_wake) { +			disable_irq_wake(irq); +			pdata->irq_wake = 0; +		} +	} else { +		clk_enable(pdata->clk); +		xgene_rtc_alarm_irq_enable(dev, 1); +	} + +	return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(xgene_rtc_pm_ops, xgene_rtc_suspend, xgene_rtc_resume); + +#ifdef CONFIG_OF +static const struct of_device_id xgene_rtc_of_match[] = { +	{.compatible = "apm,xgene-rtc" }, +	{ } +}; +MODULE_DEVICE_TABLE(of, xgene_rtc_of_match); +#endif + +static struct platform_driver xgene_rtc_driver = { +	.probe		= xgene_rtc_probe, +	.remove		= xgene_rtc_remove, +	.driver		= { +		.owner	= THIS_MODULE, +		.name	= "xgene-rtc", +		.pm = &xgene_rtc_pm_ops, +		.of_match_table	= of_match_ptr(xgene_rtc_of_match), +	}, +}; + +module_platform_driver(xgene_rtc_driver); + +MODULE_DESCRIPTION("APM X-Gene SoC RTC driver"); +MODULE_AUTHOR("Rameshwar Sahu <rsahu@apm.com>"); +MODULE_LICENSE("GPL"); | 
