drivers/rtc/rtc-ds3232.c: enable ds3232 to work as wakeup source
Add suspend/resume and device_init_wakeup to enable ds3232 as wakeup source, /sys/class/rtc/rtcX/wakealarm for set wakeup alarm. Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									3f93822d36
								
							
						
					
					
						commit
						c93a3ae2d2
					
				| @ -57,6 +57,7 @@ struct ds3232 { | ||||
| 	 * in the remove function. | ||||
| 	 */ | ||||
| 	struct mutex mutex; | ||||
| 	bool suspended; | ||||
| 	int exiting; | ||||
| }; | ||||
| 
 | ||||
| @ -345,7 +346,15 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id) | ||||
| 	struct ds3232 *ds3232 = i2c_get_clientdata(client); | ||||
| 
 | ||||
| 	disable_irq_nosync(irq); | ||||
| 	schedule_work(&ds3232->work); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If rtc as a wakeup source, can't schedule the work | ||||
| 	 * at system resume flow, because at this time the i2c bus | ||||
| 	 * has not been resumed. | ||||
| 	 */ | ||||
| 	if (!ds3232->suspended) | ||||
| 		schedule_work(&ds3232->work); | ||||
| 
 | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| 
 | ||||
| @ -363,22 +372,26 @@ static void ds3232_work(struct work_struct *work) | ||||
| 
 | ||||
| 	if (stat & DS3232_REG_SR_A1F) { | ||||
| 		control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); | ||||
| 		if (control < 0) | ||||
| 			goto out; | ||||
| 		/* disable alarm1 interrupt */ | ||||
| 		control &= ~(DS3232_REG_CR_A1IE); | ||||
| 		i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); | ||||
| 		if (control < 0) { | ||||
| 			pr_warn("Read DS3232 Control Register error." | ||||
| 				"Disable IRQ%d.\n", client->irq); | ||||
| 		} else { | ||||
| 			/* disable alarm1 interrupt */ | ||||
| 			control &= ~(DS3232_REG_CR_A1IE); | ||||
| 			i2c_smbus_write_byte_data(client, DS3232_REG_CR, | ||||
| 						control); | ||||
| 
 | ||||
| 		/* clear the alarm pend flag */ | ||||
| 		stat &= ~DS3232_REG_SR_A1F; | ||||
| 		i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); | ||||
| 			/* clear the alarm pend flag */ | ||||
| 			stat &= ~DS3232_REG_SR_A1F; | ||||
| 			i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); | ||||
| 
 | ||||
| 		rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); | ||||
| 			rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); | ||||
| 
 | ||||
| 			if (!ds3232->exiting) | ||||
| 				enable_irq(client->irq); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| out: | ||||
| 	if (!ds3232->exiting) | ||||
| 		enable_irq(client->irq); | ||||
| unlock: | ||||
| 	mutex_unlock(&ds3232->mutex); | ||||
| } | ||||
| @ -411,21 +424,17 @@ static int ds3232_probe(struct i2c_client *client, | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	ds3232->rtc = devm_rtc_device_register(&client->dev, client->name, | ||||
| 					  &ds3232_rtc_ops, THIS_MODULE); | ||||
| 	if (IS_ERR(ds3232->rtc)) { | ||||
| 		return PTR_ERR(ds3232->rtc); | ||||
| 	} | ||||
| 
 | ||||
| 	if (client->irq >= 0) { | ||||
| 	if (client->irq > 0) { | ||||
| 		ret = devm_request_irq(&client->dev, client->irq, ds3232_irq, | ||||
| 				       IRQF_SHARED, "ds3232", client); | ||||
| 		if (ret) { | ||||
| 			dev_err(&client->dev, "unable to request IRQ\n"); | ||||
| 		} | ||||
| 		device_init_wakeup(&client->dev, 1); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 	ds3232->rtc = devm_rtc_device_register(&client->dev, client->name, | ||||
| 					  &ds3232_rtc_ops, THIS_MODULE); | ||||
| 	return PTR_ERR_OR_ZERO(ds3232->rtc); | ||||
| } | ||||
| 
 | ||||
| static int ds3232_remove(struct i2c_client *client) | ||||
| @ -444,6 +453,42 @@ static int ds3232_remove(struct i2c_client *client) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_PM_SLEEP | ||||
| static int ds3232_suspend(struct device *dev) | ||||
| { | ||||
| 	struct ds3232 *ds3232 = dev_get_drvdata(dev); | ||||
| 	struct i2c_client *client = to_i2c_client(dev); | ||||
| 
 | ||||
| 	if (device_can_wakeup(dev)) { | ||||
| 		ds3232->suspended = true; | ||||
| 		irq_set_irq_wake(client->irq, 1); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ds3232_resume(struct device *dev) | ||||
| { | ||||
| 	struct ds3232 *ds3232 = dev_get_drvdata(dev); | ||||
| 	struct i2c_client *client = to_i2c_client(dev); | ||||
| 
 | ||||
| 	if (ds3232->suspended) { | ||||
| 		ds3232->suspended = false; | ||||
| 
 | ||||
| 		/* Clear the hardware alarm pend flag */ | ||||
| 		schedule_work(&ds3232->work); | ||||
| 
 | ||||
| 		irq_set_irq_wake(client->irq, 0); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static const struct dev_pm_ops ds3232_pm_ops = { | ||||
| 	SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume) | ||||
| }; | ||||
| 
 | ||||
| static const struct i2c_device_id ds3232_id[] = { | ||||
| 	{ "ds3232", 0 }, | ||||
| 	{ } | ||||
| @ -454,6 +499,7 @@ static struct i2c_driver ds3232_driver = { | ||||
| 	.driver = { | ||||
| 		.name = "rtc-ds3232", | ||||
| 		.owner = THIS_MODULE, | ||||
| 		.pm	= &ds3232_pm_ops, | ||||
| 	}, | ||||
| 	.probe = ds3232_probe, | ||||
| 	.remove = ds3232_remove, | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user