From 370927c4b651539c65dd8d17dd5079526cd8401d Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 7 Mar 2016 00:27:47 +0900 Subject: rtc: ds3232: convert to use regmap This is preparation for merging rtc-ds3232 i2c driver and rtc-ds3234 spi driver. Signed-off-by: Akinobu Mita Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: Dennis Aberilla Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds3232.c | 216 +++++++++++++++++++++++++---------------------- 1 file changed, 113 insertions(+), 103 deletions(-) (limited to 'drivers/rtc/rtc-ds3232.c') diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 4e99ace66f74..5791f996fa32 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -9,11 +9,6 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ -/* - * It would be more efficient to use i2c msgs/i2c_transfer directly but, as - * recommened in .../Documentation/i2c/writing-clients section - * "Sending and receiving", using SMBus level communication is preferred. - */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -25,6 +20,7 @@ #include #include #include +#include #define DS3232_REG_SECONDS 0x00 #define DS3232_REG_MINUTES 0x01 @@ -50,7 +46,9 @@ # define DS3232_REG_SR_A1F 0x01 struct ds3232 { - struct i2c_client *client; + struct device *dev; + struct regmap *regmap; + int irq; struct rtc_device *rtc; struct work_struct work; @@ -63,26 +61,25 @@ struct ds3232 { int exiting; }; -static struct i2c_driver ds3232_driver; - -static int ds3232_check_rtc_status(struct i2c_client *client) +static int ds3232_check_rtc_status(struct device *dev) { + struct ds3232 *ds3232 = dev_get_drvdata(dev); int ret = 0; int control, stat; - stat = i2c_smbus_read_byte_data(client, DS3232_REG_SR); - if (stat < 0) - return stat; + ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat); + if (ret) + return ret; if (stat & DS3232_REG_SR_OSF) - dev_warn(&client->dev, + dev_warn(dev, "oscillator discontinuity flagged, " "time unreliable\n"); stat &= ~(DS3232_REG_SR_OSF | DS3232_REG_SR_A1F | DS3232_REG_SR_A2F); - ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); - if (ret < 0) + ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat); + if (ret) return ret; /* If the alarm is pending, clear it before requesting @@ -90,31 +87,28 @@ static int ds3232_check_rtc_status(struct i2c_client *client) * before everything is initialized. */ - control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); - if (control < 0) - return control; + ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control); + if (ret) + return ret; control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE); control |= DS3232_REG_CR_INTCN; - return i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); + return regmap_write(ds3232->regmap, DS3232_REG_CR, control); } static int ds3232_read_time(struct device *dev, struct rtc_time *time) { - struct i2c_client *client = to_i2c_client(dev); + struct ds3232 *ds3232 = dev_get_drvdata(dev); int ret; u8 buf[7]; unsigned int year, month, day, hour, minute, second; unsigned int week, twelve_hr, am_pm; unsigned int century, add_century = 0; - ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_SECONDS, 7, buf); - - if (ret < 0) + ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_SECONDS, buf, 7); + if (ret) return ret; - if (ret < 7) - return -EIO; second = buf[0]; minute = buf[1]; @@ -159,7 +153,7 @@ static int ds3232_read_time(struct device *dev, struct rtc_time *time) static int ds3232_set_time(struct device *dev, struct rtc_time *time) { - struct i2c_client *client = to_i2c_client(dev); + struct ds3232 *ds3232 = dev_get_drvdata(dev); u8 buf[7]; /* Extract time from rtc_time and load into ds3232*/ @@ -179,8 +173,7 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time) buf[6] = bin2bcd(time->tm_year); } - return i2c_smbus_write_i2c_block_data(client, - DS3232_REG_SECONDS, 7, buf); + return regmap_bulk_write(ds3232->regmap, DS3232_REG_SECONDS, buf, 7); } /* @@ -190,24 +183,21 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time) */ static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - struct i2c_client *client = to_i2c_client(dev); - struct ds3232 *ds3232 = i2c_get_clientdata(client); + struct ds3232 *ds3232 = dev_get_drvdata(dev); int control, stat; int ret; u8 buf[4]; mutex_lock(&ds3232->mutex); - ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR); - if (ret < 0) + ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat); + if (ret) goto out; - stat = ret; - ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR); - if (ret < 0) + ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control); + if (ret) goto out; - control = ret; - ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); - if (ret < 0) + ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_ALARM1, buf, 4); + if (ret) goto out; alarm->time.tm_sec = bcd2bin(buf[0] & 0x7F); @@ -236,13 +226,12 @@ out: */ static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - struct i2c_client *client = to_i2c_client(dev); - struct ds3232 *ds3232 = i2c_get_clientdata(client); + struct ds3232 *ds3232 = dev_get_drvdata(dev); int control, stat; int ret; u8 buf[4]; - if (client->irq <= 0) + if (ds3232->irq <= 0) return -EINVAL; mutex_lock(&ds3232->mutex); @@ -253,47 +242,45 @@ static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) buf[3] = bin2bcd(alarm->time.tm_mday); /* clear alarm interrupt enable bit */ - ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR); - if (ret < 0) + ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control); + if (ret) goto out; - control = ret; control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE); - ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); - if (ret < 0) + ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control); + if (ret) goto out; /* clear any pending alarm flag */ - ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR); - if (ret < 0) + ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat); + if (ret) goto out; - stat = ret; stat &= ~(DS3232_REG_SR_A1F | DS3232_REG_SR_A2F); - ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); - if (ret < 0) + ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat); + if (ret) goto out; - ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); + ret = regmap_bulk_write(ds3232->regmap, DS3232_REG_ALARM1, buf, 4); if (alarm->enabled) { control |= DS3232_REG_CR_A1IE; - ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); + ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control); } out: mutex_unlock(&ds3232->mutex); return ret; } -static void ds3232_update_alarm(struct i2c_client *client) +static void ds3232_update_alarm(struct device *dev) { - struct ds3232 *ds3232 = i2c_get_clientdata(client); + struct ds3232 *ds3232 = dev_get_drvdata(dev); int control; int ret; u8 buf[4]; mutex_lock(&ds3232->mutex); - ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); - if (ret < 0) + ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_ALARM1, buf, 4); + if (ret) goto unlock; buf[0] = bcd2bin(buf[0]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? @@ -305,12 +292,12 @@ static void ds3232_update_alarm(struct i2c_client *client) buf[3] = bcd2bin(buf[3]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? 0x80 : buf[3]; - ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); - if (ret < 0) + ret = regmap_bulk_write(ds3232->regmap, DS3232_REG_ALARM1, buf, 4); + if (ret) goto unlock; - control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); - if (control < 0) + ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control); + if (ret) goto unlock; if (ds3232->rtc->irq_data & (RTC_AF | RTC_UF)) @@ -319,7 +306,7 @@ static void ds3232_update_alarm(struct i2c_client *client) else /* disable alarm1 interrupt */ control &= ~(DS3232_REG_CR_A1IE); - i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); + regmap_write(ds3232->regmap, DS3232_REG_CR, control); unlock: mutex_unlock(&ds3232->mutex); @@ -327,10 +314,9 @@ unlock: static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled) { - struct i2c_client *client = to_i2c_client(dev); - struct ds3232 *ds3232 = i2c_get_clientdata(client); + struct ds3232 *ds3232 = dev_get_drvdata(dev); - if (client->irq <= 0) + if (ds3232->irq <= 0) return -EINVAL; if (enabled) @@ -338,14 +324,14 @@ static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled) else ds3232->rtc->irq_data &= ~RTC_AF; - ds3232_update_alarm(client); + ds3232_update_alarm(dev); return 0; } static irqreturn_t ds3232_irq(int irq, void *dev_id) { - struct i2c_client *client = dev_id; - struct ds3232 *ds3232 = i2c_get_clientdata(client); + struct device *dev = dev_id; + struct ds3232 *ds3232 = dev_get_drvdata(dev); disable_irq_nosync(irq); @@ -363,34 +349,33 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id) static void ds3232_work(struct work_struct *work) { struct ds3232 *ds3232 = container_of(work, struct ds3232, work); - struct i2c_client *client = ds3232->client; + int ret; int stat, control; mutex_lock(&ds3232->mutex); - stat = i2c_smbus_read_byte_data(client, DS3232_REG_SR); - if (stat < 0) + ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat); + if (ret) goto unlock; if (stat & DS3232_REG_SR_A1F) { - control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); - if (control < 0) { + ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control); + if (ret) { pr_warn("Read Control Register error - Disable IRQ%d\n", - client->irq); + ds3232->irq); } else { /* disable alarm1 interrupt */ control &= ~(DS3232_REG_CR_A1IE); - i2c_smbus_write_byte_data(client, DS3232_REG_CR, - control); + regmap_write(ds3232->regmap, DS3232_REG_CR, control); /* clear the alarm pend flag */ stat &= ~DS3232_REG_SR_A1F; - i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); + regmap_write(ds3232->regmap, DS3232_REG_SR, stat); rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); if (!ds3232->exiting) - enable_irq(client->irq); + enable_irq(ds3232->irq); } } @@ -406,49 +391,53 @@ static const struct rtc_class_ops ds3232_rtc_ops = { .alarm_irq_enable = ds3232_alarm_irq_enable, }; -static int ds3232_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, + const char *name) { struct ds3232 *ds3232; int ret; - ds3232 = devm_kzalloc(&client->dev, sizeof(struct ds3232), GFP_KERNEL); + ds3232 = devm_kzalloc(dev, sizeof(*ds3232), GFP_KERNEL); if (!ds3232) return -ENOMEM; - ds3232->client = client; - i2c_set_clientdata(client, ds3232); + ds3232->regmap = regmap; + ds3232->irq = irq; + ds3232->dev = dev; + dev_set_drvdata(dev, ds3232); INIT_WORK(&ds3232->work, ds3232_work); mutex_init(&ds3232->mutex); - ret = ds3232_check_rtc_status(client); + ret = ds3232_check_rtc_status(dev); if (ret) return ret; - if (client->irq > 0) { - ret = devm_request_irq(&client->dev, client->irq, ds3232_irq, - IRQF_SHARED, "ds3232", client); + if (ds3232->irq > 0) { + ret = devm_request_irq(dev, ds3232->irq, ds3232_irq, + IRQF_SHARED, name, dev); if (ret) { - dev_err(&client->dev, "unable to request IRQ\n"); - } - device_init_wakeup(&client->dev, 1); + ds3232->irq = 0; + dev_err(dev, "unable to request IRQ\n"); + } else + device_init_wakeup(dev, 1); } - ds3232->rtc = devm_rtc_device_register(&client->dev, client->name, - &ds3232_rtc_ops, THIS_MODULE); + ds3232->rtc = devm_rtc_device_register(dev, name, &ds3232_rtc_ops, + THIS_MODULE); + return PTR_ERR_OR_ZERO(ds3232->rtc); } -static int ds3232_remove(struct i2c_client *client) +static int ds3232_remove(struct device *dev) { - struct ds3232 *ds3232 = i2c_get_clientdata(client); + struct ds3232 *ds3232 = dev_get_drvdata(dev); - if (client->irq > 0) { + if (ds3232->irq > 0) { mutex_lock(&ds3232->mutex); ds3232->exiting = 1; mutex_unlock(&ds3232->mutex); - devm_free_irq(&client->dev, client->irq, client); + devm_free_irq(dev, ds3232->irq, dev); cancel_work_sync(&ds3232->work); } @@ -459,11 +448,10 @@ static int ds3232_remove(struct i2c_client *client) 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; - if (irq_set_irq_wake(client->irq, 1)) { + if (irq_set_irq_wake(ds3232->irq, 1)) { dev_warn_once(dev, "Cannot set wakeup source\n"); ds3232->suspended = false; } @@ -475,7 +463,6 @@ static int ds3232_suspend(struct device *dev) 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; @@ -483,7 +470,7 @@ static int ds3232_resume(struct device *dev) /* Clear the hardware alarm pend flag */ schedule_work(&ds3232->work); - irq_set_irq_wake(client->irq, 0); + irq_set_irq_wake(ds3232->irq, 0); } return 0; @@ -494,6 +481,30 @@ static const struct dev_pm_ops ds3232_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume) }; +static int ds3232_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct regmap *regmap; + static const struct regmap_config config = { + .reg_bits = 8, + .val_bits = 8, + }; + + regmap = devm_regmap_init_i2c(client, &config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "%s: regmap allocation failed: %ld\n", + __func__, PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return ds3232_probe(&client->dev, regmap, client->irq, client->name); +} + +static int ds3232_i2c_remove(struct i2c_client *client) +{ + return ds3232_remove(&client->dev); +} + static const struct i2c_device_id ds3232_id[] = { { "ds3232", 0 }, { } @@ -505,11 +516,10 @@ static struct i2c_driver ds3232_driver = { .name = "rtc-ds3232", .pm = &ds3232_pm_ops, }, - .probe = ds3232_probe, - .remove = ds3232_remove, + .probe = ds3232_i2c_probe, + .remove = ds3232_i2c_remove, .id_table = ds3232_id, }; - module_i2c_driver(ds3232_driver); MODULE_AUTHOR("Srikanth Srinivasan "); -- cgit v1.2.3 From 080481f54ef621211d6c75a03dc652fb6ed04222 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 7 Mar 2016 00:27:48 +0900 Subject: rtc: merge ds3232 and ds3234 According to "Feature Comparison of the DS323x Real-Time Clocks" (http://pdfserv.maximintegrated.com/en/an/AN5143.pdf), DS3232 and DS3234 are very similar. This merges rtc-ds3232 and rtc-ds3234 with using regmap. This change also enables to support alarm for ds3234. Signed-off-by: Akinobu Mita Suggested-by: Alexandre Belloni Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 44 ++++++------ drivers/rtc/Makefile | 1 - drivers/rtc/rtc-ds3232.c | 167 ++++++++++++++++++++++++++++++++++++++++++++- drivers/rtc/rtc-ds3234.c | 171 ----------------------------------------------- 4 files changed, 189 insertions(+), 194 deletions(-) delete mode 100644 drivers/rtc/rtc-ds3234.c (limited to 'drivers/rtc/rtc-ds3232.c') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 9babb4ccd65b..987c50168fd8 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -247,16 +247,6 @@ config RTC_DRV_DS1672 This driver can also be built as a module. If so, the module will be called rtc-ds1672. -config RTC_DRV_DS3232 - tristate "Dallas/Maxim DS3232" - help - If you say yes here you get support for Dallas Semiconductor - DS3232 real-time clock chips. If an interrupt is associated - with the device, the alarm functionality is supported. - - This driver can also be built as a module. If so, the module - will be called rtc-ds3232. - config RTC_DRV_HYM8563 tristate "Haoyu Microelectronics HYM8563" depends on OF @@ -733,15 +723,6 @@ config RTC_DRV_MAX6902 This driver can also be built as a module. If so, the module will be called rtc-max6902. -config RTC_DRV_DS3234 - tristate "Maxim/Dallas DS3234" - help - If you say yes here you get support for the - Maxim/Dallas DS3234 SPI RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-ds3234. - config RTC_DRV_PCF2123 tristate "NXP PCF2123" help @@ -761,6 +742,31 @@ config RTC_DRV_MCP795 endif # SPI_MASTER +# +# Helper to resolve issues with configs that have SPI enabled but I2C +# modular. See SND_SOC_I2C_AND_SPI for more information +# +config RTC_I2C_AND_SPI + tristate + default m if I2C=m + default y if I2C=y + default y if SPI_MASTER=y + select REGMAP_I2C if I2C + select REGMAP_SPI if SPI_MASTER + +comment "SPI and I2C RTC drivers" + +config RTC_DRV_DS3232 + tristate "Dallas/Maxim DS3232/DS3234" + depends on RTC_I2C_AND_SPI + help + If you say yes here you get support for Dallas Semiconductor + DS3232 and DS3234 real-time clock chips. If an interrupt is associated + with the device, the alarm functionality is supported. + + This driver can also be built as a module. If so, the module + will be called rtc-ds3232. + comment "Platform RTC drivers" # this 'CMOS' RTC driver is arch dependent because diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 27229d2a466b..ea2833723fa9 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -60,7 +60,6 @@ obj-$(CONFIG_RTC_DRV_DS1685_FAMILY) += rtc-ds1685.o obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o obj-$(CONFIG_RTC_DRV_DS2404) += rtc-ds2404.o obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o -obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 5791f996fa32..ca43bfcbb846 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -1,8 +1,9 @@ /* - * RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C + * RTC client/driver for the Maxim/Dallas DS3232/DS3234 Real-Time Clock * * Copyright (C) 2009-2011 Freescale Semiconductor. * Author: Jack Lan + * Copyright (C) 2008 MIMOMax Wireless Ltd. * * 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 @@ -16,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -481,6 +483,8 @@ static const struct dev_pm_ops ds3232_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume) }; +#if IS_ENABLED(CONFIG_I2C) + static int ds3232_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -520,8 +524,165 @@ static struct i2c_driver ds3232_driver = { .remove = ds3232_i2c_remove, .id_table = ds3232_id, }; -module_i2c_driver(ds3232_driver); + +static int ds3232_register_driver(void) +{ + return i2c_add_driver(&ds3232_driver); +} + +static void ds3232_unregister_driver(void) +{ + i2c_del_driver(&ds3232_driver); +} + +#else + +static int ds3232_register_driver(void) +{ + return 0; +} + +static void ds3232_unregister_driver(void) +{ +} + +#endif + +#if IS_ENABLED(CONFIG_SPI_MASTER) + +static int ds3234_probe(struct spi_device *spi) +{ + int res; + unsigned int tmp; + static const struct regmap_config config = { + .reg_bits = 8, + .val_bits = 8, + .write_flag_mask = 0x80, + }; + struct regmap *regmap; + + regmap = devm_regmap_init_spi(spi, &config); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "%s: regmap allocation failed: %ld\n", + __func__, PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + spi->mode = SPI_MODE_3; + spi->bits_per_word = 8; + spi_setup(spi); + + res = regmap_read(regmap, DS3232_REG_SECONDS, &tmp); + if (res) + return res; + + /* Control settings + * + * CONTROL_REG + * BIT 7 6 5 4 3 2 1 0 + * EOSC BBSQW CONV RS2 RS1 INTCN A2IE A1IE + * + * 0 0 0 1 1 1 0 0 + * + * CONTROL_STAT_REG + * BIT 7 6 5 4 3 2 1 0 + * OSF BB32kHz CRATE1 CRATE0 EN32kHz BSY A2F A1F + * + * 1 0 0 0 1 0 0 0 + */ + res = regmap_read(regmap, DS3232_REG_CR, &tmp); + if (res) + return res; + res = regmap_write(regmap, DS3232_REG_CR, tmp & 0x1c); + if (res) + return res; + + res = regmap_read(regmap, DS3232_REG_SR, &tmp); + if (res) + return res; + res = regmap_write(regmap, DS3232_REG_SR, tmp & 0x88); + if (res) + return res; + + /* Print our settings */ + res = regmap_read(regmap, DS3232_REG_CR, &tmp); + if (res) + return res; + dev_info(&spi->dev, "Control Reg: 0x%02x\n", tmp); + + res = regmap_read(regmap, DS3232_REG_SR, &tmp); + if (res) + return res; + dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp); + + return ds3232_probe(&spi->dev, regmap, spi->irq, "ds3234"); +} + +static int ds3234_remove(struct spi_device *spi) +{ + return ds3232_remove(&spi->dev); +} + +static struct spi_driver ds3234_driver = { + .driver = { + .name = "ds3234", + }, + .probe = ds3234_probe, + .remove = ds3234_remove, +}; + +static int ds3234_register_driver(void) +{ + return spi_register_driver(&ds3234_driver); +} + +static void ds3234_unregister_driver(void) +{ + spi_unregister_driver(&ds3234_driver); +} + +#else + +static int ds3234_register_driver(void) +{ + return 0; +} + +static void ds3234_unregister_driver(void) +{ +} + +#endif + +static int __init ds323x_init(void) +{ + int ret; + + ret = ds3232_register_driver(); + if (ret) { + pr_err("Failed to register ds3232 driver: %d\n", ret); + return ret; + } + + ret = ds3234_register_driver(); + if (ret) { + pr_err("Failed to register ds3234 driver: %d\n", ret); + ds3232_unregister_driver(); + } + + return ret; +} +module_init(ds323x_init) + +static void __exit ds323x_exit(void) +{ + ds3234_unregister_driver(); + ds3232_unregister_driver(); +} +module_exit(ds323x_exit) MODULE_AUTHOR("Srikanth Srinivasan "); -MODULE_DESCRIPTION("Maxim/Dallas DS3232 RTC Driver"); +MODULE_AUTHOR("Dennis Aberilla "); +MODULE_DESCRIPTION("Maxim/Dallas DS3232/DS3234 RTC Driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:ds3234"); diff --git a/drivers/rtc/rtc-ds3234.c b/drivers/rtc/rtc-ds3234.c deleted file mode 100644 index 570ab28fc354..000000000000 --- a/drivers/rtc/rtc-ds3234.c +++ /dev/null @@ -1,171 +0,0 @@ -/* rtc-ds3234.c - * - * Driver for Dallas Semiconductor (DS3234) SPI RTC with Integrated Crystal - * and SRAM. - * - * Copyright (C) 2008 MIMOMax Wireless Ltd. - * - * 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 -#include -#include -#include -#include -#include -#include - -#define DS3234_REG_SECONDS 0x00 -#define DS3234_REG_MINUTES 0x01 -#define DS3234_REG_HOURS 0x02 -#define DS3234_REG_DAY 0x03 -#define DS3234_REG_DATE 0x04 -#define DS3234_REG_MONTH 0x05 -#define DS3234_REG_YEAR 0x06 -#define DS3234_REG_CENTURY (1 << 7) /* Bit 7 of the Month register */ - -#define DS3234_REG_CONTROL 0x0E -#define DS3234_REG_CONT_STAT 0x0F - -static int ds3234_set_reg(struct device *dev, unsigned char address, - unsigned char data) -{ - struct spi_device *spi = to_spi_device(dev); - unsigned char buf[2]; - - /* MSB must be '1' to indicate write */ - buf[0] = address | 0x80; - buf[1] = data; - - return spi_write_then_read(spi, buf, 2, NULL, 0); -} - -static int ds3234_get_reg(struct device *dev, unsigned char address, - unsigned char *data) -{ - struct spi_device *spi = to_spi_device(dev); - - *data = address & 0x7f; - - return spi_write_then_read(spi, data, 1, data, 1); -} - -static int ds3234_read_time(struct device *dev, struct rtc_time *dt) -{ - int err; - unsigned char buf[8]; - struct spi_device *spi = to_spi_device(dev); - - buf[0] = 0x00; /* Start address */ - - err = spi_write_then_read(spi, buf, 1, buf, 8); - if (err != 0) - return err; - - /* Seconds, Minutes, Hours, Day, Date, Month, Year */ - 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; /* 0 = Sun */ - dt->tm_mday = bcd2bin(buf[4]); - dt->tm_mon = bcd2bin(buf[5] & 0x1f) - 1; /* 0 = Jan */ - dt->tm_year = bcd2bin(buf[6] & 0xff) + 100; /* Assume 20YY */ - - return rtc_valid_tm(dt); -} - -static int ds3234_set_time(struct device *dev, struct rtc_time *dt) -{ - ds3234_set_reg(dev, DS3234_REG_SECONDS, bin2bcd(dt->tm_sec)); - ds3234_set_reg(dev, DS3234_REG_MINUTES, bin2bcd(dt->tm_min)); - ds3234_set_reg(dev, DS3234_REG_HOURS, bin2bcd(dt->tm_hour) & 0x3f); - - /* 0 = Sun */ - ds3234_set_reg(dev, DS3234_REG_DAY, bin2bcd(dt->tm_wday + 1)); - ds3234_set_reg(dev, DS3234_REG_DATE, bin2bcd(dt->tm_mday)); - - /* 0 = Jan */ - ds3234_set_reg(dev, DS3234_REG_MONTH, bin2bcd(dt->tm_mon + 1)); - - /* Assume 20YY although we just want to make sure not to go negative. */ - if (dt->tm_year > 100) - dt->tm_year -= 100; - - ds3234_set_reg(dev, DS3234_REG_YEAR, bin2bcd(dt->tm_year)); - - return 0; -} - -static const struct rtc_class_ops ds3234_rtc_ops = { - .read_time = ds3234_read_time, - .set_time = ds3234_set_time, -}; - -static int ds3234_probe(struct spi_device *spi) -{ - struct rtc_device *rtc; - unsigned char tmp; - int res; - - spi->mode = SPI_MODE_3; - spi->bits_per_word = 8; - spi_setup(spi); - - res = ds3234_get_reg(&spi->dev, DS3234_REG_SECONDS, &tmp); - if (res != 0) - return res; - - /* Control settings - * - * CONTROL_REG - * BIT 7 6 5 4 3 2 1 0 - * EOSC BBSQW CONV RS2 RS1 INTCN A2IE A1IE - * - * 0 0 0 1 1 1 0 0 - * - * CONTROL_STAT_REG - * BIT 7 6 5 4 3 2 1 0 - * OSF BB32kHz CRATE1 CRATE0 EN32kHz BSY A2F A1F - * - * 1 0 0 0 1 0 0 0 - */ - ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp); - ds3234_set_reg(&spi->dev, DS3234_REG_CONTROL, tmp & 0x1c); - - ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp); - ds3234_set_reg(&spi->dev, DS3234_REG_CONT_STAT, tmp & 0x88); - - /* Print our settings */ - ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp); - dev_info(&spi->dev, "Control Reg: 0x%02x\n", tmp); - - ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp); - dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp); - - rtc = devm_rtc_device_register(&spi->dev, "ds3234", - &ds3234_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - - spi_set_drvdata(spi, rtc); - - return 0; -} - -static struct spi_driver ds3234_driver = { - .driver = { - .name = "ds3234", - }, - .probe = ds3234_probe, -}; - -module_spi_driver(ds3234_driver); - -MODULE_DESCRIPTION("DS3234 SPI RTC driver"); -MODULE_AUTHOR("Dennis Aberilla "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("spi:ds3234"); -- cgit v1.2.3 From dfc2532b55a4989930d0d67cdf83da9ccb2a1b5b Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 7 Mar 2016 00:27:49 +0900 Subject: rtc: ds3232: fix read on /dev/rtc after RTC_AIE_ON The rtctest (tools/testing/selftests/timers/rtctest.c) found that reading ds3232 rtc device immediately return the value 0x20 (RTC_AF) without waiting alarm interrupt. This is because alarm_irq_enable() of ds3232 driver changes RTC_AF flag in rtc->irq_data. So calling ioctl with RTC_AIE_ON generates invalid value in rtc device. The lower-level driver should not touch rtc->irq_data directly. Signed-off-by: Akinobu Mita Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds3232.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/rtc/rtc-ds3232.c') diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index ca43bfcbb846..6bf7848c1576 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -272,7 +272,7 @@ out: return ret; } -static void ds3232_update_alarm(struct device *dev) +static void ds3232_update_alarm(struct device *dev, unsigned int enabled) { struct ds3232 *ds3232 = dev_get_drvdata(dev); int control; @@ -302,7 +302,7 @@ static void ds3232_update_alarm(struct device *dev) if (ret) goto unlock; - if (ds3232->rtc->irq_data & (RTC_AF | RTC_UF)) + if (enabled || (ds3232->rtc->irq_data & RTC_UF)) /* enable alarm1 interrupt */ control |= DS3232_REG_CR_A1IE; else @@ -321,12 +321,8 @@ static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled) if (ds3232->irq <= 0) return -EINVAL; - if (enabled) - ds3232->rtc->irq_data |= RTC_AF; - else - ds3232->rtc->irq_data &= ~RTC_AF; + ds3232_update_alarm(dev, enabled); - ds3232_update_alarm(dev); return 0; } -- cgit v1.2.3 From 7b4393a62f784bdd295c397c640cd93238ded0be Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 7 Mar 2016 00:27:50 +0900 Subject: rtc: ds3232: add register access error checks Add missing register access error checks and make it return error code or print error message. Signed-off-by: Akinobu Mita Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds3232.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'drivers/rtc/rtc-ds3232.c') diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 6bf7848c1576..321b8670ff7a 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -262,6 +262,8 @@ static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) goto out; ret = regmap_bulk_write(ds3232->regmap, DS3232_REG_ALARM1, buf, 4); + if (ret) + goto out; if (alarm->enabled) { control |= DS3232_REG_CR_A1IE; @@ -272,7 +274,7 @@ out: return ret; } -static void ds3232_update_alarm(struct device *dev, unsigned int enabled) +static int ds3232_update_alarm(struct device *dev, unsigned int enabled) { struct ds3232 *ds3232 = dev_get_drvdata(dev); int control; @@ -308,10 +310,12 @@ static void ds3232_update_alarm(struct device *dev, unsigned int enabled) else /* disable alarm1 interrupt */ control &= ~(DS3232_REG_CR_A1IE); - regmap_write(ds3232->regmap, DS3232_REG_CR, control); + ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control); unlock: mutex_unlock(&ds3232->mutex); + + return ret; } static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled) @@ -321,9 +325,7 @@ static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled) if (ds3232->irq <= 0) return -EINVAL; - ds3232_update_alarm(dev, enabled); - - return 0; + return ds3232_update_alarm(dev, enabled); } static irqreturn_t ds3232_irq(int irq, void *dev_id) @@ -364,11 +366,24 @@ static void ds3232_work(struct work_struct *work) } else { /* disable alarm1 interrupt */ control &= ~(DS3232_REG_CR_A1IE); - regmap_write(ds3232->regmap, DS3232_REG_CR, control); + ret = regmap_write(ds3232->regmap, DS3232_REG_CR, + control); + if (ret) { + dev_warn(ds3232->dev, + "Write Control Register error %d\n", + ret); + goto unlock; + } /* clear the alarm pend flag */ stat &= ~DS3232_REG_SR_A1F; - regmap_write(ds3232->regmap, DS3232_REG_SR, stat); + ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat); + if (ret) { + dev_warn(ds3232->dev, + "Write Status Register error %d\n", + ret); + goto unlock; + } rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); -- cgit v1.2.3 From 7522297e1638f985e5d52f34b871e742b10586d4 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 7 Mar 2016 00:27:51 +0900 Subject: rtc: ds3232: remove unused UIE code UIE mode irqs are handled by the generic rtc core now. But there are remaining unused code fragments for it. Signed-off-by: Akinobu Mita Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds3232.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) (limited to 'drivers/rtc/rtc-ds3232.c') diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 321b8670ff7a..f0ffd3f5d8f5 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -279,32 +279,14 @@ static int ds3232_update_alarm(struct device *dev, unsigned int enabled) struct ds3232 *ds3232 = dev_get_drvdata(dev); int control; int ret; - u8 buf[4]; mutex_lock(&ds3232->mutex); - ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_ALARM1, buf, 4); - if (ret) - goto unlock; - - buf[0] = bcd2bin(buf[0]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? - 0x80 : buf[0]; - buf[1] = bcd2bin(buf[1]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? - 0x80 : buf[1]; - buf[2] = bcd2bin(buf[2]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? - 0x80 : buf[2]; - buf[3] = bcd2bin(buf[3]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? - 0x80 : buf[3]; - - ret = regmap_bulk_write(ds3232->regmap, DS3232_REG_ALARM1, buf, 4); - if (ret) - goto unlock; - ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control); if (ret) goto unlock; - if (enabled || (ds3232->rtc->irq_data & RTC_UF)) + if (enabled) /* enable alarm1 interrupt */ control |= DS3232_REG_CR_A1IE; else -- cgit v1.2.3 From 95c60c1c8f51521e7f2174fd0fff4dae6d522b83 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 7 Mar 2016 00:27:52 +0900 Subject: rtc: ds3232: fix issue when irq is shared several devices ds3232-core requests irq with IRQF_SHARED, so irq can be shared by several devices. But the irq handler for ds3232 unconditionally disables the irq at first and the irq is re-enabled only when the interrupt source was the ds3232's alarm. This behaviour breaks the devices sharing the same irq in the various scenarios. This converts to use threaded irq and remove outdated code in suspend/resume paths. Signed-off-by: Akinobu Mita Suggested-by: Alexandre Belloni Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds3232.c | 81 +++++++----------------------------------------- 1 file changed, 12 insertions(+), 69 deletions(-) (limited to 'drivers/rtc/rtc-ds3232.c') diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index f0ffd3f5d8f5..9857287215a9 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -52,7 +51,6 @@ struct ds3232 { struct regmap *regmap; int irq; struct rtc_device *rtc; - struct work_struct work; /* The mutex protects alarm operations, and prevents a race * between the enable_irq() in the workqueue and the free_irq() @@ -60,7 +58,6 @@ struct ds3232 { */ struct mutex mutex; bool suspended; - int exiting; }; static int ds3232_check_rtc_status(struct device *dev) @@ -314,23 +311,6 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id) { struct device *dev = dev_id; struct ds3232 *ds3232 = dev_get_drvdata(dev); - - disable_irq_nosync(irq); - - /* - * 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; -} - -static void ds3232_work(struct work_struct *work) -{ - struct ds3232 *ds3232 = container_of(work, struct ds3232, work); int ret; int stat, control; @@ -343,8 +323,8 @@ static void ds3232_work(struct work_struct *work) if (stat & DS3232_REG_SR_A1F) { ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control); if (ret) { - pr_warn("Read Control Register error - Disable IRQ%d\n", - ds3232->irq); + dev_warn(ds3232->dev, + "Read Control Register error %d\n", ret); } else { /* disable alarm1 interrupt */ control &= ~(DS3232_REG_CR_A1IE); @@ -368,14 +348,13 @@ static void ds3232_work(struct work_struct *work) } rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); - - if (!ds3232->exiting) - enable_irq(ds3232->irq); } } unlock: mutex_unlock(&ds3232->mutex); + + return IRQ_HANDLED; } static const struct rtc_class_ops ds3232_rtc_ops = { @@ -401,7 +380,6 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, ds3232->dev = dev; dev_set_drvdata(dev, ds3232); - INIT_WORK(&ds3232->work, ds3232_work); mutex_init(&ds3232->mutex); ret = ds3232_check_rtc_status(dev); @@ -409,8 +387,10 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, return ret; if (ds3232->irq > 0) { - ret = devm_request_irq(dev, ds3232->irq, ds3232_irq, - IRQF_SHARED, name, dev); + ret = devm_request_threaded_irq(dev, ds3232->irq, NULL, + ds3232_irq, + IRQF_SHARED | IRQF_ONESHOT, + name, dev); if (ret) { ds3232->irq = 0; dev_err(dev, "unable to request IRQ\n"); @@ -423,33 +403,14 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, return PTR_ERR_OR_ZERO(ds3232->rtc); } -static int ds3232_remove(struct device *dev) -{ - struct ds3232 *ds3232 = dev_get_drvdata(dev); - - if (ds3232->irq > 0) { - mutex_lock(&ds3232->mutex); - ds3232->exiting = 1; - mutex_unlock(&ds3232->mutex); - - devm_free_irq(dev, ds3232->irq, dev); - cancel_work_sync(&ds3232->work); - } - - return 0; -} - #ifdef CONFIG_PM_SLEEP static int ds3232_suspend(struct device *dev) { struct ds3232 *ds3232 = dev_get_drvdata(dev); - if (device_can_wakeup(dev)) { - ds3232->suspended = true; - if (irq_set_irq_wake(ds3232->irq, 1)) { + if (device_may_wakeup(dev)) { + if (enable_irq_wake(ds3232->irq)) dev_warn_once(dev, "Cannot set wakeup source\n"); - ds3232->suspended = false; - } } return 0; @@ -459,14 +420,8 @@ static int ds3232_resume(struct device *dev) { struct ds3232 *ds3232 = dev_get_drvdata(dev); - if (ds3232->suspended) { - ds3232->suspended = false; - - /* Clear the hardware alarm pend flag */ - schedule_work(&ds3232->work); - - irq_set_irq_wake(ds3232->irq, 0); - } + if (device_may_wakeup(dev)) + disable_irq_wake(ds3232->irq); return 0; } @@ -497,11 +452,6 @@ static int ds3232_i2c_probe(struct i2c_client *client, return ds3232_probe(&client->dev, regmap, client->irq, client->name); } -static int ds3232_i2c_remove(struct i2c_client *client) -{ - return ds3232_remove(&client->dev); -} - static const struct i2c_device_id ds3232_id[] = { { "ds3232", 0 }, { } @@ -514,7 +464,6 @@ static struct i2c_driver ds3232_driver = { .pm = &ds3232_pm_ops, }, .probe = ds3232_i2c_probe, - .remove = ds3232_i2c_remove, .id_table = ds3232_id, }; @@ -611,17 +560,11 @@ static int ds3234_probe(struct spi_device *spi) return ds3232_probe(&spi->dev, regmap, spi->irq, "ds3234"); } -static int ds3234_remove(struct spi_device *spi) -{ - return ds3232_remove(&spi->dev); -} - static struct spi_driver ds3234_driver = { .driver = { .name = "ds3234", }, .probe = ds3234_probe, - .remove = ds3234_remove, }; static int ds3234_register_driver(void) -- cgit v1.2.3 From fc1dcb0b39dbb10d3290f2fcd6e154670f699166 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 7 Mar 2016 00:27:53 +0900 Subject: rtc: ds3232: use rtc->ops_lock to protect alarm operations ds3232->mutex is used to protect for alarm operations which need to access status and control registers. But we can use rtc->ops_lock instead. rtc->ops_lock is held when most of rtc_class_ops methods are called, so we only need to explicitly acquire it from irq handler in order to protect form concurrent accesses. Signed-off-by: Akinobu Mita Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds3232.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) (limited to 'drivers/rtc/rtc-ds3232.c') diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 9857287215a9..7edc889729c5 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -52,11 +52,6 @@ struct ds3232 { int irq; struct rtc_device *rtc; - /* The mutex protects alarm operations, and prevents a race - * between the enable_irq() in the workqueue and the free_irq() - * in the remove function. - */ - struct mutex mutex; bool suspended; }; @@ -187,8 +182,6 @@ static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) int ret; u8 buf[4]; - mutex_lock(&ds3232->mutex); - ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat); if (ret) goto out; @@ -215,7 +208,6 @@ static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) ret = 0; out: - mutex_unlock(&ds3232->mutex); return ret; } @@ -233,8 +225,6 @@ static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) if (ds3232->irq <= 0) return -EINVAL; - mutex_lock(&ds3232->mutex); - buf[0] = bin2bcd(alarm->time.tm_sec); buf[1] = bin2bcd(alarm->time.tm_min); buf[2] = bin2bcd(alarm->time.tm_hour); @@ -267,7 +257,6 @@ static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control); } out: - mutex_unlock(&ds3232->mutex); return ret; } @@ -277,11 +266,9 @@ static int ds3232_update_alarm(struct device *dev, unsigned int enabled) int control; int ret; - mutex_lock(&ds3232->mutex); - ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control); if (ret) - goto unlock; + return ret; if (enabled) /* enable alarm1 interrupt */ @@ -291,9 +278,6 @@ static int ds3232_update_alarm(struct device *dev, unsigned int enabled) control &= ~(DS3232_REG_CR_A1IE); ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control); -unlock: - mutex_unlock(&ds3232->mutex); - return ret; } @@ -311,10 +295,11 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id) { struct device *dev = dev_id; struct ds3232 *ds3232 = dev_get_drvdata(dev); + struct mutex *lock = &ds3232->rtc->ops_lock; int ret; int stat, control; - mutex_lock(&ds3232->mutex); + mutex_lock(lock); ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat); if (ret) @@ -352,7 +337,7 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id) } unlock: - mutex_unlock(&ds3232->mutex); + mutex_unlock(lock); return IRQ_HANDLED; } @@ -380,8 +365,6 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, ds3232->dev = dev; dev_set_drvdata(dev, ds3232); - mutex_init(&ds3232->mutex); - ret = ds3232_check_rtc_status(dev); if (ret) return ret; -- cgit v1.2.3