From 7cdffeb534360609d57a39403ee951e08dcffbe7 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 27 Jan 2016 00:36:37 -0300 Subject: rtc: max77686: Fix max77686_rtc_read_alarm() return value The function is always returning zero even in case of failures since the ret value was not propagated to the callers. Fix the error path. Reported-by: Krzysztof Kozlowski Signed-off-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Acked-by: Laxman Dewangan Reviewed-by: Andi Shyti Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 7184a0e..6653c3d 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -235,7 +235,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) out: mutex_unlock(&info->lock); - return 0; + return ret; } static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) -- cgit v0.10.2 From 862f9453bd1494f10b059076a3c97c3b90d248aa Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 27 Jan 2016 00:36:38 -0300 Subject: rtc: max77686: Use ARRAY_SIZE() instead of current array length It is better to use the ARRAY_SIZE() macro instead of the array length to avoid bugs if the array is later changed and the length not updated. Signed-off-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Reviewed-by: Andi Shyti Acked-by: Laxman Dewangan Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 6653c3d..d84a50c 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -149,7 +149,7 @@ static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm) goto out; ret = regmap_bulk_read(info->max77686->rtc_regmap, - MAX77686_RTC_SEC, data, RTC_NR_TIME); + MAX77686_RTC_SEC, data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, ret); goto out; @@ -177,7 +177,7 @@ static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm) mutex_lock(&info->lock); ret = regmap_bulk_write(info->max77686->rtc_regmap, - MAX77686_RTC_SEC, data, RTC_NR_TIME); + MAX77686_RTC_SEC, data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__, ret); @@ -205,7 +205,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) goto out; ret = regmap_bulk_read(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + MAX77686_ALARM1_SEC, data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n", __func__, __LINE__, ret); @@ -215,7 +215,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) max77686_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); alrm->enabled = 0; - for (i = 0; i < RTC_NR_TIME; i++) { + for (i = 0; i < ARRAY_SIZE(data); i++) { if (data[i] & ALARM_ENABLE_MASK) { alrm->enabled = 1; break; @@ -252,7 +252,7 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) goto out; ret = regmap_bulk_read(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + MAX77686_ALARM1_SEC, data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", __func__, ret); @@ -261,11 +261,11 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode); - for (i = 0; i < RTC_NR_TIME; i++) + for (i = 0; i < ARRAY_SIZE(data); i++) data[i] &= ~ALARM_ENABLE_MASK; ret = regmap_bulk_write(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + MAX77686_ALARM1_SEC, data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", __func__, ret); @@ -291,7 +291,7 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) goto out; ret = regmap_bulk_read(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + MAX77686_ALARM1_SEC, data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", __func__, ret); @@ -312,7 +312,7 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); ret = regmap_bulk_write(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + MAX77686_ALARM1_SEC, data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", __func__, ret); @@ -341,7 +341,7 @@ static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) goto out; ret = regmap_bulk_write(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + MAX77686_ALARM1_SEC, data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", @@ -406,7 +406,8 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info) info->rtc_24hr_mode = 1; - ret = regmap_bulk_write(info->max77686->rtc_regmap, MAX77686_RTC_CONTROLM, data, 2); + ret = regmap_bulk_write(info->max77686->rtc_regmap, + MAX77686_RTC_CONTROLM, data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", __func__, ret); -- cgit v0.10.2 From 5981804b83650de558c40769fb06f76fab31724e Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 27 Jan 2016 00:36:39 -0300 Subject: rtc: max77686: Use usleep_range() instead of msleep() Documentation/timers/timers-howto.txt suggest to use usleep_range() instead of msleep() for small msec (1ms - 20ms) since msleep() will often sleep for 20ms for any value in that range. This is fine in this case since 16ms is the _minimum_ delay required by max77686 for an RTC update but by using usleep_range() instead of msleep(), the driver can support other RTC IP blocks with a shorter minimum delay (i.e: in the range of usecs instead of msecs). Signed-off-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Reviewed-by: Andi Shyti Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index d84a50c..025a17a 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -41,7 +41,7 @@ #define ALARM_ENABLE_SHIFT 7 #define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) -#define MAX77686_RTC_UPDATE_DELAY 16 +#define MAX77686_RTC_UPDATE_DELAY 16000 enum { RTC_SEC = 0, @@ -130,7 +130,8 @@ static int max77686_rtc_update(struct max77686_rtc_info *info, __func__, ret, data); else { /* Minimum 16ms delay required before RTC update. */ - msleep(MAX77686_RTC_UPDATE_DELAY); + usleep_range(MAX77686_RTC_UPDATE_DELAY, + MAX77686_RTC_UPDATE_DELAY * 2); } return ret; -- cgit v0.10.2 From 01ea01b35120663a8ec727566e757ea6efdbd2d1 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 27 Jan 2016 00:36:40 -0300 Subject: rtc: max77686: Use a driver data struct instead hard-coded values The driver has some hard-coded values such as the minimum delay needed before a RTC update or the mask used for the sec/min/hour/etc registers. Use a data structure that contains these values and pass as driver data using the platform device ID table for each device. This allows to make the driver's ops callbacks more generic so other RTC that are similar but don't have the same values can also be supported. Signed-off-by: Javier Martinez Canillas Acked-by: Laxman Dewangan Reviewed-by: Andi Shyti Tested-by: Krzysztof Kozlowski Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 025a17a..8c4ca35 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -41,8 +41,6 @@ #define ALARM_ENABLE_SHIFT 7 #define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) -#define MAX77686_RTC_UPDATE_DELAY 16000 - enum { RTC_SEC = 0, RTC_MIN, @@ -54,6 +52,13 @@ enum { RTC_NR_TIME }; +struct max77686_rtc_driver_data { + /* Minimum usecs needed for a RTC update */ + unsigned long delay; + /* Mask used to read RTC registers value */ + u8 mask; +}; + struct max77686_rtc_info { struct device *dev; struct max77686_dev *max77686; @@ -63,6 +68,8 @@ struct max77686_rtc_info { struct regmap *regmap; + const struct max77686_rtc_driver_data *drv_data; + int virq; int rtc_24hr_mode; }; @@ -72,12 +79,19 @@ enum MAX77686_RTC_OP { MAX77686_RTC_READ, }; +static const struct max77686_rtc_driver_data max77686_drv_data = { + .delay = 16000, + .mask = 0x7f, +}; + static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, - int rtc_24hr_mode) + struct max77686_rtc_info *info) { - tm->tm_sec = data[RTC_SEC] & 0x7f; - tm->tm_min = data[RTC_MIN] & 0x7f; - if (rtc_24hr_mode) + u8 mask = info->drv_data->mask; + + tm->tm_sec = data[RTC_SEC] & mask; + tm->tm_min = data[RTC_MIN] & mask; + if (info->rtc_24hr_mode) tm->tm_hour = data[RTC_HOUR] & 0x1f; else { tm->tm_hour = data[RTC_HOUR] & 0x0f; @@ -86,10 +100,10 @@ static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, } /* Only a single bit is set in data[], so fls() would be equivalent */ - tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0x7f) - 1; + tm->tm_wday = ffs(data[RTC_WEEKDAY] & mask) - 1; tm->tm_mday = data[RTC_DATE] & 0x1f; tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; - tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100; + tm->tm_year = (data[RTC_YEAR] & mask) + 100; tm->tm_yday = 0; tm->tm_isdst = 0; } @@ -117,6 +131,7 @@ static int max77686_rtc_update(struct max77686_rtc_info *info, { int ret; unsigned int data; + unsigned long delay = info->drv_data->delay; if (op == MAX77686_RTC_WRITE) data = 1 << RTC_UDR_SHIFT; @@ -129,9 +144,8 @@ static int max77686_rtc_update(struct max77686_rtc_info *info, dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n", __func__, ret, data); else { - /* Minimum 16ms delay required before RTC update. */ - usleep_range(MAX77686_RTC_UPDATE_DELAY, - MAX77686_RTC_UPDATE_DELAY * 2); + /* Minimum delay required before RTC update. */ + usleep_range(delay, delay * 2); } return ret; @@ -156,7 +170,7 @@ static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm) goto out; } - max77686_rtc_data_to_tm(data, tm, info->rtc_24hr_mode); + max77686_rtc_data_to_tm(data, tm, info); ret = rtc_valid_tm(tm); @@ -213,7 +227,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) goto out; } - max77686_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); + max77686_rtc_data_to_tm(data, &alrm->time, info); alrm->enabled = 0; for (i = 0; i < ARRAY_SIZE(data); i++) { @@ -260,7 +274,7 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) goto out; } - max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode); + max77686_rtc_data_to_tm(data, &tm, info); for (i = 0; i < ARRAY_SIZE(data); i++) data[i] &= ~ALARM_ENABLE_MASK; @@ -299,7 +313,7 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) goto out; } - max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode); + max77686_rtc_data_to_tm(data, &tm, info); data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT); data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT); @@ -307,7 +321,7 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; if (data[RTC_MONTH] & 0xf) data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT); - if (data[RTC_YEAR] & 0x7f) + if (data[RTC_YEAR] & info->drv_data->mask) data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT); if (data[RTC_DATE] & 0x1f) data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); @@ -423,6 +437,7 @@ static int max77686_rtc_probe(struct platform_device *pdev) { struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent); struct max77686_rtc_info *info; + const struct platform_device_id *id = platform_get_device_id(pdev); int ret; dev_info(&pdev->dev, "%s\n", __func__); @@ -436,6 +451,8 @@ static int max77686_rtc_probe(struct platform_device *pdev) info->dev = &pdev->dev; info->max77686 = max77686; info->rtc = max77686->rtc; + info->drv_data = (const struct max77686_rtc_driver_data *) + id->driver_data; platform_set_drvdata(pdev, info); @@ -510,7 +527,7 @@ static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops, max77686_rtc_suspend, max77686_rtc_resume); static const struct platform_device_id rtc_id[] = { - { "max77686-rtc", 0 }, + { "max77686-rtc", .driver_data = (kernel_ulong_t)&max77686_drv_data, }, {}, }; MODULE_DEVICE_TABLE(platform, rtc_id); -- cgit v0.10.2 From 90a5698a86ba968e6fbe2e03cfab9ffc18a17186 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 27 Jan 2016 00:36:41 -0300 Subject: rtc: max77686: Add an indirection level to access RTC registers The max77686 driver is generic enough that can be used for other Maxim RTC IP blocks but these might not have the same registers layout so instead of accessing the registers directly, add a map to translate offsets to the real registers addresses for each IP. Signed-off-by: Javier Martinez Canillas Acked-by: Laxman Dewangan Tested-by: Krzysztof Kozlowski Reviewed-by: Krzysztof Kozlowski Reviewed-by: Andi Shyti Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 8c4ca35..1f501b6 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -57,6 +57,8 @@ struct max77686_rtc_driver_data { unsigned long delay; /* Mask used to read RTC registers value */ u8 mask; + /* Registers offset to I2C addresses map */ + const unsigned int *map; }; struct max77686_rtc_info { @@ -79,9 +81,69 @@ enum MAX77686_RTC_OP { MAX77686_RTC_READ, }; +/* These are not registers but just offsets that are mapped to addresses */ +enum max77686_rtc_reg_offset { + REG_RTC_CONTROLM = 0, + REG_RTC_CONTROL, + REG_RTC_UPDATE0, + REG_WTSR_SMPL_CNTL, + REG_RTC_SEC, + REG_RTC_MIN, + REG_RTC_HOUR, + REG_RTC_WEEKDAY, + REG_RTC_MONTH, + REG_RTC_YEAR, + REG_RTC_DATE, + REG_ALARM1_SEC, + REG_ALARM1_MIN, + REG_ALARM1_HOUR, + REG_ALARM1_WEEKDAY, + REG_ALARM1_MONTH, + REG_ALARM1_YEAR, + REG_ALARM1_DATE, + REG_ALARM2_SEC, + REG_ALARM2_MIN, + REG_ALARM2_HOUR, + REG_ALARM2_WEEKDAY, + REG_ALARM2_MONTH, + REG_ALARM2_YEAR, + REG_ALARM2_DATE, + REG_RTC_END, +}; + +/* Maps RTC registers offset to the MAX77686 register addresses */ +static const unsigned int max77686_map[REG_RTC_END] = { + [REG_RTC_CONTROLM] = MAX77686_RTC_CONTROLM, + [REG_RTC_CONTROL] = MAX77686_RTC_CONTROL, + [REG_RTC_UPDATE0] = MAX77686_RTC_UPDATE0, + [REG_WTSR_SMPL_CNTL] = MAX77686_WTSR_SMPL_CNTL, + [REG_RTC_SEC] = MAX77686_RTC_SEC, + [REG_RTC_MIN] = MAX77686_RTC_MIN, + [REG_RTC_HOUR] = MAX77686_RTC_HOUR, + [REG_RTC_WEEKDAY] = MAX77686_RTC_WEEKDAY, + [REG_RTC_MONTH] = MAX77686_RTC_MONTH, + [REG_RTC_YEAR] = MAX77686_RTC_YEAR, + [REG_RTC_DATE] = MAX77686_RTC_DATE, + [REG_ALARM1_SEC] = MAX77686_ALARM1_SEC, + [REG_ALARM1_MIN] = MAX77686_ALARM1_MIN, + [REG_ALARM1_HOUR] = MAX77686_ALARM1_HOUR, + [REG_ALARM1_WEEKDAY] = MAX77686_ALARM1_WEEKDAY, + [REG_ALARM1_MONTH] = MAX77686_ALARM1_MONTH, + [REG_ALARM1_YEAR] = MAX77686_ALARM1_YEAR, + [REG_ALARM1_DATE] = MAX77686_ALARM1_DATE, + [REG_ALARM2_SEC] = MAX77686_ALARM2_SEC, + [REG_ALARM2_MIN] = MAX77686_ALARM2_MIN, + [REG_ALARM2_HOUR] = MAX77686_ALARM2_HOUR, + [REG_ALARM2_WEEKDAY] = MAX77686_ALARM2_WEEKDAY, + [REG_ALARM2_MONTH] = MAX77686_ALARM2_MONTH, + [REG_ALARM2_YEAR] = MAX77686_ALARM2_YEAR, + [REG_ALARM2_DATE] = MAX77686_ALARM2_DATE, +}; + static const struct max77686_rtc_driver_data max77686_drv_data = { .delay = 16000, .mask = 0x7f, + .map = max77686_map, }; static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, @@ -139,7 +201,8 @@ static int max77686_rtc_update(struct max77686_rtc_info *info, data = 1 << RTC_RBUDR_SHIFT; ret = regmap_update_bits(info->max77686->rtc_regmap, - MAX77686_RTC_UPDATE0, data, data); + info->drv_data->map[REG_RTC_UPDATE0], + data, data); if (ret < 0) dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n", __func__, ret, data); @@ -164,7 +227,8 @@ static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm) goto out; ret = regmap_bulk_read(info->max77686->rtc_regmap, - MAX77686_RTC_SEC, data, ARRAY_SIZE(data)); + info->drv_data->map[REG_RTC_SEC], + data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, ret); goto out; @@ -192,7 +256,8 @@ static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm) mutex_lock(&info->lock); ret = regmap_bulk_write(info->max77686->rtc_regmap, - MAX77686_RTC_SEC, data, ARRAY_SIZE(data)); + info->drv_data->map[REG_RTC_SEC], + data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__, ret); @@ -211,6 +276,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct max77686_rtc_info *info = dev_get_drvdata(dev); u8 data[RTC_NR_TIME]; unsigned int val; + const unsigned int *map = info->drv_data->map; int i, ret; mutex_lock(&info->lock); @@ -220,7 +286,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) goto out; ret = regmap_bulk_read(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, ARRAY_SIZE(data)); + map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n", __func__, __LINE__, ret); @@ -258,6 +324,7 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) u8 data[RTC_NR_TIME]; int ret, i; struct rtc_time tm; + const unsigned int *map = info->drv_data->map; if (!mutex_is_locked(&info->lock)) dev_warn(info->dev, "%s: should have mutex locked\n", __func__); @@ -267,7 +334,7 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) goto out; ret = regmap_bulk_read(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, ARRAY_SIZE(data)); + map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", __func__, ret); @@ -280,7 +347,7 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) data[i] &= ~ALARM_ENABLE_MASK; ret = regmap_bulk_write(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, ARRAY_SIZE(data)); + map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", __func__, ret); @@ -297,6 +364,7 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) u8 data[RTC_NR_TIME]; int ret; struct rtc_time tm; + const unsigned int *map = info->drv_data->map; if (!mutex_is_locked(&info->lock)) dev_warn(info->dev, "%s: should have mutex locked\n", __func__); @@ -306,7 +374,7 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) goto out; ret = regmap_bulk_read(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, ARRAY_SIZE(data)); + map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", __func__, ret); @@ -327,7 +395,7 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); ret = regmap_bulk_write(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, ARRAY_SIZE(data)); + map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", __func__, ret); @@ -356,7 +424,8 @@ static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) goto out; ret = regmap_bulk_write(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, ARRAY_SIZE(data)); + info->drv_data->map[REG_ALARM1_SEC], + data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", @@ -422,7 +491,8 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info) info->rtc_24hr_mode = 1; ret = regmap_bulk_write(info->max77686->rtc_regmap, - MAX77686_RTC_CONTROLM, data, ARRAY_SIZE(data)); + info->drv_data->map[REG_RTC_CONTROLM], + data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", __func__, ret); -- cgit v0.10.2 From f903129b86070befa996d7bdc53d0b82b1fa09d3 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 27 Jan 2016 00:36:42 -0300 Subject: rtc: max77686: Add max77802 support The MAX77686 and MAX77802 RTC IP blocks are very similar with only these differences: 0) The RTC registers layout and addresses are different. 1) The MAX77686 use 1 bit of the sec/min/hour/etc registers as the alarm enable while MAX77802 has a separate register for that. 2) The MAX77686 RTCYEAR register valid values range is 0..99 while for MAX77802 is 0..199. 3) The MAX77686 has a separate I2C address for the RTC registers while the MAX77802 uses the same I2C address as the PMIC regs. 5) The minimum delay before a RTC update (16 msecs vs 200 usecs). There are separate drivers for MAX77686 and MAX77802 RTC IP blocks but the differences are not that big so the driver can be extended to support both instead of duplicating a lot of code in 2 drivers. Suggested-by: Krzysztof Kozlowski Signed-off-by: Javier Martinez Canillas Acked-by: Laxman Dewangan Tested-by: Krzysztof Kozlowski Reviewed-by: Andi Shyti Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 1f501b6..a9a4ee0 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -1,5 +1,5 @@ /* - * RTC driver for Maxim MAX77686 + * RTC driver for Maxim MAX77686 and MAX77802 * * Copyright (C) 2012 Samsung Electronics Co.Ltd * @@ -41,6 +41,15 @@ #define ALARM_ENABLE_SHIFT 7 #define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) +#define REG_RTC_NONE 0xdeadbeef + +/* + * MAX77802 has separate register (RTCAE1) for alarm enable instead + * using 1 bit from registers RTC{SEC,MIN,HOUR,DAY,MONTH,YEAR,DATE} + * as in done in MAX77686. + */ +#define MAX77802_ALARM_ENABLE_VALUE 0x77 + enum { RTC_SEC = 0, RTC_MIN, @@ -59,6 +68,10 @@ struct max77686_rtc_driver_data { u8 mask; /* Registers offset to I2C addresses map */ const unsigned int *map; + /* Has a separate alarm enable register? */ + bool alarm_enable_reg; + /* Has a separate I2C regmap for the RTC? */ + bool separate_i2c_addr; }; struct max77686_rtc_info { @@ -108,6 +121,7 @@ enum max77686_rtc_reg_offset { REG_ALARM2_MONTH, REG_ALARM2_YEAR, REG_ALARM2_DATE, + REG_RTC_AE1, REG_RTC_END, }; @@ -138,12 +152,52 @@ static const unsigned int max77686_map[REG_RTC_END] = { [REG_ALARM2_MONTH] = MAX77686_ALARM2_MONTH, [REG_ALARM2_YEAR] = MAX77686_ALARM2_YEAR, [REG_ALARM2_DATE] = MAX77686_ALARM2_DATE, + [REG_RTC_AE1] = REG_RTC_NONE, }; static const struct max77686_rtc_driver_data max77686_drv_data = { .delay = 16000, .mask = 0x7f, .map = max77686_map, + .alarm_enable_reg = false, + .separate_i2c_addr = true, +}; + +static const unsigned int max77802_map[REG_RTC_END] = { + [REG_RTC_CONTROLM] = MAX77802_RTC_CONTROLM, + [REG_RTC_CONTROL] = MAX77802_RTC_CONTROL, + [REG_RTC_UPDATE0] = MAX77802_RTC_UPDATE0, + [REG_WTSR_SMPL_CNTL] = MAX77802_WTSR_SMPL_CNTL, + [REG_RTC_SEC] = MAX77802_RTC_SEC, + [REG_RTC_MIN] = MAX77802_RTC_MIN, + [REG_RTC_HOUR] = MAX77802_RTC_HOUR, + [REG_RTC_WEEKDAY] = MAX77802_RTC_WEEKDAY, + [REG_RTC_MONTH] = MAX77802_RTC_MONTH, + [REG_RTC_YEAR] = MAX77802_RTC_YEAR, + [REG_RTC_DATE] = MAX77802_RTC_DATE, + [REG_ALARM1_SEC] = MAX77802_ALARM1_SEC, + [REG_ALARM1_MIN] = MAX77802_ALARM1_MIN, + [REG_ALARM1_HOUR] = MAX77802_ALARM1_HOUR, + [REG_ALARM1_WEEKDAY] = MAX77802_ALARM1_WEEKDAY, + [REG_ALARM1_MONTH] = MAX77802_ALARM1_MONTH, + [REG_ALARM1_YEAR] = MAX77802_ALARM1_YEAR, + [REG_ALARM1_DATE] = MAX77802_ALARM1_DATE, + [REG_ALARM2_SEC] = MAX77802_ALARM2_SEC, + [REG_ALARM2_MIN] = MAX77802_ALARM2_MIN, + [REG_ALARM2_HOUR] = MAX77802_ALARM2_HOUR, + [REG_ALARM2_WEEKDAY] = MAX77802_ALARM2_WEEKDAY, + [REG_ALARM2_MONTH] = MAX77802_ALARM2_MONTH, + [REG_ALARM2_YEAR] = MAX77802_ALARM2_YEAR, + [REG_ALARM2_DATE] = MAX77802_ALARM2_DATE, + [REG_RTC_AE1] = MAX77802_RTC_AE1, +}; + +static const struct max77686_rtc_driver_data max77802_drv_data = { + .delay = 200, + .mask = 0xff, + .map = max77802_map, + .alarm_enable_reg = true, + .separate_i2c_addr = false, }; static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, @@ -165,12 +219,20 @@ static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, tm->tm_wday = ffs(data[RTC_WEEKDAY] & mask) - 1; tm->tm_mday = data[RTC_DATE] & 0x1f; tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; - tm->tm_year = (data[RTC_YEAR] & mask) + 100; + tm->tm_year = data[RTC_YEAR] & mask; tm->tm_yday = 0; tm->tm_isdst = 0; + + /* + * MAX77686 uses 1 bit from sec/min/hour/etc RTC registers and the + * year values are just 0..99 so add 100 to support up to 2099. + */ + if (!info->drv_data->alarm_enable_reg) + tm->tm_year += 100; } -static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data) +static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data, + struct max77686_rtc_info *info) { data[RTC_SEC] = tm->tm_sec; data[RTC_MIN] = tm->tm_min; @@ -178,6 +240,12 @@ static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data) data[RTC_WEEKDAY] = 1 << tm->tm_wday; data[RTC_DATE] = tm->tm_mday; data[RTC_MONTH] = tm->tm_mon + 1; + + if (info->drv_data->alarm_enable_reg) { + data[RTC_YEAR] = tm->tm_year; + return 0; + } + data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0; if (tm->tm_year < 100) { @@ -185,6 +253,7 @@ static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data) 1900 + tm->tm_year); return -EINVAL; } + return 0; } @@ -249,7 +318,7 @@ static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm) u8 data[RTC_NR_TIME]; int ret; - ret = max77686_rtc_tm_to_data(tm, data); + ret = max77686_rtc_tm_to_data(tm, data, info); if (ret < 0) return ret; @@ -296,10 +365,31 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) max77686_rtc_data_to_tm(data, &alrm->time, info); alrm->enabled = 0; - for (i = 0; i < ARRAY_SIZE(data); i++) { - if (data[i] & ALARM_ENABLE_MASK) { + + if (info->drv_data->alarm_enable_reg) { + if (map[REG_RTC_AE1] == REG_RTC_NONE) { + ret = -EINVAL; + dev_err(info->dev, + "alarm enable register not set(%d)\n", ret); + goto out; + } + + ret = regmap_read(info->max77686->regmap, + map[REG_RTC_AE1], &val); + if (ret < 0) { + dev_err(info->dev, + "fail to read alarm enable(%d)\n", ret); + goto out; + } + + if (val) alrm->enabled = 1; - break; + } else { + for (i = 0; i < ARRAY_SIZE(data); i++) { + if (data[i] & ALARM_ENABLE_MASK) { + alrm->enabled = 1; + break; + } } } @@ -333,21 +423,35 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) if (ret < 0) goto out; - ret = regmap_bulk_read(info->max77686->rtc_regmap, - map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); - if (ret < 0) { - dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", + if (info->drv_data->alarm_enable_reg) { + if (map[REG_RTC_AE1] == REG_RTC_NONE) { + ret = -EINVAL; + dev_err(info->dev, + "alarm enable register not set(%d)\n", ret); + goto out; + } + + ret = regmap_write(info->max77686->regmap, map[REG_RTC_AE1], 0); + } else { + ret = regmap_bulk_read(info->max77686->rtc_regmap, + map[REG_ALARM1_SEC], data, + ARRAY_SIZE(data)); + if (ret < 0) { + dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", __func__, ret); - goto out; - } + goto out; + } - max77686_rtc_data_to_tm(data, &tm, info); + max77686_rtc_data_to_tm(data, &tm, info); - for (i = 0; i < ARRAY_SIZE(data); i++) - data[i] &= ~ALARM_ENABLE_MASK; + for (i = 0; i < ARRAY_SIZE(data); i++) + data[i] &= ~ALARM_ENABLE_MASK; + + ret = regmap_bulk_write(info->max77686->rtc_regmap, + map[REG_ALARM1_SEC], data, + ARRAY_SIZE(data)); + } - ret = regmap_bulk_write(info->max77686->rtc_regmap, - map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", __func__, ret); @@ -373,29 +477,37 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) if (ret < 0) goto out; - ret = regmap_bulk_read(info->max77686->rtc_regmap, - map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); - if (ret < 0) { - dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", + if (info->drv_data->alarm_enable_reg) { + ret = regmap_write(info->max77686->regmap, map[REG_RTC_AE1], + MAX77802_ALARM_ENABLE_VALUE); + } else { + ret = regmap_bulk_read(info->max77686->rtc_regmap, + map[REG_ALARM1_SEC], data, + ARRAY_SIZE(data)); + if (ret < 0) { + dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", __func__, ret); - goto out; - } - - max77686_rtc_data_to_tm(data, &tm, info); + goto out; + } - data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT); - data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT); - data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT); - data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; - if (data[RTC_MONTH] & 0xf) - data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT); - if (data[RTC_YEAR] & info->drv_data->mask) - data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT); - if (data[RTC_DATE] & 0x1f) - data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); + max77686_rtc_data_to_tm(data, &tm, info); + + data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; + if (data[RTC_MONTH] & 0xf) + data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT); + if (data[RTC_YEAR] & info->drv_data->mask) + data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT); + if (data[RTC_DATE] & 0x1f) + data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); + + ret = regmap_bulk_write(info->max77686->rtc_regmap, + map[REG_ALARM1_SEC], data, + ARRAY_SIZE(data)); + } - ret = regmap_bulk_write(info->max77686->rtc_regmap, - map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", __func__, ret); @@ -413,7 +525,7 @@ static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) u8 data[RTC_NR_TIME]; int ret; - ret = max77686_rtc_tm_to_data(&alrm->time, data); + ret = max77686_rtc_tm_to_data(&alrm->time, data, info); if (ret < 0) return ret; @@ -524,6 +636,9 @@ static int max77686_rtc_probe(struct platform_device *pdev) info->drv_data = (const struct max77686_rtc_driver_data *) id->driver_data; + if (!info->drv_data->separate_i2c_addr) + info->max77686->rtc_regmap = info->max77686->regmap; + platform_set_drvdata(pdev, info); ret = max77686_rtc_init_reg(info); @@ -535,7 +650,7 @@ static int max77686_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); - info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77686-rtc", + info->rtc_dev = devm_rtc_device_register(&pdev->dev, id->name, &max77686_rtc_ops, THIS_MODULE); if (IS_ERR(info->rtc_dev)) { @@ -598,6 +713,7 @@ static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops, static const struct platform_device_id rtc_id[] = { { "max77686-rtc", .driver_data = (kernel_ulong_t)&max77686_drv_data, }, + { "max77802-rtc", .driver_data = (kernel_ulong_t)&max77802_drv_data, }, {}, }; MODULE_DEVICE_TABLE(platform, rtc_id); -- cgit v0.10.2 From 1e5813bded3c6702841549ac2533680f410aea43 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 27 Jan 2016 00:36:43 -0300 Subject: rtc: max77686: Fix unsupported year message The max77686 RTC only supports a range of 99 years so instead of using year 1900 as the base, the year 2000 is used. This means that 1900 to 1999 are unsupported years. The driver was printing a warning for those values but was returning a error so for consistency, print an error message instead and don't say that a year 2000 is assumed, since the year is not set. Also, it is better to use dev_* log functions instead of pr_* to print information about the device in the kernel log in a standardized way. This also allows to remove the local pr_fmt() defined macro. Suggested-by: Krzysztof Kozlowski Signed-off-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski Reviewed-by: Andi Shyti Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index a9a4ee0..bbb06dd 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -12,8 +12,6 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include @@ -249,7 +247,7 @@ static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data, data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0; if (tm->tm_year < 100) { - pr_warn("RTC cannot handle the year %d. Assume it's 2000.\n", + dev_err(info->dev, "RTC cannot handle the year %d.\n", 1900 + tm->tm_year); return -EINVAL; } -- cgit v0.10.2 From fb166ba1d7f0a662f7332f4ff660a0d6f4d76915 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 4 Feb 2016 09:26:35 +0900 Subject: rtc: max77686: Properly handle regmap_irq_get_virq() error code The regmap_irq_get_virq() can return 0 or -EINVAL in error conditions but driver checked only for value of 0. This could lead to a cast of -EINVAL to an unsigned int used as a interrupt number for devm_request_threaded_irq(). Although this is not yet fatal (devm_request_threaded_irq() will just fail with -EINVAL) but might be a misleading when diagnosing errors. Signed-off-by: Krzysztof Kozlowski Fixes: 6f1c1e71d933 ("mfd: max77686: Convert to use regmap_irq") Reviewed-by: Javier Martinez Canillas Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index bbb06dd..d2d1176 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -667,7 +667,7 @@ static int max77686_rtc_probe(struct platform_device *pdev) info->virq = regmap_irq_get_virq(max77686->rtc_irq_data, MAX77686_RTCIRQ_RTCA1); - if (!info->virq) { + if (info->virq <= 0) { ret = -ENXIO; goto err_rtc; } -- cgit v0.10.2 From cd0e7c1e54af2dd4d275177cb5dea0ced398e5ef Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 27 Jan 2016 00:36:44 -0300 Subject: rtc: Remove Maxim 77802 driver The max77686 RTC driver now supports the max77802 RTC as well so there's no need to have a separate driver anymore. Signed-off-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski Acked-by: Laxman Dewangan Reviewed-by: Andi Shyti Tested-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 376322f..ef456d3 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -335,16 +335,6 @@ config RTC_DRV_RK808 This driver can also be built as a module. If so, the module will be called rk808-rtc. -config RTC_DRV_MAX77802 - tristate "Maxim 77802 RTC" - depends on MFD_MAX77686 - help - If you say yes here you will get support for the - RTC of Maxim MAX77802 PMIC. - - This driver can also be built as a module. If so, the module - will be called rtc-max77802. - config RTC_DRV_RS5C372 tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 62d61b2..ed4519e 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -86,7 +86,6 @@ obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o -obj-$(CONFIG_RTC_DRV_MAX77802) += rtc-max77802.o obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o diff --git a/drivers/rtc/rtc-max77802.c b/drivers/rtc/rtc-max77802.c deleted file mode 100644 index 82ffcc5..0000000 --- a/drivers/rtc/rtc-max77802.c +++ /dev/null @@ -1,502 +0,0 @@ -/* - * RTC driver for Maxim MAX77802 - * - * Copyright (C) 2013 Google, Inc - * - * Copyright (C) 2012 Samsung Electronics Co.Ltd - * - * based on rtc-max8997.c - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* RTC Control Register */ -#define BCD_EN_SHIFT 0 -#define BCD_EN_MASK (1 << BCD_EN_SHIFT) -#define MODEL24_SHIFT 1 -#define MODEL24_MASK (1 << MODEL24_SHIFT) -/* RTC Update Register1 */ -#define RTC_UDR_SHIFT 0 -#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) -#define RTC_RBUDR_SHIFT 4 -#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT) -/* RTC Hour register */ -#define HOUR_PM_SHIFT 6 -#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT) -/* RTC Alarm Enable */ -#define ALARM_ENABLE_SHIFT 7 -#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) - -/* For the RTCAE1 register, we write this value to enable the alarm */ -#define ALARM_ENABLE_VALUE 0x77 - -#define MAX77802_RTC_UPDATE_DELAY_US 200 - -enum { - RTC_SEC = 0, - RTC_MIN, - RTC_HOUR, - RTC_WEEKDAY, - RTC_MONTH, - RTC_YEAR, - RTC_DATE, - RTC_NR_TIME -}; - -struct max77802_rtc_info { - struct device *dev; - struct max77686_dev *max77802; - struct i2c_client *rtc; - struct rtc_device *rtc_dev; - struct mutex lock; - - struct regmap *regmap; - - int virq; - int rtc_24hr_mode; -}; - -enum MAX77802_RTC_OP { - MAX77802_RTC_WRITE, - MAX77802_RTC_READ, -}; - -static void max77802_rtc_data_to_tm(u8 *data, struct rtc_time *tm, - int rtc_24hr_mode) -{ - tm->tm_sec = data[RTC_SEC] & 0xff; - tm->tm_min = data[RTC_MIN] & 0xff; - if (rtc_24hr_mode) - tm->tm_hour = data[RTC_HOUR] & 0x1f; - else { - tm->tm_hour = data[RTC_HOUR] & 0x0f; - if (data[RTC_HOUR] & HOUR_PM_MASK) - tm->tm_hour += 12; - } - - /* Only a single bit is set in data[], so fls() would be equivalent */ - tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0xff) - 1; - tm->tm_mday = data[RTC_DATE] & 0x1f; - tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; - - tm->tm_year = data[RTC_YEAR] & 0xff; - tm->tm_yday = 0; - tm->tm_isdst = 0; -} - -static int max77802_rtc_tm_to_data(struct rtc_time *tm, u8 *data) -{ - data[RTC_SEC] = tm->tm_sec; - data[RTC_MIN] = tm->tm_min; - data[RTC_HOUR] = tm->tm_hour; - data[RTC_WEEKDAY] = 1 << tm->tm_wday; - data[RTC_DATE] = tm->tm_mday; - data[RTC_MONTH] = tm->tm_mon + 1; - data[RTC_YEAR] = tm->tm_year; - - return 0; -} - -static int max77802_rtc_update(struct max77802_rtc_info *info, - enum MAX77802_RTC_OP op) -{ - int ret; - unsigned int data; - - if (op == MAX77802_RTC_WRITE) - data = 1 << RTC_UDR_SHIFT; - else - data = 1 << RTC_RBUDR_SHIFT; - - ret = regmap_update_bits(info->max77802->regmap, - MAX77802_RTC_UPDATE0, data, data); - if (ret < 0) - dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n", - __func__, ret, data); - else { - /* Minimum delay required before RTC update. */ - usleep_range(MAX77802_RTC_UPDATE_DELAY_US, - MAX77802_RTC_UPDATE_DELAY_US * 2); - } - - return ret; -} - -static int max77802_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - struct max77802_rtc_info *info = dev_get_drvdata(dev); - u8 data[RTC_NR_TIME]; - int ret; - - mutex_lock(&info->lock); - - ret = max77802_rtc_update(info, MAX77802_RTC_READ); - if (ret < 0) - goto out; - - ret = regmap_bulk_read(info->max77802->regmap, - MAX77802_RTC_SEC, data, RTC_NR_TIME); - if (ret < 0) { - dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, - ret); - goto out; - } - - max77802_rtc_data_to_tm(data, tm, info->rtc_24hr_mode); - - ret = rtc_valid_tm(tm); - -out: - mutex_unlock(&info->lock); - return ret; -} - -static int max77802_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - struct max77802_rtc_info *info = dev_get_drvdata(dev); - u8 data[RTC_NR_TIME]; - int ret; - - ret = max77802_rtc_tm_to_data(tm, data); - if (ret < 0) - return ret; - - mutex_lock(&info->lock); - - ret = regmap_bulk_write(info->max77802->regmap, - MAX77802_RTC_SEC, data, RTC_NR_TIME); - if (ret < 0) { - dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__, - ret); - goto out; - } - - ret = max77802_rtc_update(info, MAX77802_RTC_WRITE); - -out: - mutex_unlock(&info->lock); - return ret; -} - -static int max77802_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) -{ - struct max77802_rtc_info *info = dev_get_drvdata(dev); - u8 data[RTC_NR_TIME]; - unsigned int val; - int ret; - - mutex_lock(&info->lock); - - ret = max77802_rtc_update(info, MAX77802_RTC_READ); - if (ret < 0) - goto out; - - ret = regmap_bulk_read(info->max77802->regmap, - MAX77802_ALARM1_SEC, data, RTC_NR_TIME); - if (ret < 0) { - dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n", - __func__, __LINE__, ret); - goto out; - } - - max77802_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); - - alrm->enabled = 0; - ret = regmap_read(info->max77802->regmap, - MAX77802_RTC_AE1, &val); - if (ret < 0) { - dev_err(info->dev, "%s:%d fail to read alarm enable(%d)\n", - __func__, __LINE__, ret); - goto out; - } - if (val) - alrm->enabled = 1; - - alrm->pending = 0; - ret = regmap_read(info->max77802->regmap, MAX77802_REG_STATUS2, &val); - if (ret < 0) { - dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n", - __func__, __LINE__, ret); - goto out; - } - - if (val & (1 << 2)) /* RTCA1 */ - alrm->pending = 1; - -out: - mutex_unlock(&info->lock); - return 0; -} - -static int max77802_rtc_stop_alarm(struct max77802_rtc_info *info) -{ - int ret; - - if (!mutex_is_locked(&info->lock)) - dev_warn(info->dev, "%s: should have mutex locked\n", __func__); - - ret = max77802_rtc_update(info, MAX77802_RTC_READ); - if (ret < 0) - goto out; - - ret = regmap_write(info->max77802->regmap, - MAX77802_RTC_AE1, 0); - if (ret < 0) { - dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", - __func__, ret); - goto out; - } - - ret = max77802_rtc_update(info, MAX77802_RTC_WRITE); -out: - return ret; -} - -static int max77802_rtc_start_alarm(struct max77802_rtc_info *info) -{ - int ret; - - if (!mutex_is_locked(&info->lock)) - dev_warn(info->dev, "%s: should have mutex locked\n", - __func__); - - ret = max77802_rtc_update(info, MAX77802_RTC_READ); - if (ret < 0) - goto out; - - ret = regmap_write(info->max77802->regmap, - MAX77802_RTC_AE1, - ALARM_ENABLE_VALUE); - - if (ret < 0) { - dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", - __func__, ret); - goto out; - } - - ret = max77802_rtc_update(info, MAX77802_RTC_WRITE); -out: - return ret; -} - -static int max77802_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) -{ - struct max77802_rtc_info *info = dev_get_drvdata(dev); - u8 data[RTC_NR_TIME]; - int ret; - - ret = max77802_rtc_tm_to_data(&alrm->time, data); - if (ret < 0) - return ret; - - mutex_lock(&info->lock); - - ret = max77802_rtc_stop_alarm(info); - if (ret < 0) - goto out; - - ret = regmap_bulk_write(info->max77802->regmap, - MAX77802_ALARM1_SEC, data, RTC_NR_TIME); - - if (ret < 0) { - dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", - __func__, ret); - goto out; - } - - ret = max77802_rtc_update(info, MAX77802_RTC_WRITE); - if (ret < 0) - goto out; - - if (alrm->enabled) - ret = max77802_rtc_start_alarm(info); -out: - mutex_unlock(&info->lock); - return ret; -} - -static int max77802_rtc_alarm_irq_enable(struct device *dev, - unsigned int enabled) -{ - struct max77802_rtc_info *info = dev_get_drvdata(dev); - int ret; - - mutex_lock(&info->lock); - if (enabled) - ret = max77802_rtc_start_alarm(info); - else - ret = max77802_rtc_stop_alarm(info); - mutex_unlock(&info->lock); - - return ret; -} - -static irqreturn_t max77802_rtc_alarm_irq(int irq, void *data) -{ - struct max77802_rtc_info *info = data; - - dev_dbg(info->dev, "%s:irq(%d)\n", __func__, irq); - - rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); - - return IRQ_HANDLED; -} - -static const struct rtc_class_ops max77802_rtc_ops = { - .read_time = max77802_rtc_read_time, - .set_time = max77802_rtc_set_time, - .read_alarm = max77802_rtc_read_alarm, - .set_alarm = max77802_rtc_set_alarm, - .alarm_irq_enable = max77802_rtc_alarm_irq_enable, -}; - -static int max77802_rtc_init_reg(struct max77802_rtc_info *info) -{ - u8 data[2]; - int ret; - - max77802_rtc_update(info, MAX77802_RTC_READ); - - /* Set RTC control register : Binary mode, 24hour mdoe */ - data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); - data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); - - info->rtc_24hr_mode = 1; - - ret = regmap_bulk_write(info->max77802->regmap, - MAX77802_RTC_CONTROLM, data, ARRAY_SIZE(data)); - if (ret < 0) { - dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", - __func__, ret); - return ret; - } - - ret = max77802_rtc_update(info, MAX77802_RTC_WRITE); - return ret; -} - -static int max77802_rtc_probe(struct platform_device *pdev) -{ - struct max77686_dev *max77802 = dev_get_drvdata(pdev->dev.parent); - struct max77802_rtc_info *info; - int ret; - - dev_dbg(&pdev->dev, "%s\n", __func__); - - info = devm_kzalloc(&pdev->dev, sizeof(struct max77802_rtc_info), - GFP_KERNEL); - if (!info) - return -ENOMEM; - - mutex_init(&info->lock); - info->dev = &pdev->dev; - info->max77802 = max77802; - info->rtc = max77802->i2c; - - platform_set_drvdata(pdev, info); - - ret = max77802_rtc_init_reg(info); - - if (ret < 0) { - dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret); - return ret; - } - - device_init_wakeup(&pdev->dev, 1); - - info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77802-rtc", - &max77802_rtc_ops, THIS_MODULE); - - if (IS_ERR(info->rtc_dev)) { - ret = PTR_ERR(info->rtc_dev); - dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); - if (ret == 0) - ret = -EINVAL; - return ret; - } - - if (!max77802->rtc_irq_data) { - dev_err(&pdev->dev, "No RTC regmap IRQ chip\n"); - return -EINVAL; - } - - info->virq = regmap_irq_get_virq(max77802->rtc_irq_data, - MAX77686_RTCIRQ_RTCA1); - - if (info->virq <= 0) { - dev_err(&pdev->dev, "Failed to get virtual IRQ %d\n", - MAX77686_RTCIRQ_RTCA1); - return -EINVAL; - } - - ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL, - max77802_rtc_alarm_irq, 0, "rtc-alarm1", - info); - if (ret < 0) - dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", - info->virq, ret); - - return ret; -} - -#ifdef CONFIG_PM_SLEEP -static int max77802_rtc_suspend(struct device *dev) -{ - if (device_may_wakeup(dev)) { - struct max77802_rtc_info *info = dev_get_drvdata(dev); - - return enable_irq_wake(info->virq); - } - - return 0; -} - -static int max77802_rtc_resume(struct device *dev) -{ - if (device_may_wakeup(dev)) { - struct max77802_rtc_info *info = dev_get_drvdata(dev); - - return disable_irq_wake(info->virq); - } - - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(max77802_rtc_pm_ops, - max77802_rtc_suspend, max77802_rtc_resume); - -static const struct platform_device_id rtc_id[] = { - { "max77802-rtc", 0 }, - {}, -}; -MODULE_DEVICE_TABLE(platform, rtc_id); - -static struct platform_driver max77802_rtc_driver = { - .driver = { - .name = "max77802-rtc", - .pm = &max77802_rtc_pm_ops, - }, - .probe = max77802_rtc_probe, - .id_table = rtc_id, -}; - -module_platform_driver(max77802_rtc_driver); - -MODULE_DESCRIPTION("Maxim MAX77802 RTC driver"); -MODULE_AUTHOR("Simon Glass "); -MODULE_LICENSE("GPL"); -- cgit v0.10.2 From bf035f42344a3e790c2d37ed3ee9005311f98075 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 27 Jan 2016 15:46:11 +0900 Subject: rtc: max77686: Cleanup and reduce dmesg output Cleanup of entire driver of its dmesg output: 1. Remove printing of the function name, because printing device name is sufficient. This also makes the dev_err()-like functions more compact and readable (not need of line break). 2. Lower from info to debug printing of each RTC interrupt (no need to make noise on each alarm). 3. Remove dev_info() at beginning of probe because a message is already always printed by either probe failure or from registering the RTC device as /dev/rtcX. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Javier Martinez Canillas Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index d2d1176..0f2965d 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -271,8 +271,8 @@ static int max77686_rtc_update(struct max77686_rtc_info *info, info->drv_data->map[REG_RTC_UPDATE0], data, data); if (ret < 0) - dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n", - __func__, ret, data); + dev_err(info->dev, "Fail to write update reg(ret=%d, data=0x%x)\n", + ret, data); else { /* Minimum delay required before RTC update. */ usleep_range(delay, delay * 2); @@ -297,7 +297,7 @@ static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm) info->drv_data->map[REG_RTC_SEC], data, ARRAY_SIZE(data)); if (ret < 0) { - dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, ret); + dev_err(info->dev, "Fail to read time reg(%d)\n", ret); goto out; } @@ -326,8 +326,7 @@ static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm) info->drv_data->map[REG_RTC_SEC], data, ARRAY_SIZE(data)); if (ret < 0) { - dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__, - ret); + dev_err(info->dev, "Fail to write time reg(%d)\n", ret); goto out; } @@ -355,8 +354,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) ret = regmap_bulk_read(info->max77686->rtc_regmap, map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); if (ret < 0) { - dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n", - __func__, __LINE__, ret); + dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret); goto out; } @@ -394,8 +392,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->pending = 0; ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS2, &val); if (ret < 0) { - dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n", - __func__, __LINE__, ret); + dev_err(info->dev, "Fail to read status2 reg(%d)\n", ret); goto out; } @@ -435,8 +432,7 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); if (ret < 0) { - dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", - __func__, ret); + dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret); goto out; } @@ -451,8 +447,7 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) } if (ret < 0) { - dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", - __func__, ret); + dev_err(info->dev, "Fail to write alarm reg(%d)\n", ret); goto out; } @@ -483,8 +478,7 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); if (ret < 0) { - dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", - __func__, ret); + dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret); goto out; } @@ -507,8 +501,7 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) } if (ret < 0) { - dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", - __func__, ret); + dev_err(info->dev, "Fail to write alarm reg(%d)\n", ret); goto out; } @@ -538,8 +531,7 @@ static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) data, ARRAY_SIZE(data)); if (ret < 0) { - dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", - __func__, ret); + dev_err(info->dev, "Fail to write alarm reg(%d)\n", ret); goto out; } @@ -574,7 +566,7 @@ static irqreturn_t max77686_rtc_alarm_irq(int irq, void *data) { struct max77686_rtc_info *info = data; - dev_info(info->dev, "%s:irq(%d)\n", __func__, irq); + dev_dbg(info->dev, "RTC alarm IRQ: %d\n", irq); rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); @@ -604,8 +596,7 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info) info->drv_data->map[REG_RTC_CONTROLM], data, ARRAY_SIZE(data)); if (ret < 0) { - dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", - __func__, ret); + dev_err(info->dev, "Fail to write controlm reg(%d)\n", ret); return ret; } @@ -620,8 +611,6 @@ static int max77686_rtc_probe(struct platform_device *pdev) const struct platform_device_id *id = platform_get_device_id(pdev); int ret; - dev_info(&pdev->dev, "%s\n", __func__); - info = devm_kzalloc(&pdev->dev, sizeof(struct max77686_rtc_info), GFP_KERNEL); if (!info) @@ -661,7 +650,7 @@ static int max77686_rtc_probe(struct platform_device *pdev) if (!max77686->rtc_irq_data) { ret = -EINVAL; - dev_err(&pdev->dev, "%s: no RTC regmap IRQ chip\n", __func__); + dev_err(&pdev->dev, "No RTC regmap IRQ chip\n"); goto err_rtc; } -- cgit v0.10.2 From 54dd1c4c2979d1ad127d0e615fdd0f5016a5d713 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Wed, 23 Dec 2015 20:54:33 +0800 Subject: rtc: ds1305: use to_spi_device and kobj_to_dev For better readability, use to_spi_device() and kobj_to_dev() instead of container_of(). Signed-off-by: Geliang Tang Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index f39691e..8e41c46 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -532,7 +532,7 @@ ds1305_nvram_read(struct file *filp, struct kobject *kobj, struct spi_transfer x[2]; int status; - spi = container_of(kobj, struct spi_device, dev.kobj); + spi = to_spi_device(kobj_to_dev(kobj)); addr = DS1305_NVRAM + off; msg_init(&m, x, &addr, count, NULL, buf); @@ -554,7 +554,7 @@ ds1305_nvram_write(struct file *filp, struct kobject *kobj, struct spi_transfer x[2]; int status; - spi = container_of(kobj, struct spi_device, dev.kobj); + spi = to_spi_device(kobj_to_dev(kobj)); addr = (DS1305_WRITE | DS1305_NVRAM) + off; msg_init(&m, x, &addr, count, buf, NULL); -- cgit v0.10.2 From aaa3cee5deffa28415a6e1852c5afae0f5d210e2 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 21 Jan 2016 13:24:21 +0100 Subject: rtc: rx8025: remove rv8803 id The rv8803 has its own driver that should be used. Remove its id from the rx8025 driver. Fixes: b1f9d790b59dc04f8813a49a92ddd8651770ffee Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index bd911ba..17341fe 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -65,7 +65,6 @@ static const struct i2c_device_id rx8025_id[] = { { "rx8025", 0 }, - { "rv8803", 1 }, { } }; MODULE_DEVICE_TABLE(i2c, rx8025_id); -- cgit v0.10.2 From 04d3ba70a3c9c9ba593d3208531463c65f055526 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 25 Jan 2016 17:04:46 +0100 Subject: rtc: mt6397: add IRQ domain dependency The mt6397 RTC driver can be built either when the MFD_MT6397 driver is enabled (which selects IRQ_DOMAIN), or when compile testing. The latter however fails without IRQ domains: drivers/rtc/rtc-mt6397.c: In function 'mtk_rtc_probe': drivers/rtc/rtc-mt6397.c:326:13: error: implicit declaration of function 'irq_create_mapping' [-Werror=implicit-function-declaration] rtc->irq = irq_create_mapping(mt6397_chip->irq_domain, res->start); This adds an explicit dependency for the COMPILE_TEST case. Signed-off-by: Arnd Bergmann Acked-by: Eddie Huang Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index ef456d3..27f6ac4 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1593,7 +1593,7 @@ config RTC_DRV_MOXART config RTC_DRV_MT6397 tristate "Mediatek Real Time Clock driver" - depends on MFD_MT6397 || COMPILE_TEST + depends on MFD_MT6397 || (COMPILE_TEST && IRQ_DOMAIN) help This selects the Mediatek(R) RTC driver. RTC is part of Mediatek MT6397 PMIC. You should enable MT6397 PMIC MFD before select -- cgit v0.10.2 From 8bc2a40730ec74271a0573a6882871308d069f5d Mon Sep 17 00:00:00 2001 From: Michael Lange Date: Thu, 21 Jan 2016 18:10:16 +0100 Subject: rtc: ds1307: add support for the DT property 'wakeup-source' For RTC chips with no IRQ directly connected to the SoC, the RTC chip can be forced as a wakeup source by stating that explicitly in the device's .dts file using the "wakeup-source" boolean property. This will guarantee the 'wakealarm' sysfs entry is available on the device, if supported by the RTC. With these changes to the driver rtc-ds1307 and the necessary entries in the .dts file, I get an working ds1337 RTC on the Witty Pi extension board by UUGear for the Raspberry Pi. An example for the entry in the .dts file: rtc: ds1337@68 { compatible = "dallas,ds1337"; reg = <0x68>; wakeup-source; If the "wakeup-source" property is set, do not request an IRQ. Set also UIE mode to unsupported, to get a working 'hwclock' binary. Signed-off-by: Michael Lange Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index cf685f6..bfedeb5 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -851,6 +851,7 @@ static int ds1307_probe(struct i2c_client *client, struct chip_desc *chip = &chips[id->driver_data]; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); bool want_irq = false; + bool ds1307_can_wakeup_device = false; unsigned char *buf; struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev); irq_handler_t irq_handler = ds1307_irq; @@ -898,6 +899,20 @@ static int ds1307_probe(struct i2c_client *client, ds1307->write_block_data = ds1307_write_block_data; } +#ifdef CONFIG_OF +/* + * For devices with no IRQ directly connected to the SoC, the RTC chip + * can be forced as a wakeup source by stating that explicitly in + * the device's .dts file using the "wakeup-source" boolean property. + * If the "wakeup-source" property is set, don't request an IRQ. + * This will guarantee the 'wakealarm' sysfs entry is available on the device, + * if supported by the RTC. + */ + if (of_property_read_bool(client->dev.of_node, "wakeup-source")) { + ds1307_can_wakeup_device = true; + } +#endif + switch (ds1307->type) { case ds_1337: case ds_1339: @@ -916,11 +931,13 @@ static int ds1307_probe(struct i2c_client *client, ds1307->regs[0] &= ~DS1337_BIT_nEOSC; /* - * Using IRQ? Disable the square wave and both alarms. + * Using IRQ or defined as wakeup-source? + * Disable the square wave and both alarms. * For some variants, be sure alarms can trigger when we're * running on Vbackup (BBSQI/BBSQW) */ - if (ds1307->client->irq > 0 && chip->alarm) { + if (chip->alarm && (ds1307->client->irq > 0 || + ds1307_can_wakeup_device)) { ds1307->regs[0] |= DS1337_BIT_INTCN | bbsqi_bitpos[ds1307->type]; ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE); @@ -1135,6 +1152,14 @@ read_rtc: return PTR_ERR(ds1307->rtc); } + if (ds1307_can_wakeup_device) { + /* Disable request for an IRQ */ + want_irq = false; + dev_info(&client->dev, "'wakeup-source' is set, request for an IRQ is disabled!\n"); + /* We cannot support UIE mode if we do not have an IRQ line */ + ds1307->rtc->uie_unsupported = 1; + } + if (want_irq) { err = devm_request_threaded_irq(&client->dev, client->irq, NULL, irq_handler, -- cgit v0.10.2 From 445c02076f1e60d2ee51503bf1288ef9f3bc8809 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 25 Jan 2016 00:22:16 +0900 Subject: rtc: ds1307: add temperature sensor support for ds3231 DS3231 has the temperature registers with a resolution of 0.25 degree celsius. This enables to get the value through hwmon. # cat /sys/class/i2c-adapter/i2c-2/2-0068/hwmon/hwmon0/temp1_input 21000 Signed-off-by: Akinobu Mita Acked-by: Guenter Roeck Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 27f6ac4..d47ad96 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -212,6 +212,15 @@ config RTC_DRV_DS1307 This driver can also be built as a module. If so, the module will be called rtc-ds1307. +config RTC_DRV_DS1307_HWMON + bool "HWMON support for rtc-ds1307" + depends on RTC_DRV_DS1307 && HWMON + depends on !(RTC_DRV_DS1307=y && HWMON=m) + default y + help + Say Y here if you want to expose temperature sensor data on + rtc-ds1307 (only DS3231) + config RTC_DRV_DS1374 tristate "Dallas/Maxim DS1374" help diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index bfedeb5..2462d5a 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include /* * We can't determine type by probing, but if we expect pre-Linux code @@ -842,6 +844,90 @@ out: return; } +/*----------------------------------------------------------------------*/ + +#ifdef CONFIG_RTC_DRV_DS1307_HWMON + +/* + * Temperature sensor support for ds3231 devices. + */ + +#define DS3231_REG_TEMPERATURE 0x11 + +/* + * A user-initiated temperature conversion is not started by this function, + * so the temperature is updated once every 64 seconds. + */ +static int ds3231_hwmon_read_temp(struct device *dev, s16 *mC) +{ + struct ds1307 *ds1307 = dev_get_drvdata(dev); + u8 temp_buf[2]; + s16 temp; + int ret; + + ret = ds1307->read_block_data(ds1307->client, DS3231_REG_TEMPERATURE, + sizeof(temp_buf), temp_buf); + if (ret < 0) + return ret; + if (ret != sizeof(temp_buf)) + return -EIO; + + /* + * Temperature is represented as a 10-bit code with a resolution of + * 0.25 degree celsius and encoded in two's complement format. + */ + temp = (temp_buf[0] << 8) | temp_buf[1]; + temp >>= 6; + *mC = temp * 250; + + return 0; +} + +static ssize_t ds3231_hwmon_show_temp(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + s16 temp; + + ret = ds3231_hwmon_read_temp(dev, &temp); + if (ret) + return ret; + + return sprintf(buf, "%d\n", temp); +} +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ds3231_hwmon_show_temp, + NULL, 0); + +static struct attribute *ds3231_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(ds3231_hwmon); + +static void ds1307_hwmon_register(struct ds1307 *ds1307) +{ + struct device *dev; + + if (ds1307->type != ds_3231) + return; + + dev = devm_hwmon_device_register_with_groups(&ds1307->client->dev, + ds1307->client->name, + ds1307, ds3231_hwmon_groups); + if (IS_ERR(dev)) { + dev_warn(&ds1307->client->dev, + "unable to register hwmon device %ld\n", PTR_ERR(dev)); + } +} + +#else + +static void ds1307_hwmon_register(struct ds1307 *ds1307) +{ +} + +#endif + static int ds1307_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1207,6 +1293,8 @@ read_rtc: } } + ds1307_hwmon_register(ds1307); + return 0; exit: -- cgit v0.10.2 From 245cb74be649ada355ca68f1cc9cfec519aae612 Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Mon, 4 Jan 2016 10:31:19 -0800 Subject: rtc: pcf2123: define registers and bit macros Add defines for all 16 registers in the pcf2123. Add defines for useful bits from several registers I've tried to document all the registers, and as best as possible, all the special bits they employ Use BIT() wherever possible in the bit definitions Signed-off-by: Joshua Clayton Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index ea8a31c..be3ec83 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -48,6 +48,7 @@ #define DRV_VERSION "0.6" +/* REGISTERS */ #define PCF2123_REG_CTRL1 (0x00) /* Control Register 1 */ #define PCF2123_REG_CTRL2 (0x01) /* Control Register 2 */ #define PCF2123_REG_SC (0x02) /* datetime */ @@ -57,10 +58,53 @@ #define PCF2123_REG_DW (0x06) #define PCF2123_REG_MO (0x07) #define PCF2123_REG_YR (0x08) +#define PCF2123_REG_ALRM_MN (0x09) /* Alarm Registers */ +#define PCF2123_REG_ALRM_HR (0x0a) +#define PCF2123_REG_ALRM_DM (0x0b) +#define PCF2123_REG_ALRM_DW (0x0c) +#define PCF2123_REG_OFFSET (0x0d) /* Clock Rate Offset Register */ +#define PCF2123_REG_TMR_CLKOUT (0x0e) /* Timer Registers */ +#define PCF2123_REG_CTDWN_TMR (0x0f) + +/* PCF2123_REG_CTRL1 BITS */ +#define CTRL1_CLEAR (0) /* Clear */ +#define CTRL1_CORR_INT BIT(1) /* Correction irq enable */ +#define CTRL1_12_HOUR BIT(2) /* 12 hour time */ +#define CTRL1_SW_RESET (BIT(3) | BIT(4) | BIT(6)) /* Software reset */ +#define CTRL1_STOP BIT(5) /* Stop the clock */ +#define CTRL1_EXT_TEST BIT(7) /* External clock test mode */ + +/* PCF2123_REG_CTRL2 BITS */ +#define CTRL2_TIE BIT(0) /* Countdown timer irq enable */ +#define CTRL2_AIE BIT(1) /* Alarm irq enable */ +#define CTRL2_TF BIT(2) /* Countdown timer flag */ +#define CTRL2_AF BIT(3) /* Alarm flag */ +#define CTRL2_TI_TP BIT(4) /* Irq pin generates pulse */ +#define CTRL2_MSF BIT(5) /* Minute or second irq flag */ +#define CTRL2_SI BIT(6) /* Second irq enable */ +#define CTRL2_MI BIT(7) /* Minute irq enable */ + +/* PCF2123_REG_SC BITS */ +#define OSC_HAS_STOPPED BIT(7) /* Clock has been stopped */ + +/* PCF2123_REG_ALRM_XX BITS */ +#define ALRM_ENABLE BIT(7) /* MN, HR, DM, or DW alarm enable */ + +/* PCF2123_REG_TMR_CLKOUT BITS */ +#define CD_TMR_4096KHZ (0) /* 4096 KHz countdown timer */ +#define CD_TMR_64HZ (1) /* 64 Hz countdown timer */ +#define CD_TMR_1HZ (2) /* 1 Hz countdown timer */ +#define CD_TMR_60th_HZ (3) /* 60th Hz countdown timer */ +#define CD_TMR_TE BIT(3) /* Countdown timer enable */ + +/* PCF2123_REG_OFFSET BITS */ +#define OFFSET_SIGN_BIT BIT(6) /* 2's complement sign bit */ +#define OFFSET_COARSE BIT(7) /* Coarse mode offset */ + +/* READ/WRITE ADDRESS BITS */ +#define PCF2123_WRITE BIT(4) +#define PCF2123_READ (BIT(4) | BIT(7)) -#define PCF2123_SUBADDR (1 << 4) -#define PCF2123_WRITE ((0 << 7) | PCF2123_SUBADDR) -#define PCF2123_READ ((1 << 7) | PCF2123_SUBADDR) static struct spi_driver pcf2123_driver; -- cgit v0.10.2 From 66c056d6a1f7392b4fe49500ad65fd96e4d94435 Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Mon, 4 Jan 2016 10:31:20 -0800 Subject: rtc: pcf2123: clean up reads from the chip Put read operations into a function. This improves modularity and readability. Signed-off-by: Joshua Clayton Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index be3ec83..4c4b3fc 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -128,12 +128,23 @@ static inline void pcf2123_delay_trec(void) ndelay(30); } +static int pcf2123_read(struct device *dev, u8 reg, u8 *rxbuf, size_t size) +{ + struct spi_device *spi = to_spi_device(dev); + int ret; + + reg |= PCF2123_READ; + ret = spi_write_then_read(spi, ®, 1, rxbuf, size); + pcf2123_delay_trec(); + + return ret; +} + static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr, char *buffer) { - struct spi_device *spi = to_spi_device(dev); struct pcf2123_sysfs_reg *r; - u8 txbuf[1], rxbuf[1]; + u8 rxbuf[1]; unsigned long reg; int ret; @@ -143,11 +154,10 @@ static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr, if (ret) return ret; - txbuf[0] = PCF2123_READ | reg; - ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 1); + ret = pcf2123_read(dev, reg, rxbuf, 1); if (ret < 0) return -EIO; - pcf2123_delay_trec(); + return sprintf(buffer, "0x%x\n", rxbuf[0]); } @@ -182,16 +192,12 @@ static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr, static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct spi_device *spi = to_spi_device(dev); - u8 txbuf[1], rxbuf[7]; + u8 rxbuf[7]; int ret; - txbuf[0] = PCF2123_READ | PCF2123_REG_SC; - ret = spi_write_then_read(spi, txbuf, sizeof(txbuf), - rxbuf, sizeof(rxbuf)); + ret = pcf2123_read(dev, PCF2123_REG_SC, rxbuf, sizeof(rxbuf)); if (ret < 0) return ret; - pcf2123_delay_trec(); tm->tm_sec = bcd2bin(rxbuf[0] & 0x7F); tm->tm_min = bcd2bin(rxbuf[1] & 0x7F); @@ -297,16 +303,12 @@ static int pcf2123_probe(struct spi_device *spi) pcf2123_delay_trec(); /* See if the counter was actually stopped */ - txbuf[0] = PCF2123_READ | PCF2123_REG_CTRL1; - dev_dbg(&spi->dev, "checking for presence of RTC (0x%02X)\n", - txbuf[0]); - ret = spi_write_then_read(spi, txbuf, 1 * sizeof(u8), - rxbuf, 2 * sizeof(u8)); + dev_dbg(&spi->dev, "checking for presence of RTC\n"); + ret = pcf2123_read(&spi->dev, PCF2123_REG_CTRL1, rxbuf, sizeof(rxbuf)); dev_dbg(&spi->dev, "received data from RTC (0x%02X 0x%02X)\n", rxbuf[0], rxbuf[1]); if (ret < 0) goto kfree_exit; - pcf2123_delay_trec(); if (!(rxbuf[0] & 0x20)) { dev_err(&spi->dev, "chip not found\n"); -- cgit v0.10.2 From 809b453b76e1544d245b7285fe570f3f20b8bd89 Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Mon, 4 Jan 2016 10:31:21 -0800 Subject: rtc: pcf2123: clean up writes to the rtc chip Add new functions pcf2123_write(), and pcf2123_write_reg(). Use named defines for the values being written. This improves modularity and readability, and reduces lines of code. Signed-off-by: Joshua Clayton Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index 4c4b3fc..0f2ce45 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -140,6 +140,27 @@ static int pcf2123_read(struct device *dev, u8 reg, u8 *rxbuf, size_t size) return ret; } +static int pcf2123_write(struct device *dev, u8 *txbuf, size_t size) +{ + struct spi_device *spi = to_spi_device(dev); + int ret; + + txbuf[0] |= PCF2123_WRITE; + ret = spi_write(spi, txbuf, size); + pcf2123_delay_trec(); + + return ret; +} + +static int pcf2123_write_reg(struct device *dev, u8 reg, u8 val) +{ + u8 txbuf[2]; + + txbuf[0] = reg; + txbuf[1] = val; + return pcf2123_write(dev, txbuf, sizeof(txbuf)); +} + static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr, char *buffer) { @@ -163,9 +184,7 @@ static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr, static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr, const char *buffer, size_t count) { - struct spi_device *spi = to_spi_device(dev); struct pcf2123_sysfs_reg *r; - u8 txbuf[2]; unsigned long reg; unsigned long val; @@ -181,12 +200,9 @@ static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr, if (ret) return ret; - txbuf[0] = PCF2123_WRITE | reg; - txbuf[1] = val; - ret = spi_write(spi, txbuf, sizeof(txbuf)); + pcf2123_write_reg(dev, reg, val); if (ret < 0) return -EIO; - pcf2123_delay_trec(); return count; } @@ -220,7 +236,6 @@ static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm) static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct spi_device *spi = to_spi_device(dev); u8 txbuf[8]; int ret; @@ -231,15 +246,12 @@ static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm) tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); /* Stop the counter first */ - txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1; - txbuf[1] = 0x20; - ret = spi_write(spi, txbuf, 2); + ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP); if (ret < 0) return ret; - pcf2123_delay_trec(); /* Set the new time */ - txbuf[0] = PCF2123_WRITE | PCF2123_REG_SC; + txbuf[0] = PCF2123_REG_SC; txbuf[1] = bin2bcd(tm->tm_sec & 0x7F); txbuf[2] = bin2bcd(tm->tm_min & 0x7F); txbuf[3] = bin2bcd(tm->tm_hour & 0x3F); @@ -248,18 +260,14 @@ static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm) txbuf[6] = bin2bcd((tm->tm_mon + 1) & 0x1F); /* rtc mn 1-12 */ txbuf[7] = bin2bcd(tm->tm_year < 100 ? tm->tm_year : tm->tm_year - 100); - ret = spi_write(spi, txbuf, sizeof(txbuf)); + ret = pcf2123_write(dev, txbuf, sizeof(txbuf)); if (ret < 0) return ret; - pcf2123_delay_trec(); /* Start the counter */ - txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1; - txbuf[1] = 0x00; - ret = spi_write(spi, txbuf, 2); + ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR); if (ret < 0) return ret; - pcf2123_delay_trec(); return 0; } @@ -273,7 +281,7 @@ static int pcf2123_probe(struct spi_device *spi) { struct rtc_device *rtc; struct pcf2123_plat_data *pdata; - u8 txbuf[2], rxbuf[2]; + u8 rxbuf[2]; int ret, i; pdata = devm_kzalloc(&spi->dev, sizeof(struct pcf2123_plat_data), @@ -283,24 +291,16 @@ static int pcf2123_probe(struct spi_device *spi) spi->dev.platform_data = pdata; /* Send a software reset command */ - txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1; - txbuf[1] = 0x58; - dev_dbg(&spi->dev, "resetting RTC (0x%02X 0x%02X)\n", - txbuf[0], txbuf[1]); - ret = spi_write(spi, txbuf, 2 * sizeof(u8)); + dev_dbg(&spi->dev, "resetting RTC\n"); + ret = pcf2123_write_reg(&spi->dev, PCF2123_REG_CTRL1, CTRL1_SW_RESET); if (ret < 0) goto kfree_exit; - pcf2123_delay_trec(); /* Stop the counter */ - txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1; - txbuf[1] = 0x20; - dev_dbg(&spi->dev, "stopping RTC (0x%02X 0x%02X)\n", - txbuf[0], txbuf[1]); - ret = spi_write(spi, txbuf, 2 * sizeof(u8)); + dev_dbg(&spi->dev, "stopping RTC\n"); + ret = pcf2123_write_reg(&spi->dev, PCF2123_REG_CTRL1, CTRL1_STOP); if (ret < 0) goto kfree_exit; - pcf2123_delay_trec(); /* See if the counter was actually stopped */ dev_dbg(&spi->dev, "checking for presence of RTC\n"); @@ -321,12 +321,9 @@ static int pcf2123_probe(struct spi_device *spi) (spi->max_speed_hz + 500) / 1000); /* Start the counter */ - txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1; - txbuf[1] = 0x00; - ret = spi_write(spi, txbuf, sizeof(txbuf)); + ret = pcf2123_write_reg(&spi->dev, PCF2123_REG_CTRL1, CTRL1_CLEAR); if (ret < 0) goto kfree_exit; - pcf2123_delay_trec(); /* Finalize the initialization */ rtc = devm_rtc_device_register(&spi->dev, pcf2123_driver.driver.name, -- cgit v0.10.2 From 1e094b946c1e2186b412118c2af3cc602cad3ac4 Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Mon, 4 Jan 2016 10:31:22 -0800 Subject: rtc: pcf2123: refactor chip reset into a function Refactor chip reset items into its own function, isolating it from the rest of the device probe. Subsequent commits will avoid calling this code. Signed-off-by: Joshua Clayton Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index 0f2ce45..2d886d4 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -272,6 +272,40 @@ static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm) return 0; } +static int pcf2123_reset(struct device *dev) +{ + int ret; + u8 rxbuf[2]; + + ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_SW_RESET); + if (ret < 0) + return ret; + + /* Stop the counter */ + dev_dbg(dev, "stopping RTC\n"); + ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP); + if (ret < 0) + return ret; + + /* See if the counter was actually stopped */ + dev_dbg(dev, "checking for presence of RTC\n"); + ret = pcf2123_read(dev, PCF2123_REG_CTRL1, rxbuf, sizeof(rxbuf)); + if (ret < 0) + return ret; + + dev_dbg(dev, "received data from RTC (0x%02X 0x%02X)\n", + rxbuf[0], rxbuf[1]); + if (!(rxbuf[0] & CTRL1_STOP)) + return -ENODEV; + + /* Start the counter */ + ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR); + if (ret < 0) + return ret; + + return 0; +} + static const struct rtc_class_ops pcf2123_rtc_ops = { .read_time = pcf2123_rtc_read_time, .set_time = pcf2123_rtc_set_time, @@ -281,7 +315,6 @@ static int pcf2123_probe(struct spi_device *spi) { struct rtc_device *rtc; struct pcf2123_plat_data *pdata; - u8 rxbuf[2]; int ret, i; pdata = devm_kzalloc(&spi->dev, sizeof(struct pcf2123_plat_data), @@ -290,29 +323,9 @@ static int pcf2123_probe(struct spi_device *spi) return -ENOMEM; spi->dev.platform_data = pdata; - /* Send a software reset command */ - dev_dbg(&spi->dev, "resetting RTC\n"); - ret = pcf2123_write_reg(&spi->dev, PCF2123_REG_CTRL1, CTRL1_SW_RESET); - if (ret < 0) - goto kfree_exit; - - /* Stop the counter */ - dev_dbg(&spi->dev, "stopping RTC\n"); - ret = pcf2123_write_reg(&spi->dev, PCF2123_REG_CTRL1, CTRL1_STOP); - if (ret < 0) - goto kfree_exit; - - /* See if the counter was actually stopped */ - dev_dbg(&spi->dev, "checking for presence of RTC\n"); - ret = pcf2123_read(&spi->dev, PCF2123_REG_CTRL1, rxbuf, sizeof(rxbuf)); - dev_dbg(&spi->dev, "received data from RTC (0x%02X 0x%02X)\n", - rxbuf[0], rxbuf[1]); - if (ret < 0) - goto kfree_exit; - - if (!(rxbuf[0] & 0x20)) { + ret = pcf2123_reset(&spi->dev); + if (ret < 0) { dev_err(&spi->dev, "chip not found\n"); - ret = -ENODEV; goto kfree_exit; } @@ -320,11 +333,6 @@ static int pcf2123_probe(struct spi_device *spi) dev_info(&spi->dev, "spiclk %u KHz.\n", (spi->max_speed_hz + 500) / 1000); - /* Start the counter */ - ret = pcf2123_write_reg(&spi->dev, PCF2123_REG_CTRL1, CTRL1_CLEAR); - if (ret < 0) - goto kfree_exit; - /* Finalize the initialization */ rtc = devm_rtc_device_register(&spi->dev, pcf2123_driver.driver.name, &pcf2123_rtc_ops, THIS_MODULE); -- cgit v0.10.2 From f07fa9242ee72e8a1e926458759b895b3f1de115 Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Mon, 4 Jan 2016 10:31:23 -0800 Subject: rtc: pcf2123: avoid resetting the clock if possible pcf2123 data sheet recommends a software reset when the chip is first powered on. This change avoids resetting the chip every time the driver is loaded, which has some negative effects. There are several registers including a clock rate adjustment that really should survive a reload of the driver (or reboot). In addition, stopping and restarting the clock to verify the chip is there is not a good thing once the time is set. According to the data sheet, the seconds register has a 1 in the high bit when the voltage has gotten low. We check for this condition, as well as whether the time retrieved from the chip is valid. We reset the rtc only if the time is not reliable and valid. This is sufficient for checking for the presence of the chip, as either all zeros or all 0xff will result in an invalid time/date Signed-off-by: Joshua Clayton Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index 2d886d4..d9a44ad 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -215,6 +215,11 @@ static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm) if (ret < 0) return ret; + if (rxbuf[0] & OSC_HAS_STOPPED) { + dev_info(dev, "clock was stopped. Time is not valid\n"); + return -EINVAL; + } + tm->tm_sec = bcd2bin(rxbuf[0] & 0x7F); tm->tm_min = bcd2bin(rxbuf[1] & 0x7F); tm->tm_hour = bcd2bin(rxbuf[2] & 0x3F); /* rtc hr 0-23 */ @@ -314,6 +319,7 @@ static const struct rtc_class_ops pcf2123_rtc_ops = { static int pcf2123_probe(struct spi_device *spi) { struct rtc_device *rtc; + struct rtc_time tm; struct pcf2123_plat_data *pdata; int ret, i; @@ -323,10 +329,13 @@ static int pcf2123_probe(struct spi_device *spi) return -ENOMEM; spi->dev.platform_data = pdata; - ret = pcf2123_reset(&spi->dev); + ret = pcf2123_rtc_read_time(&spi->dev, &tm); if (ret < 0) { - dev_err(&spi->dev, "chip not found\n"); - goto kfree_exit; + ret = pcf2123_reset(&spi->dev); + if (ret < 0) { + dev_err(&spi->dev, "chip not found\n"); + goto kfree_exit; + } } dev_info(&spi->dev, "chip found, driver version " DRV_VERSION "\n"); -- cgit v0.10.2 From cfe941628a04b572b0dba7a20fd4570edad74c81 Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Mon, 4 Jan 2016 18:04:34 +0100 Subject: Documentation: devicetree: add epson rx6110 binding Add the binding documentation for the Epson RX6110 RTC. Acked-by: Rob Herring Reviewed-by: Philipp Zabel Signed-off-by: Steffen Trumtrar Signed-off-by: Alexandre Belloni diff --git a/Documentation/devicetree/bindings/rtc/epson,rx6110.txt b/Documentation/devicetree/bindings/rtc/epson,rx6110.txt new file mode 100644 index 0000000..3dc313e --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/epson,rx6110.txt @@ -0,0 +1,39 @@ +Epson RX6110 Real Time Clock +============================ + +The Epson RX6110 can be used with SPI or I2C busses. The kind of +bus depends on the SPISEL pin and can not be configured via software. + +I2C mode +-------- + +Required properties: + - compatible: should be: "epson,rx6110" + - reg : the I2C address of the device for I2C + +Example: + + rtc: rtc@32 { + compatible = "epson,rx6110" + reg = <0x32>; + }; + +SPI mode +-------- + +Required properties: + - compatible: should be: "epson,rx6110" + - reg: chip select number + - spi-cs-high: RX6110 needs chipselect high + - spi-cpha: RX6110 works with SPI shifted clock phase + - spi-cpol: RX6110 works with SPI inverse clock polarity + +Example: + + rtc: rtc@3 { + compatible = "epson,rx6110" + reg = <3> + spi-cs-high; + spi-cpha; + spi-cpol; + }; -- cgit v0.10.2 From 68298c2dac96c75ed6950f059bbb1368c21da2a3 Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Mon, 4 Jan 2016 18:04:35 +0100 Subject: rtc: add driver for RX6110SA real time clock The RX6110 comes in two different variants: SPI and I2C. This driver only supports the SPI variant. If the need ever arises to also support the I2C variant, this driver could easily be refactored to support both cases. Reviewed-by: Philipp Zabel Signed-off-by: Steffen Trumtrar Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index d47ad96..ec6a253 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -743,6 +743,15 @@ 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_RX6110 + tristate "Epson RX-6110" + select REGMAP_SPI + help + If you say yes here you will get support for the Epson RX-6610. + + This driver can also be built as a module. If so the module + will be called rtc-rx6110. + config RTC_DRV_MCP795 tristate "Microchip MCP795" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index ed4519e..c8a2147 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -127,6 +127,7 @@ obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o obj-$(CONFIG_RTC_DRV_RV8803) += rtc-rv8803.o obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o +obj-$(CONFIG_RTC_DRV_RX6110) += rtc-rx6110.o obj-$(CONFIG_RTC_DRV_RX8010) += rtc-rx8010.o obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c new file mode 100644 index 0000000..bbad00b --- /dev/null +++ b/drivers/rtc/rtc-rx6110.c @@ -0,0 +1,402 @@ +/* + * Driver for the Epson RTC module RX-6110 SA + * + * Copyright(C) 2015 Pengutronix, Steffen Trumtrar + * Copyright(C) SEIKO EPSON CORPORATION 2013. All rights reserved. + * + * This driver software is distributed as is, without any warranty of any kind, + * either express or implied as further specified in the GNU Public License. + * This software may be used and distributed according to the terms of the GNU + * Public License, version 2 as published by the Free Software Foundation. + * See the file COPYING in the main directory of this archive for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* RX-6110 Register definitions */ +#define RX6110_REG_SEC 0x10 +#define RX6110_REG_MIN 0x11 +#define RX6110_REG_HOUR 0x12 +#define RX6110_REG_WDAY 0x13 +#define RX6110_REG_MDAY 0x14 +#define RX6110_REG_MONTH 0x15 +#define RX6110_REG_YEAR 0x16 +#define RX6110_REG_RES1 0x17 +#define RX6110_REG_ALMIN 0x18 +#define RX6110_REG_ALHOUR 0x19 +#define RX6110_REG_ALWDAY 0x1A +#define RX6110_REG_TCOUNT0 0x1B +#define RX6110_REG_TCOUNT1 0x1C +#define RX6110_REG_EXT 0x1D +#define RX6110_REG_FLAG 0x1E +#define RX6110_REG_CTRL 0x1F +#define RX6110_REG_USER0 0x20 +#define RX6110_REG_USER1 0x21 +#define RX6110_REG_USER2 0x22 +#define RX6110_REG_USER3 0x23 +#define RX6110_REG_USER4 0x24 +#define RX6110_REG_USER5 0x25 +#define RX6110_REG_USER6 0x26 +#define RX6110_REG_USER7 0x27 +#define RX6110_REG_USER8 0x28 +#define RX6110_REG_USER9 0x29 +#define RX6110_REG_USERA 0x2A +#define RX6110_REG_USERB 0x2B +#define RX6110_REG_USERC 0x2C +#define RX6110_REG_USERD 0x2D +#define RX6110_REG_USERE 0x2E +#define RX6110_REG_USERF 0x2F +#define RX6110_REG_RES2 0x30 +#define RX6110_REG_RES3 0x31 +#define RX6110_REG_IRQ 0x32 + +#define RX6110_BIT_ALARM_EN BIT(7) + +/* Extension Register (1Dh) bit positions */ +#define RX6110_BIT_EXT_TSEL0 BIT(0) +#define RX6110_BIT_EXT_TSEL1 BIT(1) +#define RX6110_BIT_EXT_TSEL2 BIT(2) +#define RX6110_BIT_EXT_WADA BIT(3) +#define RX6110_BIT_EXT_TE BIT(4) +#define RX6110_BIT_EXT_USEL BIT(5) +#define RX6110_BIT_EXT_FSEL0 BIT(6) +#define RX6110_BIT_EXT_FSEL1 BIT(7) + +/* Flag Register (1Eh) bit positions */ +#define RX6110_BIT_FLAG_VLF BIT(1) +#define RX6110_BIT_FLAG_AF BIT(3) +#define RX6110_BIT_FLAG_TF BIT(4) +#define RX6110_BIT_FLAG_UF BIT(5) + +/* Control Register (1Fh) bit positions */ +#define RX6110_BIT_CTRL_TBKE BIT(0) +#define RX6110_BIT_CTRL_TBKON BIT(1) +#define RX6110_BIT_CTRL_TSTP BIT(2) +#define RX6110_BIT_CTRL_AIE BIT(3) +#define RX6110_BIT_CTRL_TIE BIT(4) +#define RX6110_BIT_CTRL_UIE BIT(5) +#define RX6110_BIT_CTRL_STOP BIT(6) +#define RX6110_BIT_CTRL_TEST BIT(7) + +enum { + RTC_SEC = 0, + RTC_MIN, + RTC_HOUR, + RTC_WDAY, + RTC_MDAY, + RTC_MONTH, + RTC_YEAR, + RTC_NR_TIME +}; + +#define RX6110_DRIVER_NAME "rx6110" + +struct rx6110_data { + struct rtc_device *rtc; + struct regmap *regmap; +}; + +/** + * rx6110_rtc_tm_to_data - convert rtc_time to native time encoding + * + * @tm: holds date and time + * @data: holds the encoding in rx6110 native form + */ +static int rx6110_rtc_tm_to_data(struct rtc_time *tm, u8 *data) +{ + pr_debug("%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year); + + /* + * The year in the RTC is a value between 0 and 99. + * Assume that this represents the current century + * and disregard all other values. + */ + if (tm->tm_year < 100 || tm->tm_year >= 200) + return -EINVAL; + + data[RTC_SEC] = bin2bcd(tm->tm_sec); + data[RTC_MIN] = bin2bcd(tm->tm_min); + data[RTC_HOUR] = bin2bcd(tm->tm_hour); + data[RTC_WDAY] = BIT(bin2bcd(tm->tm_wday)); + data[RTC_MDAY] = bin2bcd(tm->tm_mday); + data[RTC_MONTH] = bin2bcd(tm->tm_mon + 1); + data[RTC_YEAR] = bin2bcd(tm->tm_year % 100); + + return 0; +} + +/** + * rx6110_data_to_rtc_tm - convert native time encoding to rtc_time + * + * @data: holds the encoding in rx6110 native form + * @tm: holds date and time + */ +static int rx6110_data_to_rtc_tm(u8 *data, struct rtc_time *tm) +{ + tm->tm_sec = bcd2bin(data[RTC_SEC] & 0x7f); + tm->tm_min = bcd2bin(data[RTC_MIN] & 0x7f); + /* only 24-hour clock */ + tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f); + tm->tm_wday = ffs(data[RTC_WDAY] & 0x7f); + tm->tm_mday = bcd2bin(data[RTC_MDAY] & 0x3f); + tm->tm_mon = bcd2bin(data[RTC_MONTH] & 0x1f) - 1; + tm->tm_year = bcd2bin(data[RTC_YEAR]) + 100; + + pr_debug("%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year); + + /* + * The year in the RTC is a value between 0 and 99. + * Assume that this represents the current century + * and disregard all other values. + */ + if (tm->tm_year < 100 || tm->tm_year >= 200) + return -EINVAL; + + return 0; +} + +/** + * rx6110_set_time - set the current time in the rx6110 registers + * + * @dev: the rtc device in use + * @tm: holds date and time + * + * BUG: The HW assumes every year that is a multiple of 4 to be a leap + * year. Next time this is wrong is 2100, which will not be a leap year + * + * Note: If STOP is not set/cleared, the clock will start when the seconds + * register is written + * + */ +static int rx6110_set_time(struct device *dev, struct rtc_time *tm) +{ + struct rx6110_data *rx6110 = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + int ret; + + ret = rx6110_rtc_tm_to_data(tm, data); + if (ret < 0) + return ret; + + /* set STOP bit before changing clock/calendar */ + ret = regmap_update_bits(rx6110->regmap, RX6110_REG_CTRL, + RX6110_BIT_CTRL_STOP, RX6110_BIT_CTRL_STOP); + if (ret) + return ret; + + ret = regmap_bulk_write(rx6110->regmap, RX6110_REG_SEC, data, + RTC_NR_TIME); + if (ret) + return ret; + + /* The time in the RTC is valid. Be sure to have VLF cleared. */ + ret = regmap_update_bits(rx6110->regmap, RX6110_REG_FLAG, + RX6110_BIT_FLAG_VLF, 0); + if (ret) + return ret; + + /* clear STOP bit after changing clock/calendar */ + ret = regmap_update_bits(rx6110->regmap, RX6110_REG_CTRL, + RX6110_BIT_CTRL_STOP, 0); + + return ret; +} + +/** + * rx6110_get_time - get the current time from the rx6110 registers + * @dev: the rtc device in use + * @tm: holds date and time + */ +static int rx6110_get_time(struct device *dev, struct rtc_time *tm) +{ + struct rx6110_data *rx6110 = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + int flags; + int ret; + + ret = regmap_read(rx6110->regmap, RX6110_REG_FLAG, &flags); + if (ret) + return -EINVAL; + + /* check for VLF Flag (set at power-on) */ + if ((flags & RX6110_BIT_FLAG_VLF)) { + dev_warn(dev, "Voltage low, data is invalid.\n"); + return -EINVAL; + } + + /* read registers to date */ + ret = regmap_bulk_read(rx6110->regmap, RX6110_REG_SEC, data, + RTC_NR_TIME); + if (ret) + return ret; + + ret = rx6110_data_to_rtc_tm(data, tm); + if (ret) + return ret; + + dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year); + + return rtc_valid_tm(tm); +} + +static const struct reg_sequence rx6110_default_regs[] = { + { RX6110_REG_RES1, 0xB8 }, + { RX6110_REG_RES2, 0x00 }, + { RX6110_REG_RES3, 0x10 }, + { RX6110_REG_IRQ, 0x00 }, + { RX6110_REG_ALMIN, 0x00 }, + { RX6110_REG_ALHOUR, 0x00 }, + { RX6110_REG_ALWDAY, 0x00 }, +}; + +/** + * rx6110_init - initialize the rx6110 registers + * + * @rx6110: pointer to the rx6110 struct in use + * + */ +static int rx6110_init(struct rx6110_data *rx6110) +{ + struct rtc_device *rtc = rx6110->rtc; + int flags; + int ret; + + ret = regmap_update_bits(rx6110->regmap, RX6110_REG_EXT, + RX6110_BIT_EXT_TE, 0); + if (ret) + return ret; + + ret = regmap_register_patch(rx6110->regmap, rx6110_default_regs, + ARRAY_SIZE(rx6110_default_regs)); + if (ret) + return ret; + + ret = regmap_read(rx6110->regmap, RX6110_REG_FLAG, &flags); + if (ret) + return ret; + + /* check for VLF Flag (set at power-on) */ + if ((flags & RX6110_BIT_FLAG_VLF)) + dev_warn(&rtc->dev, "Voltage low, data loss detected.\n"); + + /* check for Alarm Flag */ + if (flags & RX6110_BIT_FLAG_AF) + dev_warn(&rtc->dev, "An alarm may have been missed.\n"); + + /* check for Periodic Timer Flag */ + if (flags & RX6110_BIT_FLAG_TF) + dev_warn(&rtc->dev, "Periodic timer was detected\n"); + + /* check for Update Timer Flag */ + if (flags & RX6110_BIT_FLAG_UF) + dev_warn(&rtc->dev, "Update timer was detected\n"); + + /* clear all flags BUT VLF */ + ret = regmap_update_bits(rx6110->regmap, RX6110_REG_FLAG, + RX6110_BIT_FLAG_AF | + RX6110_BIT_FLAG_UF | + RX6110_BIT_FLAG_TF, + 0); + + return ret; +} + +static struct rtc_class_ops rx6110_rtc_ops = { + .read_time = rx6110_get_time, + .set_time = rx6110_set_time, +}; + +static struct regmap_config regmap_spi_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RX6110_REG_IRQ, + .read_flag_mask = 0x80, +}; + +/** + * rx6110_probe - initialize rtc driver + * @spi: pointer to spi device + */ +static int rx6110_probe(struct spi_device *spi) +{ + struct rx6110_data *rx6110; + int err; + + if ((spi->bits_per_word && spi->bits_per_word != 8) || + (spi->max_speed_hz > 2000000) || + (spi->mode != (SPI_CS_HIGH | SPI_CPOL | SPI_CPHA))) { + dev_warn(&spi->dev, "SPI settings: bits_per_word: %d, max_speed_hz: %d, mode: %xh\n", + spi->bits_per_word, spi->max_speed_hz, spi->mode); + dev_warn(&spi->dev, "driving device in an unsupported mode"); + } + + rx6110 = devm_kzalloc(&spi->dev, sizeof(*rx6110), GFP_KERNEL); + if (!rx6110) + return -ENOMEM; + + rx6110->regmap = devm_regmap_init_spi(spi, ®map_spi_config); + if (IS_ERR(rx6110->regmap)) { + dev_err(&spi->dev, "regmap init failed for rtc rx6110\n"); + return PTR_ERR(rx6110->regmap); + } + + spi_set_drvdata(spi, rx6110); + + rx6110->rtc = devm_rtc_device_register(&spi->dev, + RX6110_DRIVER_NAME, + &rx6110_rtc_ops, THIS_MODULE); + + if (IS_ERR(rx6110->rtc)) + return PTR_ERR(rx6110->rtc); + + err = rx6110_init(rx6110); + if (err) + return err; + + rx6110->rtc->max_user_freq = 1; + + return 0; +} + +static int rx6110_remove(struct spi_device *spi) +{ + return 0; +} + +static const struct spi_device_id rx6110_id[] = { + { "rx6110", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, rx6110_id); + +static struct spi_driver rx6110_driver = { + .driver = { + .name = RX6110_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = rx6110_probe, + .remove = rx6110_remove, + .id_table = rx6110_id, +}; + +module_spi_driver(rx6110_driver); + +MODULE_AUTHOR("Val Krutov "); +MODULE_DESCRIPTION("RX-6110 SA RTC driver"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 2863934e2393e6b3bf635ff51a35ed1bc5a83ca8 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 1 Feb 2016 17:39:22 +0000 Subject: rtc: allow compilation of sun6i RTC for all sunxi SoCs At the moment the "sun6i" RTC drivers depends on having two specific SoC families selected. The Allwinner A64 SoC has the same RTC, so extend the Kconfig option to allow inclusion of the driver for all Allwinner SoCs. Signed-off-by: Andre Przywara Acked-by: Maxime Ripard Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index ec6a253..2cf87f7 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1368,10 +1368,11 @@ config RTC_DRV_SUN4V config RTC_DRV_SUN6I tristate "Allwinner A31 RTC" - depends on MACH_SUN6I || MACH_SUN8I + default MACH_SUN6I || MACH_SUN8I + depends on ARCH_SUNXI help - If you say Y here you will get support for the RTC found on - Allwinner A31. + If you say Y here you will get support for the RTC found in + some Allwinner SoCs like the A31 or the A64. config RTC_DRV_SUNXI tristate "Allwinner sun4i/sun7i RTC" -- cgit v0.10.2 From 0b4f8b085b5dc2567e5cfb6417df9f79df9cb39e Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 9 Feb 2016 22:56:30 +0530 Subject: rtc: max77686: fix checkpatch error Fix following check patch error in rtc-max77686 driver: - Alignment should match open parenthesis. - braces {} should be used on all arms of this statement. - Prefer using the BIT macro Signed-off-by: Laxman Dewangan Tested-by: Krzysztof Kozlowski Reviewed-by: Krzysztof Kozlowski Tested-by: Javier Martinez Canillas Reviewed-by: Javier Martinez Canillas Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 0f2965d..7f1ca10 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -24,20 +24,20 @@ /* RTC Control Register */ #define BCD_EN_SHIFT 0 -#define BCD_EN_MASK (1 << BCD_EN_SHIFT) +#define BCD_EN_MASK BIT(BCD_EN_SHIFT) #define MODEL24_SHIFT 1 -#define MODEL24_MASK (1 << MODEL24_SHIFT) +#define MODEL24_MASK BIT(MODEL24_SHIFT) /* RTC Update Register1 */ #define RTC_UDR_SHIFT 0 -#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) +#define RTC_UDR_MASK BIT(RTC_UDR_SHIFT) #define RTC_RBUDR_SHIFT 4 -#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT) +#define RTC_RBUDR_MASK BIT(RTC_RBUDR_SHIFT) /* RTC Hour register */ #define HOUR_PM_SHIFT 6 -#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT) +#define HOUR_PM_MASK BIT(HOUR_PM_SHIFT) /* RTC Alarm Enable */ #define ALARM_ENABLE_SHIFT 7 -#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) +#define ALARM_ENABLE_MASK BIT(ALARM_ENABLE_SHIFT) #define REG_RTC_NONE 0xdeadbeef @@ -205,9 +205,9 @@ static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, tm->tm_sec = data[RTC_SEC] & mask; tm->tm_min = data[RTC_MIN] & mask; - if (info->rtc_24hr_mode) + if (info->rtc_24hr_mode) { tm->tm_hour = data[RTC_HOUR] & 0x1f; - else { + } else { tm->tm_hour = data[RTC_HOUR] & 0x0f; if (data[RTC_HOUR] & HOUR_PM_MASK) tm->tm_hour += 12; @@ -256,7 +256,7 @@ static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data, } static int max77686_rtc_update(struct max77686_rtc_info *info, - enum MAX77686_RTC_OP op) + enum MAX77686_RTC_OP op) { int ret; unsigned int data; @@ -547,7 +547,7 @@ out: } static int max77686_rtc_alarm_irq_enable(struct device *dev, - unsigned int enabled) + unsigned int enabled) { struct max77686_rtc_info *info = dev_get_drvdata(dev); int ret; @@ -612,7 +612,7 @@ static int max77686_rtc_probe(struct platform_device *pdev) int ret; info = devm_kzalloc(&pdev->dev, sizeof(struct max77686_rtc_info), - GFP_KERNEL); + GFP_KERNEL); if (!info) return -ENOMEM; @@ -662,7 +662,8 @@ static int max77686_rtc_probe(struct platform_device *pdev) } ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL, - max77686_rtc_alarm_irq, 0, "rtc-alarm1", info); + max77686_rtc_alarm_irq, 0, + "rtc-alarm1", info); if (ret < 0) dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", info->virq, ret); -- cgit v0.10.2 From 69be249ab4bcfe3dae61866835f102632cdbe9d9 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 9 Feb 2016 22:56:31 +0530 Subject: rtc: max77686: use rtc regmap to access RTC registers rtc_regmap should be used to access all RTC registers instead of parent regmap regardless of what chip or property have it. This makes the register access uniform and extendible for other chips. Signed-off-by: Laxman Dewangan Tested-by: Krzysztof Kozlowski Reviewed-by: Krzysztof Kozlowski Tested-by: Javier Martinez Canillas Reviewed-by: Javier Martinez Canillas Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 7f1ca10..28330e8 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -370,7 +370,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) goto out; } - ret = regmap_read(info->max77686->regmap, + ret = regmap_read(info->max77686->rtc_regmap, map[REG_RTC_AE1], &val); if (ret < 0) { dev_err(info->dev, @@ -426,7 +426,8 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) goto out; } - ret = regmap_write(info->max77686->regmap, map[REG_RTC_AE1], 0); + ret = regmap_write(info->max77686->rtc_regmap, + map[REG_RTC_AE1], 0); } else { ret = regmap_bulk_read(info->max77686->rtc_regmap, map[REG_ALARM1_SEC], data, @@ -471,7 +472,7 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) goto out; if (info->drv_data->alarm_enable_reg) { - ret = regmap_write(info->max77686->regmap, map[REG_RTC_AE1], + ret = regmap_write(info->max77686->rtc_regmap, map[REG_RTC_AE1], MAX77802_ALARM_ENABLE_VALUE); } else { ret = regmap_bulk_read(info->max77686->rtc_regmap, -- cgit v0.10.2 From f604c48849a5408065d1b53e89588dd76054dd06 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 9 Feb 2016 22:56:32 +0530 Subject: rtc: max77686: avoid reference of parent device info multiple places Get rid of referring parent device info for register access all the places by making regmap as part of max77686 rtc device info. This will also remove the need of storing parent device info in max77686 rtc device info as this is no more required. Signed-off-by: Laxman Dewangan Tested-by: Krzysztof Kozlowski Reviewed-by: Krzysztof Kozlowski Tested-by: Javier Martinez Canillas Reviewed-by: Javier Martinez Canillas Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 28330e8..8fe1092 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -74,12 +74,12 @@ struct max77686_rtc_driver_data { struct max77686_rtc_info { struct device *dev; - struct max77686_dev *max77686; struct i2c_client *rtc; struct rtc_device *rtc_dev; struct mutex lock; struct regmap *regmap; + struct regmap *rtc_regmap; const struct max77686_rtc_driver_data *drv_data; @@ -267,7 +267,7 @@ static int max77686_rtc_update(struct max77686_rtc_info *info, else data = 1 << RTC_RBUDR_SHIFT; - ret = regmap_update_bits(info->max77686->rtc_regmap, + ret = regmap_update_bits(info->rtc_regmap, info->drv_data->map[REG_RTC_UPDATE0], data, data); if (ret < 0) @@ -293,7 +293,7 @@ static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm) if (ret < 0) goto out; - ret = regmap_bulk_read(info->max77686->rtc_regmap, + ret = regmap_bulk_read(info->rtc_regmap, info->drv_data->map[REG_RTC_SEC], data, ARRAY_SIZE(data)); if (ret < 0) { @@ -322,7 +322,7 @@ static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm) mutex_lock(&info->lock); - ret = regmap_bulk_write(info->max77686->rtc_regmap, + ret = regmap_bulk_write(info->rtc_regmap, info->drv_data->map[REG_RTC_SEC], data, ARRAY_SIZE(data)); if (ret < 0) { @@ -351,8 +351,8 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) if (ret < 0) goto out; - ret = regmap_bulk_read(info->max77686->rtc_regmap, - map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); + ret = regmap_bulk_read(info->rtc_regmap, map[REG_ALARM1_SEC], + data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret); goto out; @@ -370,8 +370,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) goto out; } - ret = regmap_read(info->max77686->rtc_regmap, - map[REG_RTC_AE1], &val); + ret = regmap_read(info->rtc_regmap, map[REG_RTC_AE1], &val); if (ret < 0) { dev_err(info->dev, "fail to read alarm enable(%d)\n", ret); @@ -390,7 +389,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) } alrm->pending = 0; - ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS2, &val); + ret = regmap_read(info->regmap, MAX77686_REG_STATUS2, &val); if (ret < 0) { dev_err(info->dev, "Fail to read status2 reg(%d)\n", ret); goto out; @@ -426,12 +425,10 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) goto out; } - ret = regmap_write(info->max77686->rtc_regmap, - map[REG_RTC_AE1], 0); + ret = regmap_write(info->rtc_regmap, map[REG_RTC_AE1], 0); } else { - ret = regmap_bulk_read(info->max77686->rtc_regmap, - map[REG_ALARM1_SEC], data, - ARRAY_SIZE(data)); + ret = regmap_bulk_read(info->rtc_regmap, map[REG_ALARM1_SEC], + data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret); goto out; @@ -442,9 +439,8 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) for (i = 0; i < ARRAY_SIZE(data); i++) data[i] &= ~ALARM_ENABLE_MASK; - ret = regmap_bulk_write(info->max77686->rtc_regmap, - map[REG_ALARM1_SEC], data, - ARRAY_SIZE(data)); + ret = regmap_bulk_write(info->rtc_regmap, map[REG_ALARM1_SEC], + data, ARRAY_SIZE(data)); } if (ret < 0) { @@ -472,12 +468,11 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) goto out; if (info->drv_data->alarm_enable_reg) { - ret = regmap_write(info->max77686->rtc_regmap, map[REG_RTC_AE1], + ret = regmap_write(info->rtc_regmap, map[REG_RTC_AE1], MAX77802_ALARM_ENABLE_VALUE); } else { - ret = regmap_bulk_read(info->max77686->rtc_regmap, - map[REG_ALARM1_SEC], data, - ARRAY_SIZE(data)); + ret = regmap_bulk_read(info->rtc_regmap, map[REG_ALARM1_SEC], + data, ARRAY_SIZE(data)); if (ret < 0) { dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret); goto out; @@ -496,9 +491,8 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) if (data[RTC_DATE] & 0x1f) data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); - ret = regmap_bulk_write(info->max77686->rtc_regmap, - map[REG_ALARM1_SEC], data, - ARRAY_SIZE(data)); + ret = regmap_bulk_write(info->rtc_regmap, map[REG_ALARM1_SEC], + data, ARRAY_SIZE(data)); } if (ret < 0) { @@ -527,7 +521,7 @@ static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) if (ret < 0) goto out; - ret = regmap_bulk_write(info->max77686->rtc_regmap, + ret = regmap_bulk_write(info->rtc_regmap, info->drv_data->map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); @@ -593,7 +587,7 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info) info->rtc_24hr_mode = 1; - ret = regmap_bulk_write(info->max77686->rtc_regmap, + ret = regmap_bulk_write(info->rtc_regmap, info->drv_data->map[REG_RTC_CONTROLM], data, ARRAY_SIZE(data)); if (ret < 0) { @@ -619,13 +613,13 @@ static int max77686_rtc_probe(struct platform_device *pdev) mutex_init(&info->lock); info->dev = &pdev->dev; - info->max77686 = max77686; info->rtc = max77686->rtc; info->drv_data = (const struct max77686_rtc_driver_data *) id->driver_data; - if (!info->drv_data->separate_i2c_addr) - info->max77686->rtc_regmap = info->max77686->regmap; + info->regmap = max77686->regmap; + info->rtc_regmap = (info->drv_data->separate_i2c_addr) ? + max77686->rtc_regmap : info->regmap; platform_set_drvdata(pdev, info); -- cgit v0.10.2 From 08e37ef17db5b0d387564cf06520f6ff5f54c76b Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 9 Feb 2016 22:56:33 +0530 Subject: mfd: max77686: do not set i2c client data for rtc i2c client There is different RTC I2C address for RTC block in MAX77686. Driver is creating dummy i2c client for this address to access the register of this IP block. As there is no call to i2c_get_clientdata() for rtc_i2c client, there is no need to store pointer and hence removing the call to set client data for rtc i2c client. Suggested-by: Krzysztof Kozlowski Signed-off-by: Laxman Dewangan Tested-by: Krzysztof Kozlowski Reviewed-by: Krzysztof Kozlowski Tested-by: Javier Martinez Canillas Reviewed-by: Javier Martinez Canillas Acked-by: Lee Jones Signed-off-by: Alexandre Belloni diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index d959ebb..bda6fd7 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -277,7 +277,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c, "Failed to allocate I2C device for RTC\n"); return -ENODEV; } - i2c_set_clientdata(max77686->rtc, max77686); max77686->rtc_regmap = devm_regmap_init_i2c(max77686->rtc, -- cgit v0.10.2 From f3937549a975fadec9b517b059616f08f9cb7653 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 9 Feb 2016 22:56:34 +0530 Subject: rtc: max77686: move initialisation of rtc regmap, irq chip locally To make RTC block of MAX77686/MAX77802 as independent driver, move the registration of i2c device, regmap for register access and irq_chip for interrupt support inside the RTC driver. Removed the same initialisation from MFD driver. Having this change will allow to reuse this driver for different PMIC/devices from Maxim Semiconductor if they kept same RTC IP on different PMIC. Some of examples as PMIC MAX77620, MAX20024 where same RTC IP used and hence driver for these chips will use this driver only for RTC support. Suggested-by: Krzysztof Kozlowski Signed-off-by: Laxman Dewangan Tested-by: Javier Martinez Canillas Reviewed-by: Javier Martinez Canillas Acked-by: Lee Jones Tested-by: Krzysztof Kozlowski Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index bda6fd7..98ecd13 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -35,8 +35,6 @@ #include #include -#define I2C_ADDR_RTC (0x0C >> 1) - static const struct mfd_cell max77686_devs[] = { { .name = "max77686-pmic", }, { .name = "max77686-rtc", }, @@ -116,11 +114,6 @@ static const struct regmap_config max77686_regmap_config = { .val_bits = 8, }; -static const struct regmap_config max77686_rtc_regmap_config = { - .reg_bits = 8, - .val_bits = 8, -}; - static const struct regmap_config max77802_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -156,25 +149,6 @@ static const struct regmap_irq_chip max77686_irq_chip = { .num_irqs = ARRAY_SIZE(max77686_irqs), }; -static const struct regmap_irq max77686_rtc_irqs[] = { - /* RTC interrupts */ - { .reg_offset = 0, .mask = MAX77686_RTCINT_RTC60S_MSK, }, - { .reg_offset = 0, .mask = MAX77686_RTCINT_RTCA1_MSK, }, - { .reg_offset = 0, .mask = MAX77686_RTCINT_RTCA2_MSK, }, - { .reg_offset = 0, .mask = MAX77686_RTCINT_SMPL_MSK, }, - { .reg_offset = 0, .mask = MAX77686_RTCINT_RTC1S_MSK, }, - { .reg_offset = 0, .mask = MAX77686_RTCINT_WTSR_MSK, }, -}; - -static const struct regmap_irq_chip max77686_rtc_irq_chip = { - .name = "max77686-rtc", - .status_base = MAX77686_RTC_INT, - .mask_base = MAX77686_RTC_INTM, - .num_regs = 1, - .irqs = max77686_rtc_irqs, - .num_irqs = ARRAY_SIZE(max77686_rtc_irqs), -}; - static const struct regmap_irq_chip max77802_irq_chip = { .name = "max77802-pmic", .status_base = MAX77802_REG_INT1, @@ -184,15 +158,6 @@ static const struct regmap_irq_chip max77802_irq_chip = { .num_irqs = ARRAY_SIZE(max77686_irqs), }; -static const struct regmap_irq_chip max77802_rtc_irq_chip = { - .name = "max77802-rtc", - .status_base = MAX77802_RTC_INT, - .mask_base = MAX77802_RTC_INTM, - .num_regs = 1, - .irqs = max77686_rtc_irqs, /* same masks as 77686 */ - .num_irqs = ARRAY_SIZE(max77686_rtc_irqs), -}; - static const struct of_device_id max77686_pmic_dt_match[] = { { .compatible = "maxim,max77686", @@ -214,8 +179,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c, int ret = 0; const struct regmap_config *config; const struct regmap_irq_chip *irq_chip; - const struct regmap_irq_chip *rtc_irq_chip; - struct regmap **rtc_regmap; const struct mfd_cell *cells; int n_devs; @@ -242,15 +205,11 @@ static int max77686_i2c_probe(struct i2c_client *i2c, if (max77686->type == TYPE_MAX77686) { config = &max77686_regmap_config; irq_chip = &max77686_irq_chip; - rtc_irq_chip = &max77686_rtc_irq_chip; - rtc_regmap = &max77686->rtc_regmap; cells = max77686_devs; n_devs = ARRAY_SIZE(max77686_devs); } else { config = &max77802_regmap_config; irq_chip = &max77802_irq_chip; - rtc_irq_chip = &max77802_rtc_irq_chip; - rtc_regmap = &max77686->regmap; cells = max77802_devs; n_devs = ARRAY_SIZE(max77802_devs); } @@ -270,59 +229,25 @@ static int max77686_i2c_probe(struct i2c_client *i2c, return -ENODEV; } - if (max77686->type == TYPE_MAX77686) { - max77686->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC); - if (!max77686->rtc) { - dev_err(max77686->dev, - "Failed to allocate I2C device for RTC\n"); - return -ENODEV; - } - - max77686->rtc_regmap = - devm_regmap_init_i2c(max77686->rtc, - &max77686_rtc_regmap_config); - if (IS_ERR(max77686->rtc_regmap)) { - ret = PTR_ERR(max77686->rtc_regmap); - dev_err(max77686->dev, - "failed to allocate RTC regmap: %d\n", - ret); - goto err_unregister_i2c; - } - } - ret = regmap_add_irq_chip(max77686->regmap, max77686->irq, IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED, 0, irq_chip, &max77686->irq_data); - if (ret) { + if (ret < 0) { dev_err(&i2c->dev, "failed to add PMIC irq chip: %d\n", ret); - goto err_unregister_i2c; - } - - ret = regmap_add_irq_chip(*rtc_regmap, max77686->irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT | - IRQF_SHARED, 0, rtc_irq_chip, - &max77686->rtc_irq_data); - if (ret) { - dev_err(&i2c->dev, "failed to add RTC irq chip: %d\n", ret); - goto err_del_irqc; + return ret; } ret = mfd_add_devices(max77686->dev, -1, cells, n_devs, NULL, 0, NULL); if (ret < 0) { dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret); - goto err_del_rtc_irqc; + goto err_del_irqc; } return 0; -err_del_rtc_irqc: - regmap_del_irq_chip(max77686->irq, max77686->rtc_irq_data); err_del_irqc: regmap_del_irq_chip(max77686->irq, max77686->irq_data); -err_unregister_i2c: - if (max77686->type == TYPE_MAX77686) - i2c_unregister_device(max77686->rtc); return ret; } @@ -333,12 +258,8 @@ static int max77686_i2c_remove(struct i2c_client *i2c) mfd_remove_devices(max77686->dev); - regmap_del_irq_chip(max77686->irq, max77686->rtc_irq_data); regmap_del_irq_chip(max77686->irq, max77686->irq_data); - if (max77686->type == TYPE_MAX77686) - i2c_unregister_device(max77686->rtc); - return 0; } diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 8fe1092..5e924f3 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -12,6 +12,7 @@ * */ +#include #include #include #include @@ -22,6 +23,9 @@ #include #include +#define MAX77686_I2C_ADDR_RTC (0x0C >> 1) +#define MAX77686_INVALID_I2C_ADDR (-1) + /* RTC Control Register */ #define BCD_EN_SHIFT 0 #define BCD_EN_MASK BIT(BCD_EN_SHIFT) @@ -68,8 +72,10 @@ struct max77686_rtc_driver_data { const unsigned int *map; /* Has a separate alarm enable register? */ bool alarm_enable_reg; - /* Has a separate I2C regmap for the RTC? */ - bool separate_i2c_addr; + /* I2C address for RTC block */ + int rtc_i2c_addr; + /* RTC IRQ CHIP for regmap */ + const struct regmap_irq_chip *rtc_irq_chip; }; struct max77686_rtc_info { @@ -82,7 +88,9 @@ struct max77686_rtc_info { struct regmap *rtc_regmap; const struct max77686_rtc_driver_data *drv_data; + struct regmap_irq_chip_data *rtc_irq_data; + int rtc_irq; int virq; int rtc_24hr_mode; }; @@ -153,12 +161,32 @@ static const unsigned int max77686_map[REG_RTC_END] = { [REG_RTC_AE1] = REG_RTC_NONE, }; +static const struct regmap_irq max77686_rtc_irqs[] = { + /* RTC interrupts */ + { .reg_offset = 0, .mask = MAX77686_RTCINT_RTC60S_MSK, }, + { .reg_offset = 0, .mask = MAX77686_RTCINT_RTCA1_MSK, }, + { .reg_offset = 0, .mask = MAX77686_RTCINT_RTCA2_MSK, }, + { .reg_offset = 0, .mask = MAX77686_RTCINT_SMPL_MSK, }, + { .reg_offset = 0, .mask = MAX77686_RTCINT_RTC1S_MSK, }, + { .reg_offset = 0, .mask = MAX77686_RTCINT_WTSR_MSK, }, +}; + +static const struct regmap_irq_chip max77686_rtc_irq_chip = { + .name = "max77686-rtc", + .status_base = MAX77686_RTC_INT, + .mask_base = MAX77686_RTC_INTM, + .num_regs = 1, + .irqs = max77686_rtc_irqs, + .num_irqs = ARRAY_SIZE(max77686_rtc_irqs), +}; + static const struct max77686_rtc_driver_data max77686_drv_data = { .delay = 16000, .mask = 0x7f, .map = max77686_map, .alarm_enable_reg = false, - .separate_i2c_addr = true, + .rtc_i2c_addr = MAX77686_I2C_ADDR_RTC, + .rtc_irq_chip = &max77686_rtc_irq_chip, }; static const unsigned int max77802_map[REG_RTC_END] = { @@ -190,12 +218,22 @@ static const unsigned int max77802_map[REG_RTC_END] = { [REG_RTC_AE1] = MAX77802_RTC_AE1, }; +static const struct regmap_irq_chip max77802_rtc_irq_chip = { + .name = "max77802-rtc", + .status_base = MAX77802_RTC_INT, + .mask_base = MAX77802_RTC_INTM, + .num_regs = 1, + .irqs = max77686_rtc_irqs, /* same masks as 77686 */ + .num_irqs = ARRAY_SIZE(max77686_rtc_irqs), +}; + static const struct max77686_rtc_driver_data max77802_drv_data = { .delay = 200, .mask = 0xff, .map = max77802_map, .alarm_enable_reg = true, - .separate_i2c_addr = false, + .rtc_i2c_addr = MAX77686_INVALID_I2C_ADDR, + .rtc_irq_chip = &max77802_rtc_irq_chip, }; static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, @@ -599,9 +637,65 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info) return ret; } +static const struct regmap_config max77686_rtc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int max77686_init_rtc_regmap(struct max77686_rtc_info *info) +{ + struct device *parent = info->dev->parent; + struct i2c_client *parent_i2c = to_i2c_client(parent); + int ret; + + info->rtc_irq = parent_i2c->irq; + + info->regmap = dev_get_regmap(parent, NULL); + if (!info->regmap) { + dev_err(info->dev, "Failed to get rtc regmap\n"); + return -ENODEV; + } + + if (info->drv_data->rtc_i2c_addr == MAX77686_INVALID_I2C_ADDR) { + info->rtc_regmap = info->regmap; + goto add_rtc_irq; + } + + info->rtc = i2c_new_dummy(parent_i2c->adapter, + info->drv_data->rtc_i2c_addr); + if (!info->rtc) { + dev_err(info->dev, "Failed to allocate I2C device for RTC\n"); + return -ENODEV; + } + + info->rtc_regmap = devm_regmap_init_i2c(info->rtc, + &max77686_rtc_regmap_config); + if (IS_ERR(info->rtc_regmap)) { + ret = PTR_ERR(info->rtc_regmap); + dev_err(info->dev, "Failed to allocate RTC regmap: %d\n", ret); + goto err_unregister_i2c; + } + +add_rtc_irq: + ret = regmap_add_irq_chip(info->rtc_regmap, info->rtc_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT | + IRQF_SHARED, 0, info->drv_data->rtc_irq_chip, + &info->rtc_irq_data); + if (ret < 0) { + dev_err(info->dev, "Failed to add RTC irq chip: %d\n", ret); + goto err_unregister_i2c; + } + + return 0; + +err_unregister_i2c: + if (info->rtc) + i2c_unregister_device(info->rtc); + return ret; +} + static int max77686_rtc_probe(struct platform_device *pdev) { - struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent); struct max77686_rtc_info *info; const struct platform_device_id *id = platform_get_device_id(pdev); int ret; @@ -613,18 +707,16 @@ static int max77686_rtc_probe(struct platform_device *pdev) mutex_init(&info->lock); info->dev = &pdev->dev; - info->rtc = max77686->rtc; info->drv_data = (const struct max77686_rtc_driver_data *) id->driver_data; - info->regmap = max77686->regmap; - info->rtc_regmap = (info->drv_data->separate_i2c_addr) ? - max77686->rtc_regmap : info->regmap; + ret = max77686_init_rtc_regmap(info); + if (ret < 0) + return ret; platform_set_drvdata(pdev, info); ret = max77686_rtc_init_reg(info); - if (ret < 0) { dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret); goto err_rtc; @@ -643,30 +735,43 @@ static int max77686_rtc_probe(struct platform_device *pdev) goto err_rtc; } - if (!max77686->rtc_irq_data) { - ret = -EINVAL; - dev_err(&pdev->dev, "No RTC regmap IRQ chip\n"); - goto err_rtc; - } - - info->virq = regmap_irq_get_virq(max77686->rtc_irq_data, + info->virq = regmap_irq_get_virq(info->rtc_irq_data, MAX77686_RTCIRQ_RTCA1); if (info->virq <= 0) { ret = -ENXIO; goto err_rtc; } - ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL, - max77686_rtc_alarm_irq, 0, - "rtc-alarm1", info); - if (ret < 0) + ret = request_threaded_irq(info->virq, NULL, max77686_rtc_alarm_irq, 0, + "rtc-alarm1", info); + if (ret < 0) { dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", info->virq, ret); + goto err_rtc; + } + + return 0; err_rtc: + regmap_del_irq_chip(info->rtc_irq, info->rtc_irq_data); + if (info->rtc) + i2c_unregister_device(info->rtc); + return ret; } +static int max77686_rtc_remove(struct platform_device *pdev) +{ + struct max77686_rtc_info *info = platform_get_drvdata(pdev); + + free_irq(info->virq, info); + regmap_del_irq_chip(info->rtc_irq, info->rtc_irq_data); + if (info->rtc) + i2c_unregister_device(info->rtc); + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int max77686_rtc_suspend(struct device *dev) { @@ -707,6 +812,7 @@ static struct platform_driver max77686_rtc_driver = { .pm = &max77686_rtc_pm_ops, }, .probe = max77686_rtc_probe, + .remove = max77686_rtc_remove, .id_table = rtc_id, }; diff --git a/include/linux/mfd/max77686-private.h b/include/linux/mfd/max77686-private.h index f504349..643dae7 100644 --- a/include/linux/mfd/max77686-private.h +++ b/include/linux/mfd/max77686-private.h @@ -437,14 +437,11 @@ enum max77686_irq { struct max77686_dev { struct device *dev; struct i2c_client *i2c; /* 0xcc / PMIC, Battery Control, and FLASH */ - struct i2c_client *rtc; /* slave addr 0x0c */ unsigned long type; struct regmap *regmap; /* regmap for mfd */ - struct regmap *rtc_regmap; /* regmap for rtc */ struct regmap_irq_chip_data *irq_data; - struct regmap_irq_chip_data *rtc_irq_data; int irq; struct mutex irqlock; -- cgit v0.10.2 From 6c6ff145b3346b071e7d80f9bd33aa7de0e438bc Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 31 Jan 2016 23:10:10 +0900 Subject: rtc: ds1307: add clock provider support for DS3231 DS3231 has programmable square-wave output signal. This enables to use this feature as a clock provider of common clock framework. Signed-off-by: Akinobu Mita Reviewed-by: Michael Turquette Signed-off-by: Alexandre Belloni diff --git a/Documentation/devicetree/bindings/rtc/maxim,ds3231.txt b/Documentation/devicetree/bindings/rtc/maxim,ds3231.txt new file mode 100644 index 0000000..ddef330 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/maxim,ds3231.txt @@ -0,0 +1,37 @@ +* Maxim DS3231 Real Time Clock + +Required properties: +see: Documentation/devicetree/bindings/i2c/trivial-devices.txt + +Optional property: +- #clock-cells: Should be 1. +- clock-output-names: + overwrite the default clock names "ds3231_clk_sqw" and "ds3231_clk_32khz". + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. Following indices are allowed: + - 0: square-wave output on the SQW pin + - 1: square-wave output on the 32kHz pin + +- interrupts: rtc alarm/event interrupt. When this property is selected, + clock on the SQW pin cannot be used. + +Example: + +ds3231: ds3231@51 { + compatible = "maxim,ds3231"; + reg = <0x68>; + #clock-cells = <1>; +}; + +device1 { +... + clocks = <&ds3231 0>; +... +}; + +device2 { +... + clocks = <&ds3231 1>; +... +}; diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 2462d5a..b2156ee 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -21,6 +21,7 @@ #include #include #include +#include /* * We can't determine type by probing, but if we expect pre-Linux code @@ -91,6 +92,7 @@ enum ds_type { # define DS1340_BIT_OSF 0x80 #define DS1337_REG_STATUS 0x0f # define DS1337_BIT_OSF 0x80 +# define DS3231_BIT_EN32KHZ 0x08 # define DS1337_BIT_A2I 0x02 # define DS1337_BIT_A1I 0x01 #define DS1339_REG_ALARM1_SECS 0x07 @@ -120,6 +122,9 @@ struct ds1307 { u8 length, u8 *values); s32 (*write_block_data)(const struct i2c_client *client, u8 command, u8 length, const u8 *values); +#ifdef CONFIG_COMMON_CLK + struct clk_hw clks[2]; +#endif }; struct chip_desc { @@ -926,7 +931,295 @@ static void ds1307_hwmon_register(struct ds1307 *ds1307) { } -#endif +#endif /* CONFIG_RTC_DRV_DS1307_HWMON */ + +/*----------------------------------------------------------------------*/ + +/* + * Square-wave output support for DS3231 + * Datasheet: https://datasheets.maximintegrated.com/en/ds/DS3231.pdf + */ +#ifdef CONFIG_COMMON_CLK + +enum { + DS3231_CLK_SQW = 0, + DS3231_CLK_32KHZ, +}; + +#define clk_sqw_to_ds1307(clk) \ + container_of(clk, struct ds1307, clks[DS3231_CLK_SQW]) +#define clk_32khz_to_ds1307(clk) \ + container_of(clk, struct ds1307, clks[DS3231_CLK_32KHZ]) + +static int ds3231_clk_sqw_rates[] = { + 1, + 1024, + 4096, + 8192, +}; + +static int ds1337_write_control(struct ds1307 *ds1307, u8 mask, u8 value) +{ + struct i2c_client *client = ds1307->client; + struct mutex *lock = &ds1307->rtc->ops_lock; + int control; + int ret; + + mutex_lock(lock); + + control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL); + if (control < 0) { + ret = control; + goto out; + } + + control &= ~mask; + control |= value; + + ret = i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, control); +out: + mutex_unlock(lock); + + return ret; +} + +static unsigned long ds3231_clk_sqw_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); + int control; + int rate_sel = 0; + + control = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_CONTROL); + if (control < 0) + return control; + if (control & DS1337_BIT_RS1) + rate_sel += 1; + if (control & DS1337_BIT_RS2) + rate_sel += 2; + + return ds3231_clk_sqw_rates[rate_sel]; +} + +static long ds3231_clk_sqw_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int i; + + for (i = ARRAY_SIZE(ds3231_clk_sqw_rates) - 1; i >= 0; i--) { + if (ds3231_clk_sqw_rates[i] <= rate) + return ds3231_clk_sqw_rates[i]; + } + + return 0; +} + +static int ds3231_clk_sqw_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); + int control = 0; + int rate_sel; + + for (rate_sel = 0; rate_sel < ARRAY_SIZE(ds3231_clk_sqw_rates); + rate_sel++) { + if (ds3231_clk_sqw_rates[rate_sel] == rate) + break; + } + + if (rate_sel == ARRAY_SIZE(ds3231_clk_sqw_rates)) + return -EINVAL; + + if (rate_sel & 1) + control |= DS1337_BIT_RS1; + if (rate_sel & 2) + control |= DS1337_BIT_RS2; + + return ds1337_write_control(ds1307, DS1337_BIT_RS1 | DS1337_BIT_RS2, + control); +} + +static int ds3231_clk_sqw_prepare(struct clk_hw *hw) +{ + struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); + + return ds1337_write_control(ds1307, DS1337_BIT_INTCN, 0); +} + +static void ds3231_clk_sqw_unprepare(struct clk_hw *hw) +{ + struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); + + ds1337_write_control(ds1307, DS1337_BIT_INTCN, DS1337_BIT_INTCN); +} + +static int ds3231_clk_sqw_is_prepared(struct clk_hw *hw) +{ + struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); + int control; + + control = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_CONTROL); + if (control < 0) + return control; + + return !(control & DS1337_BIT_INTCN); +} + +static const struct clk_ops ds3231_clk_sqw_ops = { + .prepare = ds3231_clk_sqw_prepare, + .unprepare = ds3231_clk_sqw_unprepare, + .is_prepared = ds3231_clk_sqw_is_prepared, + .recalc_rate = ds3231_clk_sqw_recalc_rate, + .round_rate = ds3231_clk_sqw_round_rate, + .set_rate = ds3231_clk_sqw_set_rate, +}; + +static unsigned long ds3231_clk_32khz_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return 32768; +} + +static int ds3231_clk_32khz_control(struct ds1307 *ds1307, bool enable) +{ + struct i2c_client *client = ds1307->client; + struct mutex *lock = &ds1307->rtc->ops_lock; + int status; + int ret; + + mutex_lock(lock); + + status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS); + if (status < 0) { + ret = status; + goto out; + } + + if (enable) + status |= DS3231_BIT_EN32KHZ; + else + status &= ~DS3231_BIT_EN32KHZ; + + ret = i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, status); +out: + mutex_unlock(lock); + + return ret; +} + +static int ds3231_clk_32khz_prepare(struct clk_hw *hw) +{ + struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw); + + return ds3231_clk_32khz_control(ds1307, true); +} + +static void ds3231_clk_32khz_unprepare(struct clk_hw *hw) +{ + struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw); + + ds3231_clk_32khz_control(ds1307, false); +} + +static int ds3231_clk_32khz_is_prepared(struct clk_hw *hw) +{ + struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw); + int status; + + status = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_STATUS); + if (status < 0) + return status; + + return !!(status & DS3231_BIT_EN32KHZ); +} + +static const struct clk_ops ds3231_clk_32khz_ops = { + .prepare = ds3231_clk_32khz_prepare, + .unprepare = ds3231_clk_32khz_unprepare, + .is_prepared = ds3231_clk_32khz_is_prepared, + .recalc_rate = ds3231_clk_32khz_recalc_rate, +}; + +static struct clk_init_data ds3231_clks_init[] = { + [DS3231_CLK_SQW] = { + .name = "ds3231_clk_sqw", + .ops = &ds3231_clk_sqw_ops, + .flags = CLK_IS_ROOT, + }, + [DS3231_CLK_32KHZ] = { + .name = "ds3231_clk_32khz", + .ops = &ds3231_clk_32khz_ops, + .flags = CLK_IS_ROOT, + }, +}; + +static int ds3231_clks_register(struct ds1307 *ds1307) +{ + struct i2c_client *client = ds1307->client; + struct device_node *node = client->dev.of_node; + struct clk_onecell_data *onecell; + int i; + + onecell = devm_kzalloc(&client->dev, sizeof(*onecell), GFP_KERNEL); + if (!onecell) + return -ENOMEM; + + onecell->clk_num = ARRAY_SIZE(ds3231_clks_init); + onecell->clks = devm_kcalloc(&client->dev, onecell->clk_num, + sizeof(onecell->clks[0]), GFP_KERNEL); + if (!onecell->clks) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(ds3231_clks_init); i++) { + struct clk_init_data init = ds3231_clks_init[i]; + + /* + * Interrupt signal due to alarm conditions and square-wave + * output share same pin, so don't initialize both. + */ + if (i == DS3231_CLK_SQW && test_bit(HAS_ALARM, &ds1307->flags)) + continue; + + /* optional override of the clockname */ + of_property_read_string_index(node, "clock-output-names", i, + &init.name); + ds1307->clks[i].init = &init; + + onecell->clks[i] = devm_clk_register(&client->dev, + &ds1307->clks[i]); + if (IS_ERR(onecell->clks[i])) + return PTR_ERR(onecell->clks[i]); + } + + if (!node) + return 0; + + of_clk_add_provider(node, of_clk_src_onecell_get, onecell); + + return 0; +} + +static void ds1307_clks_register(struct ds1307 *ds1307) +{ + int ret; + + if (ds1307->type != ds_3231) + return; + + ret = ds3231_clks_register(ds1307); + if (ret) { + dev_warn(&ds1307->client->dev, + "unable to register clock device %d\n", ret); + } +} + +#else + +static void ds1307_clks_register(struct ds1307 *ds1307) +{ +} + +#endif /* CONFIG_COMMON_CLK */ static int ds1307_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -1294,6 +1587,7 @@ read_rtc: } ds1307_hwmon_register(ds1307); + ds1307_clks_register(ds1307); return 0; -- cgit v0.10.2 From 125e550fd2573ed114076f7e0d7e9834e6cb0734 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 2 Feb 2016 20:56:10 +0100 Subject: rtc: add Alphascale asm9260 driver Add support for RTC controller found on Alphascale asm9260 SoC. Signed-off-by: Oleksij Rempel Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2cf87f7..f8a67e7 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1152,6 +1152,16 @@ config RTC_DRV_ZYNQMP comment "on-CPU RTC drivers" +config RTC_DRV_ASM9260 + tristate "Alphascale asm9260 RTC" + depends on MACH_ASM9260 + help + If you say yes here you get support for the RTC on the + Alphascale asm9260 SoC. + + This driver can also be built as a module. If so, the module + will be called rtc-asm9260. + config RTC_DRV_DAVINCI tristate "TI DaVinci RTC" depends on ARCH_DAVINCI_DM365 diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index c8a2147..c1c9a18 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o obj-$(CONFIG_RTC_DRV_ABX80X) += rtc-abx80x.o obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o +obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o diff --git a/drivers/rtc/rtc-asm9260.c b/drivers/rtc/rtc-asm9260.c new file mode 100644 index 0000000..14e08c4 --- /dev/null +++ b/drivers/rtc/rtc-asm9260.c @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2016 Oleksij Rempel + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Miscellaneous registers */ +/* Interrupt Location Register */ +#define HW_ILR 0x00 +#define BM_RTCALF BIT(1) +#define BM_RTCCIF BIT(0) + +/* Clock Control Register */ +#define HW_CCR 0x08 +/* Calibration counter disable */ +#define BM_CCALOFF BIT(4) +/* Reset internal oscillator divider */ +#define BM_CTCRST BIT(1) +/* Clock Enable */ +#define BM_CLKEN BIT(0) + +/* Counter Increment Interrupt Register */ +#define HW_CIIR 0x0C +#define BM_CIIR_IMYEAR BIT(7) +#define BM_CIIR_IMMON BIT(6) +#define BM_CIIR_IMDOY BIT(5) +#define BM_CIIR_IMDOW BIT(4) +#define BM_CIIR_IMDOM BIT(3) +#define BM_CIIR_IMHOUR BIT(2) +#define BM_CIIR_IMMIN BIT(1) +#define BM_CIIR_IMSEC BIT(0) + +/* Alarm Mask Register */ +#define HW_AMR 0x10 +#define BM_AMR_IMYEAR BIT(7) +#define BM_AMR_IMMON BIT(6) +#define BM_AMR_IMDOY BIT(5) +#define BM_AMR_IMDOW BIT(4) +#define BM_AMR_IMDOM BIT(3) +#define BM_AMR_IMHOUR BIT(2) +#define BM_AMR_IMMIN BIT(1) +#define BM_AMR_IMSEC BIT(0) +#define BM_AMR_OFF 0xff + +/* Consolidated time registers */ +#define HW_CTIME0 0x14 +#define BM_CTIME0_DOW_S 24 +#define BM_CTIME0_DOW_M 0x7 +#define BM_CTIME0_HOUR_S 16 +#define BM_CTIME0_HOUR_M 0x1f +#define BM_CTIME0_MIN_S 8 +#define BM_CTIME0_MIN_M 0x3f +#define BM_CTIME0_SEC_S 0 +#define BM_CTIME0_SEC_M 0x3f + +#define HW_CTIME1 0x18 +#define BM_CTIME1_YEAR_S 16 +#define BM_CTIME1_YEAR_M 0xfff +#define BM_CTIME1_MON_S 8 +#define BM_CTIME1_MON_M 0xf +#define BM_CTIME1_DOM_S 0 +#define BM_CTIME1_DOM_M 0x1f + +#define HW_CTIME2 0x1C +#define BM_CTIME2_DOY_S 0 +#define BM_CTIME2_DOY_M 0xfff + +/* Time counter registers */ +#define HW_SEC 0x20 +#define HW_MIN 0x24 +#define HW_HOUR 0x28 +#define HW_DOM 0x2C +#define HW_DOW 0x30 +#define HW_DOY 0x34 +#define HW_MONTH 0x38 +#define HW_YEAR 0x3C + +#define HW_CALIBRATION 0x40 +#define BM_CALDIR_BACK BIT(17) +#define BM_CALVAL_M 0x1ffff + +/* General purpose registers */ +#define HW_GPREG0 0x44 +#define HW_GPREG1 0x48 +#define HW_GPREG2 0x4C +#define HW_GPREG3 0x50 +#define HW_GPREG4 0x54 + +/* Alarm register group */ +#define HW_ALSEC 0x60 +#define HW_ALMIN 0x64 +#define HW_ALHOUR 0x68 +#define HW_ALDOM 0x6C +#define HW_ALDOW 0x70 +#define HW_ALDOY 0x74 +#define HW_ALMON 0x78 +#define HW_ALYEAR 0x7C + +struct asm9260_rtc_priv { + struct device *dev; + void __iomem *iobase; + struct rtc_device *rtc; + struct clk *clk; + /* io lock */ + spinlock_t lock; +}; + +static irqreturn_t asm9260_rtc_irq(int irq, void *dev_id) +{ + struct asm9260_rtc_priv *priv = dev_id; + u32 isr; + unsigned long events = 0; + + isr = ioread32(priv->iobase + HW_CIIR); + if (!isr) + return IRQ_NONE; + + iowrite32(0, priv->iobase + HW_CIIR); + + events |= RTC_AF | RTC_IRQF; + + rtc_update_irq(priv->rtc, 1, events); + + return IRQ_HANDLED; +} + +static int asm9260_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct asm9260_rtc_priv *priv = dev_get_drvdata(dev); + u32 ctime0, ctime1, ctime2; + unsigned long irq_flags; + + spin_lock_irqsave(&priv->lock, irq_flags); + ctime0 = ioread32(priv->iobase + HW_CTIME0); + ctime1 = ioread32(priv->iobase + HW_CTIME1); + ctime2 = ioread32(priv->iobase + HW_CTIME2); + + if (ctime1 != ioread32(priv->iobase + HW_CTIME1)) { + /* + * woops, counter flipped right now. Now we are safe + * to reread. + */ + ctime0 = ioread32(priv->iobase + HW_CTIME0); + ctime1 = ioread32(priv->iobase + HW_CTIME1); + ctime2 = ioread32(priv->iobase + HW_CTIME2); + } + spin_unlock_irqrestore(&priv->lock, irq_flags); + + tm->tm_sec = (ctime0 >> BM_CTIME0_SEC_S) & BM_CTIME0_SEC_M; + tm->tm_min = (ctime0 >> BM_CTIME0_MIN_S) & BM_CTIME0_MIN_M; + tm->tm_hour = (ctime0 >> BM_CTIME0_HOUR_S) & BM_CTIME0_HOUR_M; + tm->tm_wday = (ctime0 >> BM_CTIME0_DOW_S) & BM_CTIME0_DOW_M; + + tm->tm_mday = (ctime1 >> BM_CTIME1_DOM_S) & BM_CTIME1_DOM_M; + tm->tm_mon = (ctime1 >> BM_CTIME1_MON_S) & BM_CTIME1_MON_M; + tm->tm_year = (ctime1 >> BM_CTIME1_YEAR_S) & BM_CTIME1_YEAR_M; + + tm->tm_yday = (ctime2 >> BM_CTIME2_DOY_S) & BM_CTIME2_DOY_M; + + return 0; +} + +static int asm9260_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct asm9260_rtc_priv *priv = dev_get_drvdata(dev); + unsigned long irq_flags; + + spin_lock_irqsave(&priv->lock, irq_flags); + /* + * make sure SEC counter will not flip other counter on write time, + * real value will be written at the enf of sequence. + */ + iowrite32(0, priv->iobase + HW_SEC); + + iowrite32(tm->tm_year, priv->iobase + HW_YEAR); + iowrite32(tm->tm_mon, priv->iobase + HW_MONTH); + iowrite32(tm->tm_mday, priv->iobase + HW_DOM); + iowrite32(tm->tm_wday, priv->iobase + HW_DOW); + iowrite32(tm->tm_yday, priv->iobase + HW_DOY); + iowrite32(tm->tm_hour, priv->iobase + HW_HOUR); + iowrite32(tm->tm_min, priv->iobase + HW_MIN); + iowrite32(tm->tm_sec, priv->iobase + HW_SEC); + spin_unlock_irqrestore(&priv->lock, irq_flags); + + return 0; +} + +static int asm9260_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct asm9260_rtc_priv *priv = dev_get_drvdata(dev); + unsigned long irq_flags; + + spin_lock_irqsave(&priv->lock, irq_flags); + alrm->time.tm_year = ioread32(priv->iobase + HW_ALYEAR); + alrm->time.tm_mon = ioread32(priv->iobase + HW_ALMON); + alrm->time.tm_mday = ioread32(priv->iobase + HW_ALDOM); + alrm->time.tm_wday = ioread32(priv->iobase + HW_ALDOW); + alrm->time.tm_yday = ioread32(priv->iobase + HW_ALDOY); + alrm->time.tm_hour = ioread32(priv->iobase + HW_ALHOUR); + alrm->time.tm_min = ioread32(priv->iobase + HW_ALMIN); + alrm->time.tm_sec = ioread32(priv->iobase + HW_ALSEC); + + alrm->enabled = ioread32(priv->iobase + HW_AMR) ? 1 : 0; + alrm->pending = ioread32(priv->iobase + HW_CIIR) ? 1 : 0; + spin_unlock_irqrestore(&priv->lock, irq_flags); + + return rtc_valid_tm(&alrm->time); +} + +static int asm9260_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct asm9260_rtc_priv *priv = dev_get_drvdata(dev); + unsigned long irq_flags; + + spin_lock_irqsave(&priv->lock, irq_flags); + iowrite32(alrm->time.tm_year, priv->iobase + HW_ALYEAR); + iowrite32(alrm->time.tm_mon, priv->iobase + HW_ALMON); + iowrite32(alrm->time.tm_mday, priv->iobase + HW_ALDOM); + iowrite32(alrm->time.tm_wday, priv->iobase + HW_ALDOW); + iowrite32(alrm->time.tm_yday, priv->iobase + HW_ALDOY); + iowrite32(alrm->time.tm_hour, priv->iobase + HW_ALHOUR); + iowrite32(alrm->time.tm_min, priv->iobase + HW_ALMIN); + iowrite32(alrm->time.tm_sec, priv->iobase + HW_ALSEC); + + iowrite32(alrm->enabled ? 0 : BM_AMR_OFF, priv->iobase + HW_AMR); + spin_unlock_irqrestore(&priv->lock, irq_flags); + + return 0; +} + +static int asm9260_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct asm9260_rtc_priv *priv = dev_get_drvdata(dev); + + iowrite32(enabled ? 0 : BM_AMR_OFF, priv->iobase + HW_AMR); + return 0; +} + +static const struct rtc_class_ops asm9260_rtc_ops = { + .read_time = asm9260_rtc_read_time, + .set_time = asm9260_rtc_set_time, + .read_alarm = asm9260_rtc_read_alarm, + .set_alarm = asm9260_rtc_set_alarm, + .alarm_irq_enable = asm9260_alarm_irq_enable, +}; + +static int __init asm9260_rtc_probe(struct platform_device *pdev) +{ + struct asm9260_rtc_priv *priv; + struct device *dev = &pdev->dev; + struct resource *res; + int irq_alarm, ret; + u32 ccr; + + priv = devm_kzalloc(dev, sizeof(struct asm9260_rtc_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + platform_set_drvdata(pdev, priv); + + irq_alarm = platform_get_irq(pdev, 0); + if (irq_alarm < 0) { + dev_err(dev, "No alarm IRQ resource defined\n"); + return irq_alarm; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->iobase = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->iobase)) + return PTR_ERR(priv->iobase); + + priv->clk = devm_clk_get(dev, "ahb"); + ret = clk_prepare_enable(priv->clk); + if (ret) { + dev_err(dev, "Failed to enable clk!\n"); + return ret; + } + + ccr = ioread32(priv->iobase + HW_CCR); + /* if dev is not enabled, reset it */ + if ((ccr & (BM_CLKEN | BM_CTCRST)) != BM_CLKEN) { + iowrite32(BM_CTCRST, priv->iobase + HW_CCR); + ccr = 0; + } + + iowrite32(BM_CLKEN | ccr, priv->iobase + HW_CCR); + iowrite32(0, priv->iobase + HW_CIIR); + iowrite32(BM_AMR_OFF, priv->iobase + HW_AMR); + + priv->rtc = devm_rtc_device_register(dev, dev_name(dev), + &asm9260_rtc_ops, THIS_MODULE); + if (IS_ERR(priv->rtc)) { + ret = PTR_ERR(priv->rtc); + dev_err(dev, "Failed to register RTC device: %d\n", ret); + goto err_return; + } + + ret = devm_request_threaded_irq(dev, irq_alarm, NULL, + asm9260_rtc_irq, IRQF_ONESHOT, + dev_name(dev), priv); + if (ret < 0) { + dev_err(dev, "can't get irq %i, err %d\n", + irq_alarm, ret); + goto err_return; + } + + return 0; + +err_return: + clk_disable_unprepare(priv->clk); + return ret; +} + +static int __exit asm9260_rtc_remove(struct platform_device *pdev) +{ + struct asm9260_rtc_priv *priv = platform_get_drvdata(pdev); + + /* Disable alarm matching */ + iowrite32(BM_AMR_OFF, priv->iobase + HW_AMR); + clk_disable_unprepare(priv->clk); + return 0; +} + +static const struct of_device_id asm9260_dt_ids[] = { + { .compatible = "alphascale,asm9260-rtc", }, + {} +}; + +static struct platform_driver asm9260_rtc_driver = { + .probe = asm9260_rtc_probe, + .remove = asm9260_rtc_remove, + .driver = { + .name = "asm9260-rtc", + .owner = THIS_MODULE, + .of_match_table = asm9260_dt_ids, + }, +}; + +module_platform_driver(asm9260_rtc_driver); + +MODULE_AUTHOR("Oleksij Rempel "); +MODULE_DESCRIPTION("Alphascale asm9260 SoC Realtime Clock Driver (RTC)"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 7444845b084d7785a2581ba5292aa8adbc1fd439 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 2 Feb 2016 20:56:11 +0100 Subject: doc: dt: add documentation for alphascale,asm9260-rtc Document Alphascale asm9260 RTC bindings Signed-off-by: Oleksij Rempel Acked-by: Rob Herring Signed-off-by: Alexandre Belloni diff --git a/Documentation/devicetree/bindings/rtc/alphascale,asm9260-rtc.txt b/Documentation/devicetree/bindings/rtc/alphascale,asm9260-rtc.txt new file mode 100644 index 0000000..76ebca5 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/alphascale,asm9260-rtc.txt @@ -0,0 +1,19 @@ +* Alphascale asm9260 SoC Real Time Clock + +Required properties: +- compatible: Should be "alphascale,asm9260-rtc" +- reg: Physical base address of the controller and length + of memory mapped region. +- interrupts: IRQ line for the RTC. +- clocks: Reference to the clock entry. +- clock-names: should contain: + * "ahb" for the SoC RTC clock + +Example: +rtc0: rtc@800a0000 { + compatible = "alphascale,asm9260-rtc"; + reg = <0x800a0000 0x100>; + clocks = <&acc CLKID_AHB_RTC>; + clock-names = "ahb"; + interrupts = <2>; +}; -- cgit v0.10.2 From 9d1fa4c3737ac82520931d940dcd2426719f8dd2 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 4 Feb 2016 13:45:20 +0100 Subject: rtc: rv8803: convert spin_lock to mutex_lock Fix a scheduling while atomic issue caused by rv8803_set_time() holding a spinlock during the call to i2c_smbus_read_byte_data(). Signed-off-by: Oleksij Rempel Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index 7155c08..8d9f35c 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -52,7 +52,7 @@ struct rv8803_data { struct i2c_client *client; struct rtc_device *rtc; - spinlock_t flags_lock; + struct mutex flags_lock; u8 ctrl; }; @@ -63,11 +63,11 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id) unsigned long events = 0; int flags; - spin_lock(&rv8803->flags_lock); + mutex_lock(&rv8803->flags_lock); flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); if (flags <= 0) { - spin_unlock(&rv8803->flags_lock); + mutex_unlock(&rv8803->flags_lock); return IRQ_NONE; } @@ -102,7 +102,7 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id) rv8803->ctrl); } - spin_unlock(&rv8803->flags_lock); + mutex_unlock(&rv8803->flags_lock); return IRQ_HANDLED; } @@ -155,7 +155,6 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm) struct rv8803_data *rv8803 = dev_get_drvdata(dev); u8 date[7]; int flags, ret; - unsigned long irqflags; if ((tm->tm_year < 100) || (tm->tm_year > 199)) return -EINVAL; @@ -173,18 +172,18 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm) if (ret < 0) return ret; - spin_lock_irqsave(&rv8803->flags_lock, irqflags); + mutex_lock(&rv8803->flags_lock); flags = i2c_smbus_read_byte_data(rv8803->client, RV8803_FLAG); if (flags < 0) { - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); return flags; } ret = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG, flags & ~RV8803_FLAG_V2F); - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); return ret; } @@ -226,7 +225,6 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) u8 alarmvals[3]; u8 ctrl[2]; int ret, err; - unsigned long irqflags; /* The alarm has no seconds, round up to nearest minute */ if (alrm->time.tm_sec) { @@ -236,11 +234,11 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) rtc_time64_to_tm(alarm_time, &alrm->time); } - spin_lock_irqsave(&rv8803->flags_lock, irqflags); + mutex_lock(&rv8803->flags_lock); ret = i2c_smbus_read_i2c_block_data(client, RV8803_FLAG, 2, ctrl); if (ret != 2) { - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); return ret < 0 ? ret : -EIO; } @@ -253,14 +251,14 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) err = i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL, rv8803->ctrl); if (err) { - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); return err; } } ctrl[1] &= ~RV8803_FLAG_AF; err = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG, ctrl[1]); - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); if (err) return err; @@ -289,7 +287,6 @@ static int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled) struct i2c_client *client = to_i2c_client(dev); struct rv8803_data *rv8803 = dev_get_drvdata(dev); int ctrl, flags, err; - unsigned long irqflags; ctrl = rv8803->ctrl; @@ -305,15 +302,15 @@ static int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled) ctrl &= ~RV8803_CTRL_AIE; } - spin_lock_irqsave(&rv8803->flags_lock, irqflags); + mutex_lock(&rv8803->flags_lock); flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); if (flags < 0) { - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); return flags; } flags &= ~(RV8803_FLAG_AF | RV8803_FLAG_UF); err = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags); - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); if (err) return err; @@ -333,7 +330,6 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) struct i2c_client *client = to_i2c_client(dev); struct rv8803_data *rv8803 = dev_get_drvdata(dev); int flags, ret = 0; - unsigned long irqflags; switch (cmd) { case RTC_VL_READ: @@ -355,16 +351,16 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) return 0; case RTC_VL_CLR: - spin_lock_irqsave(&rv8803->flags_lock, irqflags); + mutex_lock(&rv8803->flags_lock); flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); if (flags < 0) { - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); return flags; } flags &= ~(RV8803_FLAG_V1F | RV8803_FLAG_V2F); ret = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags); - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); if (ret < 0) return ret; @@ -441,6 +437,7 @@ static int rv8803_probe(struct i2c_client *client, if (!rv8803) return -ENOMEM; + mutex_init(&rv8803->flags_lock); rv8803->client = client; i2c_set_clientdata(client, rv8803); -- cgit v0.10.2 From b3967067c273359c7462f4be9a887c3d1a515f49 Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Fri, 5 Feb 2016 12:41:11 -0800 Subject: rtc: Add functions to set and read rtc offset A number of rtc devices, such as the NXP pcf2123 include a facility to adjust the clock in order to compensate for temperature or a crystal, capacitor, etc, that results in the rtc clock not running at exactly 32.768 kHz. Data sheets I have seen refer to this as a clock offset, and measure it in parts per million, however they often reference ppm to 2 digits of precision, which makes integer ppm less than ideal. We use parts per billion, which more than covers the precision needed and works nicely within 32 bits Signed-off-by: Joshua Clayton Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 5836751..9ef5f6f 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -939,4 +939,58 @@ void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer) mutex_unlock(&rtc->ops_lock); } +/** + * rtc_read_offset - Read the amount of rtc offset in parts per billion + * @ rtc: rtc device to be used + * @ offset: the offset in parts per billion + * + * see below for details. + * + * Kernel interface to read rtc clock offset + * Returns 0 on success, or a negative number on error. + * If read_offset() is not implemented for the rtc, return -EINVAL + */ +int rtc_read_offset(struct rtc_device *rtc, long *offset) +{ + int ret; + + if (!rtc->ops) + return -ENODEV; + + if (!rtc->ops->read_offset) + return -EINVAL; + + mutex_lock(&rtc->ops_lock); + ret = rtc->ops->read_offset(rtc->dev.parent, offset); + mutex_unlock(&rtc->ops_lock); + return ret; +} +/** + * rtc_set_offset - Adjusts the duration of the average second + * @ rtc: rtc device to be used + * @ offset: the offset in parts per billion + * + * Some rtc's allow an adjustment to the average duration of a second + * to compensate for differences in the actual clock rate due to temperature, + * the crystal, capacitor, etc. + * + * Kernel interface to adjust an rtc clock offset. + * Return 0 on success, or a negative number on error. + * If the rtc offset is not setable (or not implemented), return -EINVAL + */ +int rtc_set_offset(struct rtc_device *rtc, long offset) +{ + int ret; + + if (!rtc->ops) + return -ENODEV; + + if (!rtc->ops->set_offset) + return -EINVAL; + + mutex_lock(&rtc->ops_lock); + ret = rtc->ops->set_offset(rtc->dev.parent, offset); + mutex_unlock(&rtc->ops_lock); + return ret; +} diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 3359f04..b693ada 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -89,6 +89,8 @@ struct rtc_class_ops { int (*set_mmss)(struct device *, unsigned long secs); int (*read_callback)(struct device *, int data); int (*alarm_irq_enable)(struct device *, unsigned int enabled); + int (*read_offset)(struct device *, long *offset); + int (*set_offset)(struct device *, long offset); }; #define RTC_DEVICE_NAME_SIZE 20 @@ -208,6 +210,8 @@ void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data); int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer, ktime_t expires, ktime_t period); void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer); +int rtc_read_offset(struct rtc_device *rtc, long *offset); +int rtc_set_offset(struct rtc_device *rtc, long offset); void rtc_timer_do_work(struct work_struct *work); static inline bool is_leap_year(unsigned int year) -- cgit v0.10.2 From 5495a4159f7413f0367e8c9727ba9facd40ade7f Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Fri, 5 Feb 2016 12:41:12 -0800 Subject: rtc: implement a sysfs interface for clock offset clock offset may be set and read in decimal parts per billion attribute is /sys/class/rtc/rtcN/offset The attribute is only visible for rtcs that have set_offset implemented. Signed-off-by: Joshua Clayton Signed-off-by: Alexandre Belloni diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt index 8446f1e..ddc3660 100644 --- a/Documentation/rtc.txt +++ b/Documentation/rtc.txt @@ -157,6 +157,12 @@ wakealarm: The time at which the clock will generate a system wakeup the epoch by default, or if there's a leading +, seconds in the future, or if there is a leading +=, seconds ahead of the current alarm. +offset: The amount which the rtc clock has been adjusted in firmware. + Visible only if the driver supports clock offset adjustment. + The unit is parts per billion, i.e. The number of clock ticks + which are added to or removed from the rtc's base clock per + billion ticks. A positive value makes a day pass more slowly, + longer, and a negative value makes a day pass more quickly. IOCTL INTERFACE --------------- diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 463e286..63b9fb1 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -218,6 +218,34 @@ wakealarm_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RW(wakealarm); +static ssize_t +offset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t retval; + long offset; + + retval = rtc_read_offset(to_rtc_device(dev), &offset); + if (retval == 0) + retval = sprintf(buf, "%ld\n", offset); + + return retval; +} + +static ssize_t +offset_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + ssize_t retval; + long offset; + + retval = kstrtol(buf, 10, &offset); + if (retval == 0) + retval = rtc_set_offset(to_rtc_device(dev), offset); + + return (retval < 0) ? retval : n; +} +static DEVICE_ATTR_RW(offset); + static struct attribute *rtc_attrs[] = { &dev_attr_name.attr, &dev_attr_date.attr, @@ -226,6 +254,7 @@ static struct attribute *rtc_attrs[] = { &dev_attr_max_user_freq.attr, &dev_attr_hctosys.attr, &dev_attr_wakealarm.attr, + &dev_attr_offset.attr, NULL, }; @@ -249,9 +278,13 @@ static umode_t rtc_attr_is_visible(struct kobject *kobj, struct rtc_device *rtc = to_rtc_device(dev); umode_t mode = attr->mode; - if (attr == &dev_attr_wakealarm.attr) + if (attr == &dev_attr_wakealarm.attr) { if (!rtc_does_wakealarm(rtc)) mode = 0; + } else if (attr == &dev_attr_offset.attr) { + if (!rtc->ops->set_offset) + mode = 0; + } return mode; } -- cgit v0.10.2 From bae2f647025549fd2a24f02e9587481a50c0066b Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Fri, 5 Feb 2016 12:41:13 -0800 Subject: rtc: pcf2123: implement read_offset and set_offset pcf2123 has an offset register, which can be used to make minor adjustments to the clock rate to compensate for temperature or a crystal that is not exactly right. Signed-off-by: Joshua Clayton Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index d9a44ad..da27738 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -100,6 +100,7 @@ /* PCF2123_REG_OFFSET BITS */ #define OFFSET_SIGN_BIT BIT(6) /* 2's complement sign bit */ #define OFFSET_COARSE BIT(7) /* Coarse mode offset */ +#define OFFSET_STEP (2170) /* Offset step in parts per billion */ /* READ/WRITE ADDRESS BITS */ #define PCF2123_WRITE BIT(4) @@ -206,6 +207,59 @@ static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr, return count; } +static int pcf2123_read_offset(struct device *dev, long *offset) +{ + int ret; + s8 reg; + + ret = pcf2123_read(dev, PCF2123_REG_OFFSET, ®, 1); + if (ret < 0) + return ret; + + if (reg & OFFSET_COARSE) + reg <<= 1; /* multiply by 2 and sign extend */ + else + reg |= (reg & OFFSET_SIGN_BIT) << 1; /* sign extend only */ + + *offset = ((long)reg) * OFFSET_STEP; + + return 0; +} + +/* + * The offset register is a 7 bit signed value with a coarse bit in bit 7. + * The main difference between the two is normal offset adjusts the first + * second of n minutes every other hour, with 61, 62 and 63 being shoved + * into the 60th minute. + * The coarse adjustment does the same, but every hour. + * the two overlap, with every even normal offset value corresponding + * to a coarse offset. Based on this algorithm, it seems that despite the + * name, coarse offset is a better fit for overlapping values. + */ +static int pcf2123_set_offset(struct device *dev, long offset) +{ + s8 reg; + + if (offset > OFFSET_STEP * 127) + reg = 127; + else if (offset < OFFSET_STEP * -128) + reg = -128; + else + reg = (s8)((offset + (OFFSET_STEP >> 1)) / OFFSET_STEP); + + /* choose fine offset only for odd values in the normal range */ + if (reg & 1 && reg <= 63 && reg >= -64) { + /* Normal offset. Clear the coarse bit */ + reg &= ~OFFSET_COARSE; + } else { + /* Coarse offset. Divide by 2 and set the coarse bit */ + reg >>= 1; + reg |= OFFSET_COARSE; + } + + return pcf2123_write_reg(dev, PCF2123_REG_OFFSET, reg); +} + static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm) { u8 rxbuf[7]; @@ -314,6 +368,9 @@ static int pcf2123_reset(struct device *dev) static const struct rtc_class_ops pcf2123_rtc_ops = { .read_time = pcf2123_rtc_read_time, .set_time = pcf2123_rtc_set_time, + .read_offset = pcf2123_read_offset, + .set_offset = pcf2123_set_offset, + }; static int pcf2123_probe(struct spi_device *spi) -- cgit v0.10.2 From 7b5768486a910532885f01b9d2dad4818c8b3be1 Mon Sep 17 00:00:00 2001 From: Juergen Borleis Date: Tue, 9 Feb 2016 11:57:25 +0100 Subject: rtc: pcf85063: simplify code to read the current time By using i2c_smbus_read_i2c_block_data() the code is now much simpler. While at it: when reading the RTC's seconds register, all time/date registers are frozen until the RTC's year register is read. So it is important to read all time/date registers in one turn to not lose a second event. Make it more clear why the read must happen in this way. Signed-off-by: Juergen Borleis Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 63334cb..7f9caee 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -45,39 +45,34 @@ struct pcf85063 { */ static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm) { + int rc; struct pcf85063 *pcf85063 = i2c_get_clientdata(client); - unsigned char buf[13] = { PCF85063_REG_CTRL1 }; - struct i2c_msg msgs[] = { - {/* setup read ptr */ - .addr = client->addr, - .len = 1, - .buf = buf - }, - {/* read status + date */ - .addr = client->addr, - .flags = I2C_M_RD, - .len = 13, - .buf = buf - }, - }; - - /* read registers */ - if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __func__); + u8 regs[7]; + + /* + * while reading, the time/date registers are blocked and not updated + * anymore until the access is finished. To not lose a second + * event, the access must be finished within one second. So, read all + * time/date registers in one turn. + */ + rc = i2c_smbus_read_i2c_block_data(client, PCF85063_REG_SC, + sizeof(regs), regs); + if (rc != sizeof(regs)) { + dev_err(&client->dev, "date/time register read error\n"); return -EIO; } - tm->tm_sec = bcd2bin(buf[PCF85063_REG_SC] & 0x7F); - tm->tm_min = bcd2bin(buf[PCF85063_REG_MN] & 0x7F); - tm->tm_hour = bcd2bin(buf[PCF85063_REG_HR] & 0x3F); /* rtc hr 0-23 */ - tm->tm_mday = bcd2bin(buf[PCF85063_REG_DM] & 0x3F); - tm->tm_wday = buf[PCF85063_REG_DW] & 0x07; - tm->tm_mon = bcd2bin(buf[PCF85063_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ - tm->tm_year = bcd2bin(buf[PCF85063_REG_YR]); + tm->tm_sec = bcd2bin(regs[0] & 0x7F); + tm->tm_min = bcd2bin(regs[1] & 0x7F); + tm->tm_hour = bcd2bin(regs[2] & 0x3F); /* rtc hr 0-23 */ + tm->tm_mday = bcd2bin(regs[3] & 0x3F); + tm->tm_wday = regs[4] & 0x07; + tm->tm_mon = bcd2bin(regs[5] & 0x1F) - 1; /* rtc mn 1-12 */ + tm->tm_year = bcd2bin(regs[6]); if (tm->tm_year < 70) tm->tm_year += 100; /* assume we are in 1970...2069 */ /* detect the polarity heuristically. see note above. */ - pcf85063->c_polarity = (buf[PCF85063_REG_MO] & PCF85063_MO_C) ? + pcf85063->c_polarity = (regs[5] & PCF85063_MO_C) ? (tm->tm_year >= 100) : (tm->tm_year < 100); return rtc_valid_tm(tm); -- cgit v0.10.2 From 6cc4c8b1e3790c63b2e1b6d9b25d2bda6e406572 Mon Sep 17 00:00:00 2001 From: Juergen Borleis Date: Tue, 9 Feb 2016 11:57:26 +0100 Subject: rtc: pcf85063: fix time/date reading Check if the RTC signals an invalid time/date (due to a battery power loss for example). In this case ignore the time/date until it is really set again. Signed-off-by: Juergen Borleis Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 7f9caee..e0343e6 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -22,6 +22,7 @@ #define PCF85063_REG_CTRL2 0x01 #define PCF85063_REG_SC 0x04 /* datetime */ +#define PCF85063_REG_SC_OS 0x80 #define PCF85063_REG_MN 0x05 #define PCF85063_REG_HR 0x06 #define PCF85063_REG_DM 0x07 @@ -62,6 +63,12 @@ static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm) return -EIO; } + /* if the clock has lost its power it makes no sense to use its time */ + if (regs[0] & PCF85063_REG_SC_OS) { + dev_warn(&client->dev, "Power loss detected, invalid time\n"); + return -EINVAL; + } + tm->tm_sec = bcd2bin(regs[0] & 0x7F); tm->tm_min = bcd2bin(regs[1] & 0x7F); tm->tm_hour = bcd2bin(regs[2] & 0x3F); /* rtc hr 0-23 */ -- cgit v0.10.2 From 31d4d33ef431364972f4a38401f660a2ec935cde Mon Sep 17 00:00:00 2001 From: Juergen Borleis Date: Tue, 9 Feb 2016 11:57:27 +0100 Subject: rtc: pcf85063: fix time/date setting When setting a new time/date the RTC's clock must be stopped first, in order to write the time/date registers in an atomic manner. So, this change stops the clock first and then writes the time/date registers and the clock control register (to re-enable the clock) in one turn. Signed-off-by: Juergen Borleis Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index e0343e6..c5db231 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -19,6 +19,7 @@ #define DRV_VERSION "0.0.1" #define PCF85063_REG_CTRL1 0x00 /* status */ +#define PCF85063_REG_CTRL1_STOP BIT(5) #define PCF85063_REG_CTRL2 0x01 #define PCF85063_REG_SC 0x04 /* datetime */ @@ -40,6 +41,30 @@ struct pcf85063 { int voltage_low; /* indicates if a low_voltage was detected */ }; +static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1) +{ + s32 ret; + + ret = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1); + if (ret < 0) { + dev_err(&client->dev, "Failing to stop the clock\n"); + return -EIO; + } + + /* stop the clock */ + ret |= PCF85063_REG_CTRL1_STOP; + + ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ret); + if (ret < 0) { + dev_err(&client->dev, "Failing to stop the clock\n"); + return -EIO; + } + + *ctrl1 = ret; + + return 0; +} + /* * In the routines that deal directly with the pcf85063 hardware, we use * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. @@ -87,41 +112,48 @@ static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm) static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm) { - int i = 0, err = 0; - unsigned char buf[11]; + int rc; + u8 regs[8]; - /* Control & status */ - buf[PCF85063_REG_CTRL1] = 0; - buf[PCF85063_REG_CTRL2] = 5; + /* + * to accurately set the time, reset the divider chain and keep it in + * reset state until all time/date registers are written + */ + rc = pcf85063_stop_clock(client, ®s[7]); + if (rc != 0) + return rc; /* hours, minutes and seconds */ - buf[PCF85063_REG_SC] = bin2bcd(tm->tm_sec) & 0x7F; + regs[0] = bin2bcd(tm->tm_sec) & 0x7F; /* clear OS flag */ - buf[PCF85063_REG_MN] = bin2bcd(tm->tm_min); - buf[PCF85063_REG_HR] = bin2bcd(tm->tm_hour); + regs[1] = bin2bcd(tm->tm_min); + regs[2] = bin2bcd(tm->tm_hour); /* Day of month, 1 - 31 */ - buf[PCF85063_REG_DM] = bin2bcd(tm->tm_mday); + regs[3] = bin2bcd(tm->tm_mday); /* Day, 0 - 6 */ - buf[PCF85063_REG_DW] = tm->tm_wday & 0x07; + regs[4] = tm->tm_wday & 0x07; /* month, 1 - 12 */ - buf[PCF85063_REG_MO] = bin2bcd(tm->tm_mon + 1); + regs[5] = bin2bcd(tm->tm_mon + 1); /* year and century */ - buf[PCF85063_REG_YR] = bin2bcd(tm->tm_year % 100); - - /* write register's data */ - for (i = 0; i < sizeof(buf); i++) { - unsigned char data[2] = { i, buf[i] }; - - err = i2c_master_send(client, data, sizeof(data)); - if (err != sizeof(data)) { - dev_err(&client->dev, "%s: err=%d addr=%02x, data=%02x\n", - __func__, err, data[0], data[1]); - return -EIO; - } + regs[6] = bin2bcd(tm->tm_year % 100); + + /* + * after all time/date registers are written, let the 'address auto + * increment' feature wrap around and write register CTRL1 to re-enable + * the clock divider chain again + */ + regs[7] &= ~PCF85063_REG_CTRL1_STOP; + + /* write all registers at once */ + rc = i2c_smbus_write_i2c_block_data(client, PCF85063_REG_SC, + sizeof(regs), regs); + if (rc < 0) { + dev_err(&client->dev, "date/time register write error\n"); + return rc; } return 0; -- cgit v0.10.2 From 270a3bd6bdc2140708f88337c833e74ddafdcf61 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 14 Feb 2016 15:04:19 -0500 Subject: rtc: make class.c explicitly non-modular The Makefile/Kconfig currently controlling compilation of this code is: obj-$(CONFIG_RTC_CLASS) += rtc-core.o rtc-core-y := class.o interface.o drivers/rtc/Kconfig:menuconfig RTC_CLASS drivers/rtc/Kconfig: bool "Real Time Clock" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the code there is no doubt it is builtin-only. We don't replace module.h with init.h since the file does need to know what a struct module is. We also delete the MODULE_LICENSE tag etc. since all that information is already contained at the top of the file in the comments. Signed-off-by: Paul Gortmaker Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index de86578..74fd974 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -361,17 +361,4 @@ static int __init rtc_init(void) rtc_dev_init(); return 0; } - -static void __exit rtc_exit(void) -{ - rtc_dev_exit(); - class_destroy(rtc_class); - ida_destroy(&rtc_ida); -} - subsys_initcall(rtc_init); -module_exit(rtc_exit); - -MODULE_AUTHOR("Alessandro Zummo "); -MODULE_DESCRIPTION("RTC class support"); -MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 8124c7117ecd1e431a287be943e590452ff4092e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 16 Feb 2016 11:04:42 +0900 Subject: rtc: s5m: De-inline large functions to save space Few functions were marked inline even though they were relatively large and sometimes used in multiple places. De-inline them to let the compiler decide whether optimization makes sense. This fixes inline_hunt report: drivers/rtc/rtc-s5m.c: Deinline s5m8767_rtc_set_alarm_reg, save 704 bytes drivers/rtc/rtc-s5m.c: Deinline s5m8767_wait_for_udr_update, save 192 bytes Reported-by: Denys Vlasenko Cc: Denys Vlasenko Signed-off-by: Krzysztof Kozlowski Reviewed-by: Javier Martinez Canillas Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 7407d73..0477678 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -216,7 +216,7 @@ static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data) * Read RTC_UDR_CON register and wait till UDR field is cleared. * This indicates that time/alarm update ended. */ -static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info) +static int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info) { int ret, retry = UDR_READ_RETRY_CNT; unsigned int data; @@ -231,7 +231,7 @@ 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, +static int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, struct rtc_wkalrm *alarm) { int ret; @@ -264,7 +264,7 @@ static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, return 0; } -static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) +static int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) { int ret; unsigned int data; @@ -288,7 +288,7 @@ static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) return ret; } -static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) +static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) { int ret; unsigned int data; -- cgit v0.10.2 From 0a966c07323a0506522587e8de96f542ebac04ba Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 15 Feb 2016 23:49:06 +0900 Subject: rtc: rx8025: fix irq handler registration When IRQ line for this chips is connected, devm_request_threaded_irq() refuses to register irq handler with the following message. genirq: Threaded irq requested with handler=NULL and !ONESHOT for irq Signed-off-by: Akinobu Mita Cc: Wolfgang Grandegger Cc: Alessandro Zummo Cc: Alexandre Belloni Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 17341fe..18240f5 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -538,8 +538,9 @@ static int rx8025_probe(struct i2c_client *client, if (client->irq > 0) { dev_info(&client->dev, "IRQ %d supplied\n", client->irq); err = devm_request_threaded_irq(&client->dev, client->irq, NULL, - rx8025_handle_irq, 0, "rx8025", - client); + rx8025_handle_irq, + IRQF_ONESHOT, + "rx8025", client); if (err) { dev_err(&client->dev, "unable to request IRQ, alarms disabled\n"); client->irq = 0; -- cgit v0.10.2 From 9dbe3852964166fdf3ac4aff4cb67311dfa243bc Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 15 Feb 2016 23:49:07 +0900 Subject: rtc: rx8025: protect ctrl1 register update by rtc->ops_lock The ctrl1 register is accessed by alarm operations. But it is updated in threaded interrupt handler without acquiring rtc->ops_lock. Signed-off-by: Akinobu Mita Cc: Wolfgang Grandegger Cc: Alessandro Zummo Cc: Alexandre Belloni Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 18240f5..2599952 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -146,8 +146,10 @@ static irqreturn_t rx8025_handle_irq(int irq, void *dev_id) { struct i2c_client *client = dev_id; struct rx8025_data *rx8025 = i2c_get_clientdata(client); + struct mutex *lock = &rx8025->rtc->ops_lock; int status; + mutex_lock(lock); status = rx8025_read_reg(client, RX8025_REG_CTRL2); if (status < 0) goto out; @@ -172,6 +174,8 @@ static irqreturn_t rx8025_handle_irq(int irq, void *dev_id) } out: + mutex_unlock(lock); + return IRQ_HANDLED; } -- cgit v0.10.2 From 302c5608e9213c9c440b512628cb6f1626f61054 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 15 Feb 2016 23:49:08 +0900 Subject: rtc: rx8025: round up to nearest minute for a minute accuracy alarm The alarm for rx8025 only has a minute accuracy, so round up to nearest minute when setting alarm. Without doing this, rtctest blocks one day after setting alarm to 5 seconds later. pcf8563 and hym8563 also have similar handling. Signed-off-by: Akinobu Mita Cc: Wolfgang Grandegger Cc: Alessandro Zummo Cc: Alexandre Belloni Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 2599952..e117a8f 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -344,7 +344,17 @@ static int rx8025_set_alarm(struct device *dev, struct rtc_wkalrm *t) if (client->irq <= 0) return -EINVAL; - /* Hardware alarm precision is 1 minute! */ + /* + * Hardware alarm precision is 1 minute! + * round up to nearest minute + */ + if (t->time.tm_sec) { + time64_t alarm_time = rtc_tm_to_time64(&t->time); + + alarm_time += 60 - t->time.tm_sec; + rtc_time64_to_tm(alarm_time, &t->time); + } + ald[0] = bin2bcd(t->time.tm_min); if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224) ald[1] = bin2bcd(t->time.tm_hour); -- cgit v0.10.2 From ef5f4a9e805d7241ebef898d832a97915c995712 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 15 Feb 2016 23:49:09 +0900 Subject: rtc: rx8025: unsupport UIE mode The alarm for rx8025 only has a minute accuracy, so unsupport UIE mode. pcf8563 and hym8563 also have a minute accuracy and unsupport it. Signed-off-by: Akinobu Mita Cc: Wolfgang Grandegger Cc: Alessandro Zummo Cc: Alexandre Belloni Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index e117a8f..b69647e 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -563,6 +563,9 @@ static int rx8025_probe(struct i2c_client *client, rx8025->rtc->max_user_freq = 1; + /* the rx8025 alarm only supports a minute accuracy */ + rx8025->rtc->uie_unsupported = 1; + err = rx8025_sysfs_register(&client->dev); return err; } -- cgit v0.10.2 From af556c11f08bbe14a6be8936d5c155fb6694f566 Mon Sep 17 00:00:00 2001 From: Joshua Henderson Date: Thu, 25 Feb 2016 10:30:43 -0700 Subject: dt/bindings: Add bindings for the PIC32 real time clock Document the devicetree bindings for the real time clock found on Microchip PIC32 class devices. Signed-off-by: Joshua Henderson Acked-by: Rob Herring Signed-off-by: Alexandre Belloni diff --git a/Documentation/devicetree/bindings/rtc/microchip,pic32-rtc.txt b/Documentation/devicetree/bindings/rtc/microchip,pic32-rtc.txt new file mode 100644 index 0000000..180b714 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/microchip,pic32-rtc.txt @@ -0,0 +1,21 @@ +* Microchip PIC32 Real Time Clock and Calendar + +The RTCC keeps time in hours, minutes, and seconds, and one half second. It +provides a calendar in weekday, date, month, and year. It also provides a +configurable alarm. + +Required properties: +- compatible: should be: "microchip,pic32mzda-rtc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: RTC alarm/event interrupt +- clocks: clock phandle + +Example: + + rtc: rtc@1f8c0000 { + compatible = "microchip,pic32mzda-rtc"; + reg = <0x1f8c0000 0x60>; + interrupts = <166 IRQ_TYPE_EDGE_RISING>; + clocks = <&PBCLK6>; + }; -- cgit v0.10.2 From 51aa905c912385ee99791b2ced80646f37b9fe0a Mon Sep 17 00:00:00 2001 From: Joshua Henderson Date: Thu, 25 Feb 2016 10:30:44 -0700 Subject: rtc: pic32: Add PIC32 real time clock driver This driver adds support for the PIC32 real time clock and calendar peripheral: - reading and setting time - alarms provided by dedicated IRQ Signed-off-by: Joshua Henderson Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index f8a67e7..2bcc861 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1641,6 +1641,16 @@ config RTC_DRV_XGENE This driver can also be built as a module, if so, the module will be called "rtc-xgene". +config RTC_DRV_PIC32 + tristate "Microchip PIC32 RTC" + depends on MACH_PIC32 + default y + help + If you say yes here you get support for the PIC32 RTC module. + + This driver can also be built as a module. If so, the module + will be called rtc-pic32 + comment "HID Sensor RTC drivers" config RTC_DRV_HID_SENSOR_TIME diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index c1c9a18..27229d2 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -112,6 +112,7 @@ obj-$(CONFIG_RTC_DRV_PCF85063) += rtc-pcf85063.o obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o +obj-$(CONFIG_RTC_DRV_PIC32) += rtc-pic32.o obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o diff --git a/drivers/rtc/rtc-pic32.c b/drivers/rtc/rtc-pic32.c new file mode 100644 index 0000000..64e1e45 --- /dev/null +++ b/drivers/rtc/rtc-pic32.c @@ -0,0 +1,411 @@ +/* + * PIC32 RTC driver + * + * Joshua Henderson + * Copyright (C) 2016 Microchip Technology Inc. All rights reserved. + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PIC32_RTCCON 0x00 +#define PIC32_RTCCON_ON BIT(15) +#define PIC32_RTCCON_SIDL BIT(13) +#define PIC32_RTCCON_RTCCLKSEL (3 << 9) +#define PIC32_RTCCON_RTCCLKON BIT(6) +#define PIC32_RTCCON_RTCWREN BIT(3) +#define PIC32_RTCCON_RTCSYNC BIT(2) +#define PIC32_RTCCON_HALFSEC BIT(1) +#define PIC32_RTCCON_RTCOE BIT(0) + +#define PIC32_RTCALRM 0x10 +#define PIC32_RTCALRM_ALRMEN BIT(15) +#define PIC32_RTCALRM_CHIME BIT(14) +#define PIC32_RTCALRM_PIV BIT(13) +#define PIC32_RTCALRM_ALARMSYNC BIT(12) +#define PIC32_RTCALRM_AMASK 0x0F00 +#define PIC32_RTCALRM_ARPT 0xFF + +#define PIC32_RTCHOUR 0x23 +#define PIC32_RTCMIN 0x22 +#define PIC32_RTCSEC 0x21 +#define PIC32_RTCYEAR 0x33 +#define PIC32_RTCMON 0x32 +#define PIC32_RTCDAY 0x31 + +#define PIC32_ALRMTIME 0x40 +#define PIC32_ALRMDATE 0x50 + +#define PIC32_ALRMHOUR 0x43 +#define PIC32_ALRMMIN 0x42 +#define PIC32_ALRMSEC 0x41 +#define PIC32_ALRMYEAR 0x53 +#define PIC32_ALRMMON 0x52 +#define PIC32_ALRMDAY 0x51 + +struct pic32_rtc_dev { + struct rtc_device *rtc; + void __iomem *reg_base; + struct clk *clk; + spinlock_t alarm_lock; + int alarm_irq; + bool alarm_clk_enabled; +}; + +static void pic32_rtc_alarm_clk_enable(struct pic32_rtc_dev *pdata, + bool enable) +{ + unsigned long flags; + + spin_lock_irqsave(&pdata->alarm_lock, flags); + if (enable) { + if (!pdata->alarm_clk_enabled) { + clk_enable(pdata->clk); + pdata->alarm_clk_enabled = true; + } + } else { + if (pdata->alarm_clk_enabled) { + clk_disable(pdata->clk); + pdata->alarm_clk_enabled = false; + } + } + spin_unlock_irqrestore(&pdata->alarm_lock, flags); +} + +static irqreturn_t pic32_rtc_alarmirq(int irq, void *id) +{ + struct pic32_rtc_dev *pdata = (struct pic32_rtc_dev *)id; + + clk_enable(pdata->clk); + rtc_update_irq(pdata->rtc, 1, RTC_AF | RTC_IRQF); + clk_disable(pdata->clk); + + pic32_rtc_alarm_clk_enable(pdata, false); + + return IRQ_HANDLED; +} + +static int pic32_rtc_setaie(struct device *dev, unsigned int enabled) +{ + struct pic32_rtc_dev *pdata = dev_get_drvdata(dev); + void __iomem *base = pdata->reg_base; + + clk_enable(pdata->clk); + + writel(PIC32_RTCALRM_ALRMEN, + base + (enabled ? PIC32_SET(PIC32_RTCALRM) : + PIC32_CLR(PIC32_RTCALRM))); + + clk_disable(pdata->clk); + + pic32_rtc_alarm_clk_enable(pdata, enabled); + + return 0; +} + +static int pic32_rtc_setfreq(struct device *dev, int freq) +{ + struct pic32_rtc_dev *pdata = dev_get_drvdata(dev); + void __iomem *base = pdata->reg_base; + + clk_enable(pdata->clk); + + writel(PIC32_RTCALRM_AMASK, base + PIC32_CLR(PIC32_RTCALRM)); + writel(freq << 8, base + PIC32_SET(PIC32_RTCALRM)); + writel(PIC32_RTCALRM_CHIME, base + PIC32_SET(PIC32_RTCALRM)); + + clk_disable(pdata->clk); + + return 0; +} + +static int pic32_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) +{ + struct pic32_rtc_dev *pdata = dev_get_drvdata(dev); + void __iomem *base = pdata->reg_base; + unsigned int tries = 0; + + clk_enable(pdata->clk); + + do { + rtc_tm->tm_hour = readb(base + PIC32_RTCHOUR); + rtc_tm->tm_min = readb(base + PIC32_RTCMIN); + rtc_tm->tm_mon = readb(base + PIC32_RTCMON); + rtc_tm->tm_mday = readb(base + PIC32_RTCDAY); + rtc_tm->tm_year = readb(base + PIC32_RTCYEAR); + rtc_tm->tm_sec = readb(base + PIC32_RTCSEC); + + /* + * The only way to work out whether the system was mid-update + * when we read it is to check the second counter, and if it + * is zero, then we re-try the entire read. + */ + tries += 1; + } while (rtc_tm->tm_sec == 0 && tries < 2); + + rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); + rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min); + rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour); + rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday); + rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon) - 1; + rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year); + + rtc_tm->tm_year += 100; + + dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n", + 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, + rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); + + clk_disable(pdata->clk); + return rtc_valid_tm(rtc_tm); +} + +static int pic32_rtc_settime(struct device *dev, struct rtc_time *tm) +{ + struct pic32_rtc_dev *pdata = dev_get_drvdata(dev); + void __iomem *base = pdata->reg_base; + int year = tm->tm_year - 100; + + dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n", + 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + if (year < 0 || year >= 100) { + dev_err(dev, "rtc only supports 100 years\n"); + return -EINVAL; + } + + clk_enable(pdata->clk); + writeb(bin2bcd(tm->tm_sec), base + PIC32_RTCSEC); + writeb(bin2bcd(tm->tm_min), base + PIC32_RTCMIN); + writeb(bin2bcd(tm->tm_hour), base + PIC32_RTCHOUR); + writeb(bin2bcd(tm->tm_mday), base + PIC32_RTCDAY); + writeb(bin2bcd(tm->tm_mon + 1), base + PIC32_RTCMON); + writeb(bin2bcd(year), base + PIC32_RTCYEAR); + clk_disable(pdata->clk); + + return 0; +} + +static int pic32_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pic32_rtc_dev *pdata = dev_get_drvdata(dev); + struct rtc_time *alm_tm = &alrm->time; + void __iomem *base = pdata->reg_base; + unsigned int alm_en; + + clk_enable(pdata->clk); + alm_tm->tm_sec = readb(base + PIC32_ALRMSEC); + alm_tm->tm_min = readb(base + PIC32_ALRMMIN); + alm_tm->tm_hour = readb(base + PIC32_ALRMHOUR); + alm_tm->tm_mon = readb(base + PIC32_ALRMMON); + alm_tm->tm_mday = readb(base + PIC32_ALRMDAY); + alm_tm->tm_year = readb(base + PIC32_ALRMYEAR); + + alm_en = readb(base + PIC32_RTCALRM); + + alrm->enabled = (alm_en & PIC32_RTCALRM_ALRMEN) ? 1 : 0; + + dev_dbg(dev, "getalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", + alm_en, + 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, + alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); + + alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec); + alm_tm->tm_min = bcd2bin(alm_tm->tm_min); + alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour); + alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday); + alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon) - 1; + alm_tm->tm_year = bcd2bin(alm_tm->tm_year); + + clk_disable(pdata->clk); + return 0; +} + +static int pic32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pic32_rtc_dev *pdata = dev_get_drvdata(dev); + struct rtc_time *tm = &alrm->time; + void __iomem *base = pdata->reg_base; + + clk_enable(pdata->clk); + dev_dbg(dev, "setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", + alrm->enabled, + 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + writel(0x00, base + PIC32_ALRMTIME); + writel(0x00, base + PIC32_ALRMDATE); + + pic32_rtc_setaie(dev, alrm->enabled); + + clk_disable(pdata->clk); + return 0; +} + +static int pic32_rtc_proc(struct device *dev, struct seq_file *seq) +{ + struct pic32_rtc_dev *pdata = dev_get_drvdata(dev); + void __iomem *base = pdata->reg_base; + unsigned int repeat; + + clk_enable(pdata->clk); + + repeat = readw(base + PIC32_RTCALRM); + repeat &= PIC32_RTCALRM_ARPT; + seq_printf(seq, "periodic_IRQ\t: %s\n", repeat ? "yes" : "no"); + + clk_disable(pdata->clk); + return 0; +} + +static const struct rtc_class_ops pic32_rtcops = { + .read_time = pic32_rtc_gettime, + .set_time = pic32_rtc_settime, + .read_alarm = pic32_rtc_getalarm, + .set_alarm = pic32_rtc_setalarm, + .proc = pic32_rtc_proc, + .alarm_irq_enable = pic32_rtc_setaie, +}; + +static void pic32_rtc_enable(struct pic32_rtc_dev *pdata, int en) +{ + void __iomem *base = pdata->reg_base; + + if (!base) + return; + + clk_enable(pdata->clk); + if (!en) { + writel(PIC32_RTCCON_ON, base + PIC32_CLR(PIC32_RTCCON)); + } else { + pic32_syskey_unlock(); + + writel(PIC32_RTCCON_RTCWREN, base + PIC32_SET(PIC32_RTCCON)); + writel(3 << 9, base + PIC32_CLR(PIC32_RTCCON)); + + if (!(readl(base + PIC32_RTCCON) & PIC32_RTCCON_ON)) + writel(PIC32_RTCCON_ON, base + PIC32_SET(PIC32_RTCCON)); + } + clk_disable(pdata->clk); +} + +static int pic32_rtc_remove(struct platform_device *pdev) +{ + struct pic32_rtc_dev *pdata = platform_get_drvdata(pdev); + + pic32_rtc_setaie(&pdev->dev, 0); + clk_unprepare(pdata->clk); + pdata->clk = NULL; + + return 0; +} + +static int pic32_rtc_probe(struct platform_device *pdev) +{ + struct pic32_rtc_dev *pdata; + struct resource *res; + int ret; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + platform_set_drvdata(pdev, pdata); + + pdata->alarm_irq = platform_get_irq(pdev, 0); + if (pdata->alarm_irq < 0) { + dev_err(&pdev->dev, "no irq for alarm\n"); + return pdata->alarm_irq; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pdata->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pdata->reg_base)) + return PTR_ERR(pdata->reg_base); + + pdata->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(pdata->clk)) { + dev_err(&pdev->dev, "failed to find rtc clock source\n"); + ret = PTR_ERR(pdata->clk); + pdata->clk = NULL; + return ret; + } + + spin_lock_init(&pdata->alarm_lock); + + clk_prepare_enable(pdata->clk); + + pic32_rtc_enable(pdata, 1); + + device_init_wakeup(&pdev->dev, 1); + + pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &pic32_rtcops, + THIS_MODULE); + if (IS_ERR(pdata->rtc)) { + ret = PTR_ERR(pdata->rtc); + goto err_nortc; + } + + pdata->rtc->max_user_freq = 128; + + pic32_rtc_setfreq(&pdev->dev, 1); + ret = devm_request_irq(&pdev->dev, pdata->alarm_irq, + pic32_rtc_alarmirq, 0, + dev_name(&pdev->dev), pdata); + if (ret) { + dev_err(&pdev->dev, + "IRQ %d error %d\n", pdata->alarm_irq, ret); + goto err_nortc; + } + + clk_disable(pdata->clk); + + return 0; + +err_nortc: + pic32_rtc_enable(pdata, 0); + clk_disable_unprepare(pdata->clk); + + return ret; +} + +static const struct of_device_id pic32_rtc_dt_ids[] = { + { .compatible = "microchip,pic32mzda-rtc" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, pic32_rtc_dt_ids); + +static struct platform_driver pic32_rtc_driver = { + .probe = pic32_rtc_probe, + .remove = pic32_rtc_remove, + .driver = { + .name = "pic32-rtc", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pic32_rtc_dt_ids), + }, +}; +module_platform_driver(pic32_rtc_driver); + +MODULE_DESCRIPTION("Microchip PIC32 RTC Driver"); +MODULE_AUTHOR("Joshua Henderson "); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From d084885e9800f574f0cc41e7b82fc4a18fca3a95 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Tue, 3 Nov 2015 23:13:46 -0800 Subject: rtc: Group Kconfig entries by vendor The RTC entries are mostly grouped by vendor. Move the few outliers in place. Also, change the one occurrence of 'nxp' to 'NXP' to make all NXP entries consistent. Signed-off-by: Soren Brinkmann Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2bcc861..583c1e6 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -390,16 +390,6 @@ config RTC_DRV_X1205 This driver can also be built as a module. If so, the module will be called rtc-x1205. -config RTC_DRV_PALMAS - tristate "TI Palmas RTC driver" - depends on MFD_PALMAS - help - If you say yes here you get support for the RTC of TI PALMA series PMIC - chips. - - This driver can also be built as a module. If so, the module - will be called rtc-palma. - config RTC_DRV_PCF2127 tristate "NXP PCF2127" help @@ -418,6 +408,14 @@ config RTC_DRV_PCF8523 This driver can also be built as a module. If so, the module will be called rtc-pcf8523. +config RTC_DRV_PCF85063 + tristate "NXP PCF85063" + help + If you say yes here you get support for the PCF85063 RTC chip + + This driver can also be built as a module. If so, the module + will be called rtc-pcf85063. + config RTC_DRV_PCF8563 tristate "Philips PCF8563/Epson RTC8564" help @@ -428,14 +426,6 @@ config RTC_DRV_PCF8563 This driver can also be built as a module. If so, the module will be called rtc-pcf8563. -config RTC_DRV_PCF85063 - tristate "nxp PCF85063" - help - If you say yes here you get support for the PCF85063 RTC chip - - This driver can also be built as a module. If so, the module - will be called rtc-pcf85063. - config RTC_DRV_PCF8583 tristate "Philips PCF8583" help @@ -500,6 +490,16 @@ config RTC_DRV_TWL4030 This driver can also be built as a module. If so, the module will be called rtc-twl. +config RTC_DRV_PALMAS + tristate "TI Palmas RTC driver" + depends on MFD_PALMAS + help + If you say yes here you get support for the RTC of TI PALMA series PMIC + chips. + + This driver can also be built as a module. If so, the module + will be called rtc-palma. + config RTC_DRV_TPS6586X tristate "TI TPS6586X RTC driver" depends on MFD_TPS6586X @@ -690,15 +690,6 @@ config RTC_DRV_DS1390 This driver can also be built as a module. If so, the module will be called rtc-ds1390. -config RTC_DRV_MAX6902 - tristate "Maxim MAX6902" - help - If you say yes here you will get support for the - Maxim MAX6902 SPI RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-max6902. - config RTC_DRV_R9701 tristate "Epson RTC-9701JE" help @@ -708,6 +699,23 @@ config RTC_DRV_R9701 This driver can also be built as a module. If so, the module will be called rtc-r9701. +config RTC_DRV_RX4581 + tristate "Epson RX-4581" + help + If you say yes here you will get support for the Epson RX-4581. + + This driver can also be built as a module. If so the module + will be called rtc-rx4581. + +config RTC_DRV_RX6110 + tristate "Epson RX-6110" + select REGMAP_SPI + help + If you say yes here you will get support for the Epson RX-6610. + + This driver can also be built as a module. If so the module + will be called rtc-rx6110. + config RTC_DRV_RS5C348 tristate "Ricoh RS5C348A/B" help @@ -717,6 +725,15 @@ config RTC_DRV_RS5C348 This driver can also be built as a module. If so, the module will be called rtc-rs5c348. +config RTC_DRV_MAX6902 + tristate "Maxim MAX6902" + help + If you say yes here you will get support for the + Maxim MAX6902 SPI RTC chip. + + 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 @@ -735,23 +752,6 @@ config RTC_DRV_PCF2123 This driver can also be built as a module. If so, the module will be called rtc-pcf2123. -config RTC_DRV_RX4581 - tristate "Epson RX-4581" - help - If you say yes here you will get support for the Epson RX-4581. - - This driver can also be built as a module. If so the module - will be called rtc-rx4581. - -config RTC_DRV_RX6110 - tristate "Epson RX-6110" - select REGMAP_SPI - help - If you say yes here you will get support for the Epson RX-6610. - - This driver can also be built as a module. If so the module - will be called rtc-rx6110. - config RTC_DRV_MCP795 tristate "Microchip MCP795" help -- cgit v0.10.2 From b3be3f6a364b0e2c59b3ad0d7f6dd259feb8a393 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 26 Feb 2016 17:42:52 +0200 Subject: rtc: palmas: Drop IRQF_EARLY_RESUME flag Palams RTC IRQ is nested threaded and wired to the Palmas inerrupt controller. So, this flag is not required for nested irqs anymore, since commit 3c646f2c6aa9 ("genirq: Don't suspend nested_thread irqs over system suspend") was merged. Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: Tony Lindgren Cc: Lee Jones Cc: Nishanth Menon Signed-off-by: Grygorii Strashko Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c index 7ea2c47..6080e0e 100644 --- a/drivers/rtc/rtc-palmas.c +++ b/drivers/rtc/rtc-palmas.c @@ -311,8 +311,7 @@ static int palmas_rtc_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(&pdev->dev, palmas_rtc->irq, NULL, palmas_rtc_interrupt, - IRQF_TRIGGER_LOW | IRQF_ONESHOT | - IRQF_EARLY_RESUME, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, dev_name(&pdev->dev), palmas_rtc); if (ret < 0) { dev_err(&pdev->dev, "IRQ request failed, err = %d\n", ret); -- cgit v0.10.2 From aa1e8069fcbc7f05e786922db2942dd49c136b4e Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 26 Feb 2016 17:42:53 +0200 Subject: rtc: tps6586x: Drop IRQF_EARLY_RESUME flag tps6586x RTC IRQ is nested threaded and wired to the tps6586x inerrupt controller. So, this flag is not required for nested irqs anymore, since commit 3c646f2c6aa9 ("genirq: Don't suspend nested_thread irqs over system suspend") was merged. Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: Lee Jones Cc: Nishanth Menon Cc: Laxman Dewangan Signed-off-by: Grygorii Strashko Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index 3b6ce80..e404faa 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -286,7 +286,7 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, tps6586x_rtc_irq, - IRQF_ONESHOT | IRQF_EARLY_RESUME, + IRQF_ONESHOT, dev_name(&pdev->dev), rtc); if (ret < 0) { dev_err(&pdev->dev, "request IRQ(%d) failed with ret %d\n", -- cgit v0.10.2 From be563c9a2727806213ad634643045d521655fc6d Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 26 Feb 2016 17:42:54 +0200 Subject: rtc: tps65910: Drop IRQF_EARLY_RESUME flag tps65910 RTC IRQ is nested threaded and wired to the tps65910 inerrupt controller. So, this flag is not required for nested irqs anymore, since commit 3c646f2c6aa9 ("genirq: Don't suspend nested_thread irqs over system suspend") was merged. Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: Lee Jones Cc: Tony Lindgren Cc: Nishanth Menon Cc: Laxman Dewangan Signed-off-by: Grygorii Strashko Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index f42aa2b..5a3d53c 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -268,7 +268,7 @@ static int tps65910_rtc_probe(struct platform_device *pdev) } ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, - tps65910_rtc_interrupt, IRQF_TRIGGER_LOW | IRQF_EARLY_RESUME, + tps65910_rtc_interrupt, IRQF_TRIGGER_LOW, dev_name(&pdev->dev), &pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "IRQ is not free.\n"); -- cgit v0.10.2 From ed214bec6803081bace1ca5d546eac6b18c36028 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 26 Feb 2016 17:42:55 +0200 Subject: rtc: tps80031: Drop IRQF_EARLY_RESUME flag tps80031 RTC IRQ is nested threaded and wired to the tps80031 inerrupt controller. So, this flag is not required for nested irqs anymore, since commit 3c646f2c6aa9 ("genirq: Don't suspend nested_thread irqs over system suspend") was merged. Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: Lee Jones Cc: Nishanth Menon Signed-off-by: Grygorii Strashko Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c index 27e254c..737f26e 100644 --- a/drivers/rtc/rtc-tps80031.c +++ b/drivers/rtc/rtc-tps80031.c @@ -287,7 +287,7 @@ static int tps80031_rtc_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, tps80031_rtc_irq, - IRQF_ONESHOT | IRQF_EARLY_RESUME, + IRQF_ONESHOT, dev_name(&pdev->dev), rtc); if (ret < 0) { dev_err(&pdev->dev, "request IRQ:%d failed, err = %d\n", -- cgit v0.10.2 From ddf7059ce5dfa28e30380524983db94868fa9083 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 26 Feb 2016 17:42:56 +0200 Subject: rtc: as3722: Drop IRQF_EARLY_RESUME flag as3722 RTC IRQ is nested threaded and wired to the as3722 inerrupt controller. So, this flag is not required for nested irqs anymore, since commit 3c646f2c6aa9 ("genirq: Don't suspend nested_thread irqs over system suspend") was merged. Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: Lee Jones Cc: Nishanth Menon Cc: Laxman Dewangan Signed-off-by: Grygorii Strashko Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-as3722.c b/drivers/rtc/rtc-as3722.c index 56cc582..6ef0c88 100644 --- a/drivers/rtc/rtc-as3722.c +++ b/drivers/rtc/rtc-as3722.c @@ -210,7 +210,7 @@ static int as3722_rtc_probe(struct platform_device *pdev) dev_info(&pdev->dev, "RTC interrupt %d\n", as3722_rtc->alarm_irq); ret = devm_request_threaded_irq(&pdev->dev, as3722_rtc->alarm_irq, NULL, - as3722_alarm_irq, IRQF_ONESHOT | IRQF_EARLY_RESUME, + as3722_alarm_irq, IRQF_ONESHOT, "rtc-alarm", as3722_rtc); if (ret < 0) { dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n", -- cgit v0.10.2 From d2c6b8743b74fc012f858abd0b78d934fc422641 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 29 Feb 2016 00:47:49 +0100 Subject: rtc: rv3029: reword Kconfig option The Kconfig option for rv3029 is not mentioning any part number, explicitly show rv3029. Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 583c1e6..08df14b 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -594,10 +594,10 @@ config RTC_DRV_EM3027 will be called rtc-em3027. config RTC_DRV_RV3029C2 - tristate "Micro Crystal RTC" + tristate "Micro Crystal RV3029" help If you say yes here you get support for the Micro Crystal - RV3029-C2 RTC chips. + RV3029 RTC chips. This driver can also be built as a module. If so, the module will be called rtc-rv3029c2. -- cgit v0.10.2 From a25f4a95ec3cded34c1250364eba704c5e4fdac4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 1 Mar 2016 09:50:01 +0100 Subject: rtc: vr41xx: Wire up alarm_irq_enable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/rtc/rtc-vr41xx.c:229: warning: ‘vr41xx_rtc_alarm_irq_enable’ defined but not used Apparently the conversion to alarm_irq_enable forgot to wire up the callback. Fixes: 16380c153a69c378 ("RTC: Convert rtc drivers to use the alarm_irq_enable method") Signed-off-by: Geert Uytterhoeven Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index f64c282..e1b86bb 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -272,12 +272,13 @@ static irqreturn_t rtclong1_interrupt(int irq, void *dev_id) } static const struct rtc_class_ops vr41xx_rtc_ops = { - .release = vr41xx_rtc_release, - .ioctl = vr41xx_rtc_ioctl, - .read_time = vr41xx_rtc_read_time, - .set_time = vr41xx_rtc_set_time, - .read_alarm = vr41xx_rtc_read_alarm, - .set_alarm = vr41xx_rtc_set_alarm, + .release = vr41xx_rtc_release, + .ioctl = vr41xx_rtc_ioctl, + .read_time = vr41xx_rtc_read_time, + .set_time = vr41xx_rtc_set_time, + .read_alarm = vr41xx_rtc_read_alarm, + .set_alarm = vr41xx_rtc_set_alarm, + .alarm_irq_enable = vr41xx_rtc_alarm_irq_enable, }; static int rtc_probe(struct platform_device *pdev) -- cgit v0.10.2 From ba270bbbf43474fe459e206b5283996fd1511647 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 24 Feb 2016 00:05:28 +0100 Subject: rtc: pcf85063: remove useless century handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pcf85063_get_datetime() tries to handle a century bit but that bit is not documented and the final value is never used anywhere else in the kernel. Reviewed-by: Juergen Borleis Tested-by: Ulrich Ölmann Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index c5db231..4e940cc 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -31,13 +31,10 @@ #define PCF85063_REG_MO 0x09 #define PCF85063_REG_YR 0x0A -#define PCF85063_MO_C 0x80 /* century */ - static struct i2c_driver pcf85063_driver; struct pcf85063 { struct rtc_device *rtc; - int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */ int voltage_low; /* indicates if a low_voltage was detected */ }; @@ -72,7 +69,6 @@ static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1) static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm) { int rc; - struct pcf85063 *pcf85063 = i2c_get_clientdata(client); u8 regs[7]; /* @@ -103,9 +99,6 @@ static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm) tm->tm_year = bcd2bin(regs[6]); if (tm->tm_year < 70) tm->tm_year += 100; /* assume we are in 1970...2069 */ - /* detect the polarity heuristically. see note above. */ - pcf85063->c_polarity = (regs[5] & PCF85063_MO_C) ? - (tm->tm_year >= 100) : (tm->tm_year < 100); return rtc_valid_tm(tm); } -- cgit v0.10.2 From 582841a4f66f64ed08450fcb8f716cacc51ac7d7 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 24 Feb 2016 14:26:20 -0300 Subject: rtc: mt6397: Remove plaform module alias The driver uses the MODULE_ALIAS() macro to export a platform module alias to allow the module to be autoloaded if the device is registered using the legacy platform registration mechanism but the driver is always used by OF only machines so the alias is not needed and should just be removed. Suggested-by: Arnd Bergmann Signed-off-by: Javier Martinez Canillas Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index 06a5c52..44f622c 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -419,4 +419,3 @@ module_platform_driver(mtk_rtc_driver); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Tianping Fang "); MODULE_DESCRIPTION("RTC Driver for MediaTek MT6397 PMIC"); -MODULE_ALIAS("platform:mt6397-rtc"); -- cgit v0.10.2 From 726fe738bd5cc5deba86d7e621505392c0f7961f Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 2 Mar 2016 14:06:24 +0530 Subject: rtc: max77686: Add support for MAX20024/MAX77620 RTC IP Maxim Semiconductor's PMIC MAX77686 has RTC IP which is reused in the MAX77620/MAX20024 PMICs. Add support for these devices in MAX77686 RTC driver. This device does not have RTC alarm pending status outside of RTC IP. The RTC IP is having separate I2C address for its register access. Signed-off-by: Laxman Dewangan Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 08df14b..1c8dadc 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -326,10 +326,10 @@ config RTC_DRV_MAX8997 config RTC_DRV_MAX77686 tristate "Maxim MAX77686" - depends on MFD_MAX77686 + depends on MFD_MAX77686 || MFD_MAX77620 help If you say yes here you will get support for the - RTC of Maxim MAX77686 PMIC. + RTC of Maxim MAX77686/MAX77620/MAX77802 PMIC. This driver can also be built as a module. If so, the module will be called rtc-max77686. diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 5e924f3..9cd4c4f 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -24,8 +24,12 @@ #include #define MAX77686_I2C_ADDR_RTC (0x0C >> 1) +#define MAX77620_I2C_ADDR_RTC 0x68 #define MAX77686_INVALID_I2C_ADDR (-1) +/* Define non existing register */ +#define MAX77686_INVALID_REG (-1) + /* RTC Control Register */ #define BCD_EN_SHIFT 0 #define BCD_EN_MASK BIT(BCD_EN_SHIFT) @@ -74,6 +78,10 @@ struct max77686_rtc_driver_data { bool alarm_enable_reg; /* I2C address for RTC block */ int rtc_i2c_addr; + /* RTC interrupt via platform resource */ + bool rtc_irq_from_platform; + /* Pending alarm status register */ + int alarm_pending_status_reg; /* RTC IRQ CHIP for regmap */ const struct regmap_irq_chip *rtc_irq_chip; }; @@ -185,10 +193,23 @@ static const struct max77686_rtc_driver_data max77686_drv_data = { .mask = 0x7f, .map = max77686_map, .alarm_enable_reg = false, + .rtc_irq_from_platform = false, + .alarm_pending_status_reg = MAX77686_REG_STATUS2, .rtc_i2c_addr = MAX77686_I2C_ADDR_RTC, .rtc_irq_chip = &max77686_rtc_irq_chip, }; +static const struct max77686_rtc_driver_data max77620_drv_data = { + .delay = 16000, + .mask = 0x7f, + .map = max77686_map, + .alarm_enable_reg = false, + .rtc_irq_from_platform = true, + .alarm_pending_status_reg = MAX77686_INVALID_REG, + .rtc_i2c_addr = MAX77620_I2C_ADDR_RTC, + .rtc_irq_chip = &max77686_rtc_irq_chip, +}; + static const unsigned int max77802_map[REG_RTC_END] = { [REG_RTC_CONTROLM] = MAX77802_RTC_CONTROLM, [REG_RTC_CONTROL] = MAX77802_RTC_CONTROL, @@ -232,6 +253,8 @@ static const struct max77686_rtc_driver_data max77802_drv_data = { .mask = 0xff, .map = max77802_map, .alarm_enable_reg = true, + .rtc_irq_from_platform = false, + .alarm_pending_status_reg = MAX77686_REG_STATUS2, .rtc_i2c_addr = MAX77686_INVALID_I2C_ADDR, .rtc_irq_chip = &max77802_rtc_irq_chip, }; @@ -427,9 +450,15 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) } alrm->pending = 0; - ret = regmap_read(info->regmap, MAX77686_REG_STATUS2, &val); + + if (info->drv_data->alarm_pending_status_reg == MAX77686_INVALID_REG) + goto out; + + ret = regmap_read(info->regmap, + info->drv_data->alarm_pending_status_reg, &val); if (ret < 0) { - dev_err(info->dev, "Fail to read status2 reg(%d)\n", ret); + dev_err(info->dev, + "Fail to read alarm pending status reg(%d)\n", ret); goto out; } @@ -648,7 +677,18 @@ static int max77686_init_rtc_regmap(struct max77686_rtc_info *info) struct i2c_client *parent_i2c = to_i2c_client(parent); int ret; - info->rtc_irq = parent_i2c->irq; + if (info->drv_data->rtc_irq_from_platform) { + struct platform_device *pdev = to_platform_device(info->dev); + + info->rtc_irq = platform_get_irq(pdev, 0); + if (info->rtc_irq < 0) { + dev_err(info->dev, "Failed to get rtc interrupts: %d\n", + info->rtc_irq); + return info->rtc_irq; + } + } else { + info->rtc_irq = parent_i2c->irq; + } info->regmap = dev_get_regmap(parent, NULL); if (!info->regmap) { @@ -802,6 +842,7 @@ static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops, static const struct platform_device_id rtc_id[] = { { "max77686-rtc", .driver_data = (kernel_ulong_t)&max77686_drv_data, }, { "max77802-rtc", .driver_data = (kernel_ulong_t)&max77802_drv_data, }, + { "max77620-rtc", .driver_data = (kernel_ulong_t)&max77620_drv_data, }, {}, }; MODULE_DEVICE_TABLE(platform, rtc_id); -- cgit v0.10.2 From 7e84536cb9ffb6562b3a2584c7454104e750e01a Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 2 Mar 2016 14:06:25 +0530 Subject: rtc: max77686: Use REGMAP_IRQ_REG for regmap-rtc-irqs initialisation Use macro REGMAP_IRQ_REG from regmap.h to initialise the regmap irq table for max77686 to have better coding style and improve readability. Signed-off-by: Laxman Dewangan Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 9cd4c4f..182fdd0 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -171,12 +171,12 @@ static const unsigned int max77686_map[REG_RTC_END] = { static const struct regmap_irq max77686_rtc_irqs[] = { /* RTC interrupts */ - { .reg_offset = 0, .mask = MAX77686_RTCINT_RTC60S_MSK, }, - { .reg_offset = 0, .mask = MAX77686_RTCINT_RTCA1_MSK, }, - { .reg_offset = 0, .mask = MAX77686_RTCINT_RTCA2_MSK, }, - { .reg_offset = 0, .mask = MAX77686_RTCINT_SMPL_MSK, }, - { .reg_offset = 0, .mask = MAX77686_RTCINT_RTC1S_MSK, }, - { .reg_offset = 0, .mask = MAX77686_RTCINT_WTSR_MSK, }, + REGMAP_IRQ_REG(0, 0, MAX77686_RTCINT_RTC60S_MSK), + REGMAP_IRQ_REG(1, 0, MAX77686_RTCINT_RTCA1_MSK), + REGMAP_IRQ_REG(2, 0, MAX77686_RTCINT_RTCA2_MSK), + REGMAP_IRQ_REG(3, 0, MAX77686_RTCINT_SMPL_MSK), + REGMAP_IRQ_REG(4, 0, MAX77686_RTCINT_RTC1S_MSK), + REGMAP_IRQ_REG(5, 0, MAX77686_RTCINT_WTSR_MSK), }; static const struct regmap_irq_chip max77686_rtc_irq_chip = { -- cgit v0.10.2 From 8c09b9fdecab1f4a289f07b46e2ad174b6641928 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 2 Mar 2016 13:07:45 +0300 Subject: rtc: ds1685: passing bogus values to irq_restore We call spin_lock_irqrestore with "flags" set to zero instead of to the value from spin_lock_irqsave(). Fixes: aaaf5fbf56f1 ('rtc: add driver for DS1685 family of real time clocks') Signed-off-by: Dan Carpenter Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 535050f..08e0ff8 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -187,9 +187,9 @@ ds1685_rtc_end_data_access(struct ds1685_priv *rtc) * Only use this where you are certain another lock will not be held. */ static inline void -ds1685_rtc_begin_ctrl_access(struct ds1685_priv *rtc, unsigned long flags) +ds1685_rtc_begin_ctrl_access(struct ds1685_priv *rtc, unsigned long *flags) { - spin_lock_irqsave(&rtc->lock, flags); + spin_lock_irqsave(&rtc->lock, *flags); ds1685_rtc_switch_to_bank1(rtc); } @@ -1300,7 +1300,7 @@ ds1685_rtc_sysfs_ctrl_regs_store(struct device *dev, { struct ds1685_priv *rtc = dev_get_drvdata(dev); u8 reg = 0, bit = 0, tmp; - unsigned long flags = 0; + unsigned long flags; long int val = 0; const struct ds1685_rtc_ctrl_regs *reg_info = ds1685_rtc_sysfs_ctrl_regs_lookup(attr->attr.name); @@ -1321,7 +1321,7 @@ ds1685_rtc_sysfs_ctrl_regs_store(struct device *dev, bit = reg_info->bit; /* Safe to spinlock during a write. */ - ds1685_rtc_begin_ctrl_access(rtc, flags); + ds1685_rtc_begin_ctrl_access(rtc, &flags); tmp = rtc->read(rtc, reg); rtc->write(rtc, reg, (val ? (tmp | bit) : (tmp & ~(bit)))); ds1685_rtc_end_ctrl_access(rtc, flags); -- cgit v0.10.2 From e0252ec77b5ea6cf4403ba49112bc95378ffe50a Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 3 Mar 2016 04:01:18 +0100 Subject: rtc: always show I2C Always show there is an I2C section, like the other sections. Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 1c8dadc..88254d3 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -140,7 +140,6 @@ config RTC_DRV_TEST will be called rtc-test. comment "I2C RTC drivers" - depends on I2C if I2C -- cgit v0.10.2 From a2892bf4456ef2c57a03b48cf09476bedee140f1 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 2 Mar 2016 11:25:42 +0100 Subject: rtc: pcf85063: remove useless DRV_VERSION Since the driver is mainlined there is no use for a separate version number. Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 4e940cc..550f675 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -16,8 +16,6 @@ #include #include -#define DRV_VERSION "0.0.1" - #define PCF85063_REG_CTRL1 0x00 /* status */ #define PCF85063_REG_CTRL1_STOP BIT(5) #define PCF85063_REG_CTRL2 0x01 @@ -182,8 +180,6 @@ static int pcf85063_probe(struct i2c_client *client, if (!pcf85063) return -ENOMEM; - dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); - i2c_set_clientdata(client, pcf85063); pcf85063->rtc = devm_rtc_device_register(&client->dev, @@ -221,4 +217,3 @@ module_i2c_driver(pcf85063_driver); MODULE_AUTHOR("Søren Andersen "); MODULE_DESCRIPTION("PCF85063 RTC driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); -- cgit v0.10.2 From 2da424af4531c4469408136772d6d5e0f8df748b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 2 Mar 2016 11:25:43 +0100 Subject: rtc: pcf85063: remove struct pcf85063 No members of struct pcf85063 are used anymore, remove the whole structure. Reviewed-by: Juergen Borleis Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 550f675..e8ddbb359 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -31,11 +31,6 @@ static struct i2c_driver pcf85063_driver; -struct pcf85063 { - struct rtc_device *rtc; - int voltage_low; /* indicates if a low_voltage was detected */ -}; - static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1) { s32 ret; @@ -168,25 +163,18 @@ static const struct rtc_class_ops pcf85063_rtc_ops = { static int pcf85063_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct pcf85063 *pcf85063; + struct rtc_device *rtc; dev_dbg(&client->dev, "%s\n", __func__); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; - pcf85063 = devm_kzalloc(&client->dev, sizeof(struct pcf85063), - GFP_KERNEL); - if (!pcf85063) - return -ENOMEM; - - i2c_set_clientdata(client, pcf85063); - - pcf85063->rtc = devm_rtc_device_register(&client->dev, - pcf85063_driver.driver.name, - &pcf85063_rtc_ops, THIS_MODULE); + rtc = devm_rtc_device_register(&client->dev, + pcf85063_driver.driver.name, + &pcf85063_rtc_ops, THIS_MODULE); - return PTR_ERR_OR_ZERO(pcf85063->rtc); + return PTR_ERR_OR_ZERO(rtc); } static const struct i2c_device_id pcf85063_id[] = { -- cgit v0.10.2 From ede44c908d44b166a5b6bd7caacd105c2ff5a70f Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 3 Mar 2016 09:55:47 +0100 Subject: rtc: pcf8523: properly handle oscillator stop bit The time and date register of the pcf8223 are undefined after a power reset. Properly handle the OS bit and return -EINVAL when that bit is set. It is properly removed when setting the time. This solves an issue where the time and date may be valid for rtc_valid_tm() but is not the current time. Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 988566c..28c48b3 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -178,28 +178,8 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) if (err < 0) return err; - if (regs[0] & REG_SECONDS_OS) { - /* - * If the oscillator was stopped, try to clear the flag. Upon - * power-up the flag is always set, but if we cannot clear it - * the oscillator isn't running properly for some reason. The - * sensible thing therefore is to return an error, signalling - * that the clock cannot be assumed to be correct. - */ - - regs[0] &= ~REG_SECONDS_OS; - - err = pcf8523_write(client, REG_SECONDS, regs[0]); - if (err < 0) - return err; - - err = pcf8523_read(client, REG_SECONDS, ®s[0]); - if (err < 0) - return err; - - if (regs[0] & REG_SECONDS_OS) - return -EAGAIN; - } + if (regs[0] & REG_SECONDS_OS) + return -EINVAL; tm->tm_sec = bcd2bin(regs[0] & 0x7f); tm->tm_min = bcd2bin(regs[1] & 0x7f); @@ -235,6 +215,7 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) return err; regs[0] = REG_SECONDS; + /* This will purposely overwrite REG_SECONDS_OS */ regs[1] = bin2bcd(tm->tm_sec); regs[2] = bin2bcd(tm->tm_min); regs[3] = bin2bcd(tm->tm_hour); -- cgit v0.10.2 From 64232fc33a5bcc29aeb001e1bee80e17a889b4fb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 1 Mar 2016 17:59:57 +0100 Subject: rtc: generic: allow building on all architectures There are four architectures using this driver, but since we can build it with COMPILE_TEST, we should try dealing with the absence of the asm/rtc.h header file, to avoid getting a build error: drivers/rtc/rtc-generic.c:12:21: fatal error: asm/rtc.h: No such file or directory This creates an alternative use of the driver, allowing architectures to pass a set of rtc_class_ops in platform data. We can convert the four architectures to use this and then remove the original code. Signed-off-by: Arnd Bergmann Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-generic.c b/drivers/rtc/rtc-generic.c index e782ebd..d726c6a 100644 --- a/drivers/rtc/rtc-generic.c +++ b/drivers/rtc/rtc-generic.c @@ -9,6 +9,8 @@ #include #include +#if defined(CONFIG_M68K) || defined(CONFIG_PARISC) || \ + defined(CONFIG_PPC) || defined(CONFIG_SUPERH32) #include static int generic_get_time(struct device *dev, struct rtc_time *tm) @@ -33,13 +35,21 @@ static const struct rtc_class_ops generic_rtc_ops = { .read_time = generic_get_time, .set_time = generic_set_time, }; +#else +#define generic_rtc_ops *(struct rtc_class_ops*)NULL +#endif static int __init generic_rtc_probe(struct platform_device *dev) { struct rtc_device *rtc; + const struct rtc_class_ops *ops; + + ops = dev_get_platdata(&dev->dev); + if (!ops) + ops = &generic_rtc_ops; rtc = devm_rtc_device_register(&dev->dev, "rtc-generic", - &generic_rtc_ops, THIS_MODULE); + ops, THIS_MODULE); if (IS_ERR(rtc)) return PTR_ERR(rtc); -- cgit v0.10.2 From 7a587eae2a8b6eeb7919fd25f686fa20b14f4821 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 3 May 2015 11:00:57 +0200 Subject: rtc: enable COMPILE_TEST There are several arch-specific RTC drivers that can be successfully compiled on other platforms. Add a COMPILE_TEST dependency for those. Signed-off-by: Alexandre Belloni Acked-by: Geert Uytterhoeven diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 88254d3..cf0d085 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1094,7 +1094,7 @@ config RTC_DRV_WM8350 config RTC_DRV_SPEAR tristate "SPEAR ST RTC" - depends on PLAT_SPEAR + depends on PLAT_SPEAR || COMPILE_TEST default y help If you say Y here you will get support for the RTC found on @@ -1126,7 +1126,7 @@ config RTC_DRV_AB8500 config RTC_DRV_NUC900 tristate "NUC910/NUC920 RTC driver" - depends on ARCH_W90X900 + depends on ARCH_W90X900 || COMPILE_TEST help If you say yes here you get support for the RTC subsystem of the NUC910/NUC920 used in embedded systems. @@ -1163,7 +1163,7 @@ config RTC_DRV_ASM9260 config RTC_DRV_DAVINCI tristate "TI DaVinci RTC" - depends on ARCH_DAVINCI_DM365 + depends on ARCH_DAVINCI_DM365 || COMPILE_TEST help If you say yes here you get support for the RTC on the DaVinci platforms (DM365). @@ -1173,7 +1173,7 @@ config RTC_DRV_DAVINCI config RTC_DRV_DIGICOLOR tristate "Conexant Digicolor RTC" - depends on ARCH_DIGICOLOR + depends on ARCH_DIGICOLOR || COMPILE_TEST help If you say yes here you get support for the RTC on Conexant Digicolor platforms. This currently includes the CX92755 SoC. @@ -1192,7 +1192,7 @@ config RTC_DRV_IMXDI config RTC_DRV_OMAP tristate "TI OMAP Real Time Clock" - depends on ARCH_OMAP || ARCH_DAVINCI + depends on ARCH_OMAP || ARCH_DAVINCI || COMPILE_TEST help Say "yes" here to support the on chip real time clock present on TI OMAP1, AM33xx, DA8xx/OMAP-L13x, AM43xx and DRA7xx. @@ -1209,7 +1209,7 @@ config HAVE_S3C_RTC config RTC_DRV_S3C tristate "Samsung S3C series SoC RTC" - depends on ARCH_S3C64XX || HAVE_S3C_RTC + depends on ARCH_S3C64XX || HAVE_S3C_RTC || COMPILE_TEST help RTC (Realtime Clock) driver for the clock inbuilt into the Samsung S3C24XX series of SoCs. This can provide periodic @@ -1225,7 +1225,7 @@ config RTC_DRV_S3C config RTC_DRV_EP93XX tristate "Cirrus Logic EP93XX" - depends on ARCH_EP93XX + depends on ARCH_EP93XX || COMPILE_TEST help If you say yes here you get support for the RTC embedded in the Cirrus Logic EP93XX processors. @@ -1255,7 +1255,7 @@ config RTC_DRV_SH config RTC_DRV_VR41XX tristate "NEC VR41XX" - depends on CPU_VR41XX + depends on CPU_VR41XX || COMPILE_TEST help If you say Y here you will get access to the real time clock built into your NEC VR41XX CPU. @@ -1285,14 +1285,14 @@ config RTC_DRV_PL031 config RTC_DRV_AT32AP700X tristate "AT32AP700X series RTC" - depends on PLATFORM_AT32AP + depends on PLATFORM_AT32AP || COMPILE_TEST help Driver for the internal RTC (Realtime Clock) on Atmel AVR32 AT32AP700x family processors. config RTC_DRV_AT91RM9200 tristate "AT91RM9200 or some AT91SAM9 RTC" - depends on ARCH_AT91 + depends on ARCH_AT91 || COMPILE_TEST help Driver for the internal RTC (Realtime Clock) module found on Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips @@ -1300,7 +1300,7 @@ config RTC_DRV_AT91RM9200 config RTC_DRV_AT91SAM9 tristate "AT91SAM9 RTT as RTC" - depends on ARCH_AT91 + depends on ARCH_AT91 || COMPILE_TEST select MFD_SYSCON help Some AT91SAM9 SoCs provide an RTT (Real Time Timer) block which @@ -1342,7 +1342,7 @@ config RTC_DRV_GENERIC tristate "Generic RTC support" # Please consider writing a new RTC driver instead of using the generic # RTC abstraction - depends on PARISC || M68K || PPC || SUPERH32 + depends on PARISC || M68K || PPC || SUPERH32 || COMPILE_TEST help Say Y or M here to enable RTC support on systems using the generic RTC abstraction. If you do not know what you are doing, you should @@ -1362,7 +1362,7 @@ config RTC_DRV_PXA config RTC_DRV_VT8500 tristate "VIA/WonderMedia 85xx SoC RTC" - depends on ARCH_VT8500 + depends on ARCH_VT8500 || COMPILE_TEST help If you say Y here you will get access to the real time clock built into your VIA VT8500 SoC or its relatives. @@ -1377,7 +1377,7 @@ config RTC_DRV_SUN4V config RTC_DRV_SUN6I tristate "Allwinner A31 RTC" - default MACH_SUN6I || MACH_SUN8I + default MACH_SUN6I || MACH_SUN8I || COMPILE_TEST depends on ARCH_SUNXI help If you say Y here you will get support for the RTC found in @@ -1385,7 +1385,7 @@ config RTC_DRV_SUN6I config RTC_DRV_SUNXI tristate "Allwinner sun4i/sun7i RTC" - depends on MACH_SUN4I || MACH_SUN7I + depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST help If you say Y here you will get support for the RTC found on Allwinner A10/A20. @@ -1406,7 +1406,7 @@ config RTC_DRV_TX4939 config RTC_DRV_MV tristate "Marvell SoC RTC" - depends on ARCH_DOVE || ARCH_MVEBU + depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST help If you say yes here you will get support for the in-chip RTC that can be found in some of Marvell's SoC devices, such as @@ -1417,7 +1417,7 @@ config RTC_DRV_MV config RTC_DRV_ARMADA38X tristate "Armada 38x Marvell SoC RTC" - depends on ARCH_MVEBU + depends on ARCH_MVEBU || COMPILE_TEST help If you say yes here you will get support for the in-chip RTC that can be found in the Armada 38x Marvell's SoC device @@ -1447,7 +1447,7 @@ config RTC_DRV_PS3 config RTC_DRV_COH901331 tristate "ST-Ericsson COH 901 331 RTC" - depends on ARCH_U300 + depends on ARCH_U300 || COMPILE_TEST help If you say Y here you will get access to ST-Ericsson COH 901 331 RTC clock found in some ST-Ericsson Mobile @@ -1459,7 +1459,7 @@ config RTC_DRV_COH901331 config RTC_DRV_STMP tristate "Freescale STMP3xxx/i.MX23/i.MX28 RTC" - depends on ARCH_MXS + depends on ARCH_MXS || COMPILE_TEST select STMP_DEVICE help If you say yes here you will get support for the onboard @@ -1494,7 +1494,7 @@ config RTC_DRV_MPC5121 config RTC_DRV_JZ4740 tristate "Ingenic JZ4740 SoC" - depends on MACH_JZ4740 + depends on MACH_JZ4740 || COMPILE_TEST help If you say yes here you get support for the Ingenic JZ4740 SoC RTC controller. @@ -1515,7 +1515,7 @@ config RTC_DRV_LPC24XX so, the module will be called rtc-lpc24xx. config RTC_DRV_LPC32XX - depends on ARCH_LPC32XX + depends on ARCH_LPC32XX || COMPILE_TEST tristate "NXP LPC32XX RTC" help This enables support for the NXP RTC in the LPC32XX @@ -1525,7 +1525,7 @@ config RTC_DRV_LPC32XX config RTC_DRV_PM8XXX tristate "Qualcomm PMIC8XXX RTC" - depends on MFD_PM8XXX || MFD_SPMI_PMIC + depends on MFD_PM8XXX || MFD_SPMI_PMIC || COMPILE_TEST help If you say yes here you get support for the Qualcomm PMIC8XXX RTC. @@ -1535,7 +1535,7 @@ config RTC_DRV_PM8XXX config RTC_DRV_TEGRA tristate "NVIDIA Tegra Internal RTC driver" - depends on ARCH_TEGRA + depends on ARCH_TEGRA || COMPILE_TEST help If you say yes here you get support for the Tegra 200 series internal RTC module. -- cgit v0.10.2 From aba39d27bdb2e92b22f0cd1b29adb3a86d781d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20B=C3=BCsch?= Date: Fri, 4 Mar 2016 22:38:45 +0100 Subject: rtc: rv3029: Remove all 'C2' suffixes from identifiers The C2 suffix does not appear anymore in the latest device and data sheet versions. Signed-off-by: Michael Buesch Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index e9ac5a4..3083ace 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -1,5 +1,5 @@ /* - * Micro Crystal RV-3029C2 rtc class driver + * Micro Crystal RV-3029 rtc class driver * * Author: Gregory Hermant * @@ -21,77 +21,77 @@ /* Register map */ /* control section */ -#define RV3029C2_ONOFF_CTRL 0x00 -#define RV3029C2_IRQ_CTRL 0x01 -#define RV3029C2_IRQ_CTRL_AIE (1 << 0) -#define RV3029C2_IRQ_FLAGS 0x02 -#define RV3029C2_IRQ_FLAGS_AF (1 << 0) -#define RV3029C2_STATUS 0x03 -#define RV3029C2_STATUS_VLOW1 (1 << 2) -#define RV3029C2_STATUS_VLOW2 (1 << 3) -#define RV3029C2_STATUS_SR (1 << 4) -#define RV3029C2_STATUS_PON (1 << 5) -#define RV3029C2_STATUS_EEBUSY (1 << 7) -#define RV3029C2_RST_CTRL 0x04 -#define RV3029C2_CONTROL_SECTION_LEN 0x05 +#define RV3029_ONOFF_CTRL 0x00 +#define RV3029_IRQ_CTRL 0x01 +#define RV3029_IRQ_CTRL_AIE (1 << 0) +#define RV3029_IRQ_FLAGS 0x02 +#define RV3029_IRQ_FLAGS_AF (1 << 0) +#define RV3029_STATUS 0x03 +#define RV3029_STATUS_VLOW1 (1 << 2) +#define RV3029_STATUS_VLOW2 (1 << 3) +#define RV3029_STATUS_SR (1 << 4) +#define RV3029_STATUS_PON (1 << 5) +#define RV3029_STATUS_EEBUSY (1 << 7) +#define RV3029_RST_CTRL 0x04 +#define RV3029_CONTROL_SECTION_LEN 0x05 /* watch section */ -#define RV3029C2_W_SEC 0x08 -#define RV3029C2_W_MINUTES 0x09 -#define RV3029C2_W_HOURS 0x0A -#define RV3029C2_REG_HR_12_24 (1<<6) /* 24h/12h mode */ -#define RV3029C2_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ -#define RV3029C2_W_DATE 0x0B -#define RV3029C2_W_DAYS 0x0C -#define RV3029C2_W_MONTHS 0x0D -#define RV3029C2_W_YEARS 0x0E -#define RV3029C2_WATCH_SECTION_LEN 0x07 +#define RV3029_W_SEC 0x08 +#define RV3029_W_MINUTES 0x09 +#define RV3029_W_HOURS 0x0A +#define RV3029_REG_HR_12_24 (1<<6) /* 24h/12h mode */ +#define RV3029_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ +#define RV3029_W_DATE 0x0B +#define RV3029_W_DAYS 0x0C +#define RV3029_W_MONTHS 0x0D +#define RV3029_W_YEARS 0x0E +#define RV3029_WATCH_SECTION_LEN 0x07 /* alarm section */ -#define RV3029C2_A_SC 0x10 -#define RV3029C2_A_MN 0x11 -#define RV3029C2_A_HR 0x12 -#define RV3029C2_A_DT 0x13 -#define RV3029C2_A_DW 0x14 -#define RV3029C2_A_MO 0x15 -#define RV3029C2_A_YR 0x16 -#define RV3029C2_ALARM_SECTION_LEN 0x07 +#define RV3029_A_SC 0x10 +#define RV3029_A_MN 0x11 +#define RV3029_A_HR 0x12 +#define RV3029_A_DT 0x13 +#define RV3029_A_DW 0x14 +#define RV3029_A_MO 0x15 +#define RV3029_A_YR 0x16 +#define RV3029_ALARM_SECTION_LEN 0x07 /* timer section */ -#define RV3029C2_TIMER_LOW 0x18 -#define RV3029C2_TIMER_HIGH 0x19 +#define RV3029_TIMER_LOW 0x18 +#define RV3029_TIMER_HIGH 0x19 /* temperature section */ -#define RV3029C2_TEMP_PAGE 0x20 +#define RV3029_TEMP_PAGE 0x20 /* eeprom data section */ -#define RV3029C2_E2P_EEDATA1 0x28 -#define RV3029C2_E2P_EEDATA2 0x29 +#define RV3029_E2P_EEDATA1 0x28 +#define RV3029_E2P_EEDATA2 0x29 /* eeprom control section */ -#define RV3029C2_CONTROL_E2P_EECTRL 0x30 -#define RV3029C2_TRICKLE_1K (1<<0) /* 1K resistance */ -#define RV3029C2_TRICKLE_5K (1<<1) /* 5K resistance */ -#define RV3029C2_TRICKLE_20K (1<<2) /* 20K resistance */ -#define RV3029C2_TRICKLE_80K (1<<3) /* 80K resistance */ -#define RV3029C2_CONTROL_E2P_XTALOFFSET 0x31 -#define RV3029C2_CONTROL_E2P_QCOEF 0x32 -#define RV3029C2_CONTROL_E2P_TURNOVER 0x33 +#define RV3029_CONTROL_E2P_EECTRL 0x30 +#define RV3029_TRICKLE_1K (1<<0) /* 1K resistance */ +#define RV3029_TRICKLE_5K (1<<1) /* 5K resistance */ +#define RV3029_TRICKLE_20K (1<<2) /* 20K resistance */ +#define RV3029_TRICKLE_80K (1<<3) /* 80K resistance */ +#define RV3029_CONTROL_E2P_XTALOFFSET 0x31 +#define RV3029_CONTROL_E2P_QCOEF 0x32 +#define RV3029_CONTROL_E2P_TURNOVER 0x33 /* user ram section */ -#define RV3029C2_USR1_RAM_PAGE 0x38 -#define RV3029C2_USR1_SECTION_LEN 0x04 -#define RV3029C2_USR2_RAM_PAGE 0x3C -#define RV3029C2_USR2_SECTION_LEN 0x04 +#define RV3029_USR1_RAM_PAGE 0x38 +#define RV3029_USR1_SECTION_LEN 0x04 +#define RV3029_USR2_RAM_PAGE 0x3C +#define RV3029_USR2_SECTION_LEN 0x04 static int -rv3029c2_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf, - unsigned len) +rv3029_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf, + unsigned len) { int ret; - if ((reg > RV3029C2_USR1_RAM_PAGE + 7) || - (reg + len > RV3029C2_USR1_RAM_PAGE + 8)) + if ((reg > RV3029_USR1_RAM_PAGE + 7) || + (reg + len > RV3029_USR1_RAM_PAGE + 8)) return -EINVAL; ret = i2c_smbus_read_i2c_block_data(client, reg, len, buf); @@ -103,20 +103,20 @@ rv3029c2_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf, } static int -rv3029c2_i2c_write_regs(struct i2c_client *client, u8 reg, u8 const buf[], - unsigned len) +rv3029_i2c_write_regs(struct i2c_client *client, u8 reg, u8 const buf[], + unsigned len) { - if ((reg > RV3029C2_USR1_RAM_PAGE + 7) || - (reg + len > RV3029C2_USR1_RAM_PAGE + 8)) + if ((reg > RV3029_USR1_RAM_PAGE + 7) || + (reg + len > RV3029_USR1_RAM_PAGE + 8)) return -EINVAL; return i2c_smbus_write_i2c_block_data(client, reg, len, buf); } static int -rv3029c2_i2c_get_sr(struct i2c_client *client, u8 *buf) +rv3029_i2c_get_sr(struct i2c_client *client, u8 *buf) { - int ret = rv3029c2_i2c_read_regs(client, RV3029C2_STATUS, buf, 1); + int ret = rv3029_i2c_read_regs(client, RV3029_STATUS, buf, 1); if (ret < 0) return -EIO; @@ -125,13 +125,13 @@ rv3029c2_i2c_get_sr(struct i2c_client *client, u8 *buf) } static int -rv3029c2_i2c_set_sr(struct i2c_client *client, u8 val) +rv3029_i2c_set_sr(struct i2c_client *client, u8 val) { u8 buf[1]; int sr; buf[0] = val; - sr = rv3029c2_i2c_write_regs(client, RV3029C2_STATUS, buf, 1); + sr = rv3029_i2c_write_regs(client, RV3029_STATUS, buf, 1); dev_dbg(&client->dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]); if (sr < 0) return -EIO; @@ -139,69 +139,70 @@ rv3029c2_i2c_set_sr(struct i2c_client *client, u8 val) } static int -rv3029c2_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) +rv3029_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) { u8 buf[1]; int ret; - u8 regs[RV3029C2_WATCH_SECTION_LEN] = { 0, }; + u8 regs[RV3029_WATCH_SECTION_LEN] = { 0, }; - ret = rv3029c2_i2c_get_sr(client, buf); + ret = rv3029_i2c_get_sr(client, buf); if (ret < 0) { dev_err(&client->dev, "%s: reading SR failed\n", __func__); return -EIO; } - ret = rv3029c2_i2c_read_regs(client, RV3029C2_W_SEC , regs, - RV3029C2_WATCH_SECTION_LEN); + ret = rv3029_i2c_read_regs(client, RV3029_W_SEC, regs, + RV3029_WATCH_SECTION_LEN); if (ret < 0) { dev_err(&client->dev, "%s: reading RTC section failed\n", __func__); return ret; } - tm->tm_sec = bcd2bin(regs[RV3029C2_W_SEC-RV3029C2_W_SEC]); - tm->tm_min = bcd2bin(regs[RV3029C2_W_MINUTES-RV3029C2_W_SEC]); + tm->tm_sec = bcd2bin(regs[RV3029_W_SEC-RV3029_W_SEC]); + tm->tm_min = bcd2bin(regs[RV3029_W_MINUTES-RV3029_W_SEC]); /* HR field has a more complex interpretation */ { - const u8 _hr = regs[RV3029C2_W_HOURS-RV3029C2_W_SEC]; - if (_hr & RV3029C2_REG_HR_12_24) { + const u8 _hr = regs[RV3029_W_HOURS-RV3029_W_SEC]; + + if (_hr & RV3029_REG_HR_12_24) { /* 12h format */ tm->tm_hour = bcd2bin(_hr & 0x1f); - if (_hr & RV3029C2_REG_HR_PM) /* PM flag set */ + if (_hr & RV3029_REG_HR_PM) /* PM flag set */ tm->tm_hour += 12; } else /* 24h format */ tm->tm_hour = bcd2bin(_hr & 0x3f); } - tm->tm_mday = bcd2bin(regs[RV3029C2_W_DATE-RV3029C2_W_SEC]); - tm->tm_mon = bcd2bin(regs[RV3029C2_W_MONTHS-RV3029C2_W_SEC]) - 1; - tm->tm_year = bcd2bin(regs[RV3029C2_W_YEARS-RV3029C2_W_SEC]) + 100; - tm->tm_wday = bcd2bin(regs[RV3029C2_W_DAYS-RV3029C2_W_SEC]) - 1; + tm->tm_mday = bcd2bin(regs[RV3029_W_DATE-RV3029_W_SEC]); + tm->tm_mon = bcd2bin(regs[RV3029_W_MONTHS-RV3029_W_SEC]) - 1; + tm->tm_year = bcd2bin(regs[RV3029_W_YEARS-RV3029_W_SEC]) + 100; + tm->tm_wday = bcd2bin(regs[RV3029_W_DAYS-RV3029_W_SEC]) - 1; return 0; } -static int rv3029c2_rtc_read_time(struct device *dev, struct rtc_time *tm) +static int rv3029_rtc_read_time(struct device *dev, struct rtc_time *tm) { - return rv3029c2_i2c_read_time(to_i2c_client(dev), tm); + return rv3029_i2c_read_time(to_i2c_client(dev), tm); } static int -rv3029c2_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) +rv3029_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) { struct rtc_time *const tm = &alarm->time; int ret; u8 regs[8]; - ret = rv3029c2_i2c_get_sr(client, regs); + ret = rv3029_i2c_get_sr(client, regs); if (ret < 0) { dev_err(&client->dev, "%s: reading SR failed\n", __func__); return -EIO; } - ret = rv3029c2_i2c_read_regs(client, RV3029C2_A_SC, regs, - RV3029C2_ALARM_SECTION_LEN); + ret = rv3029_i2c_read_regs(client, RV3029_A_SC, regs, + RV3029_ALARM_SECTION_LEN); if (ret < 0) { dev_err(&client->dev, "%s: reading alarm section failed\n", @@ -209,41 +210,41 @@ rv3029c2_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) return ret; } - tm->tm_sec = bcd2bin(regs[RV3029C2_A_SC-RV3029C2_A_SC] & 0x7f); - tm->tm_min = bcd2bin(regs[RV3029C2_A_MN-RV3029C2_A_SC] & 0x7f); - tm->tm_hour = bcd2bin(regs[RV3029C2_A_HR-RV3029C2_A_SC] & 0x3f); - tm->tm_mday = bcd2bin(regs[RV3029C2_A_DT-RV3029C2_A_SC] & 0x3f); - tm->tm_mon = bcd2bin(regs[RV3029C2_A_MO-RV3029C2_A_SC] & 0x1f) - 1; - tm->tm_year = bcd2bin(regs[RV3029C2_A_YR-RV3029C2_A_SC] & 0x7f) + 100; - tm->tm_wday = bcd2bin(regs[RV3029C2_A_DW-RV3029C2_A_SC] & 0x07) - 1; + tm->tm_sec = bcd2bin(regs[RV3029_A_SC-RV3029_A_SC] & 0x7f); + tm->tm_min = bcd2bin(regs[RV3029_A_MN-RV3029_A_SC] & 0x7f); + tm->tm_hour = bcd2bin(regs[RV3029_A_HR-RV3029_A_SC] & 0x3f); + tm->tm_mday = bcd2bin(regs[RV3029_A_DT-RV3029_A_SC] & 0x3f); + tm->tm_mon = bcd2bin(regs[RV3029_A_MO-RV3029_A_SC] & 0x1f) - 1; + tm->tm_year = bcd2bin(regs[RV3029_A_YR-RV3029_A_SC] & 0x7f) + 100; + tm->tm_wday = bcd2bin(regs[RV3029_A_DW-RV3029_A_SC] & 0x07) - 1; return 0; } static int -rv3029c2_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +rv3029_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - return rv3029c2_i2c_read_alarm(to_i2c_client(dev), alarm); + return rv3029_i2c_read_alarm(to_i2c_client(dev), alarm); } -static int rv3029c2_rtc_i2c_alarm_set_irq(struct i2c_client *client, +static int rv3029_rtc_i2c_alarm_set_irq(struct i2c_client *client, int enable) { int ret; u8 buf[1]; /* enable AIE irq */ - ret = rv3029c2_i2c_read_regs(client, RV3029C2_IRQ_CTRL, buf, 1); + ret = rv3029_i2c_read_regs(client, RV3029_IRQ_CTRL, buf, 1); if (ret < 0) { dev_err(&client->dev, "can't read INT reg\n"); return ret; } if (enable) - buf[0] |= RV3029C2_IRQ_CTRL_AIE; + buf[0] |= RV3029_IRQ_CTRL_AIE; else - buf[0] &= ~RV3029C2_IRQ_CTRL_AIE; + buf[0] &= ~RV3029_IRQ_CTRL_AIE; - ret = rv3029c2_i2c_write_regs(client, RV3029C2_IRQ_CTRL, buf, 1); + ret = rv3029_i2c_write_regs(client, RV3029_IRQ_CTRL, buf, 1); if (ret < 0) { dev_err(&client->dev, "can't set INT reg\n"); return ret; @@ -252,8 +253,8 @@ static int rv3029c2_rtc_i2c_alarm_set_irq(struct i2c_client *client, return 0; } -static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client, - struct rtc_wkalrm *alarm) +static int rv3029_rtc_i2c_set_alarm(struct i2c_client *client, + struct rtc_wkalrm *alarm) { struct rtc_time *const tm = &alarm->time; int ret; @@ -267,21 +268,21 @@ static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client, if (tm->tm_year < 100) return -EINVAL; - ret = rv3029c2_i2c_get_sr(client, regs); + ret = rv3029_i2c_get_sr(client, regs); if (ret < 0) { dev_err(&client->dev, "%s: reading SR failed\n", __func__); return -EIO; } - regs[RV3029C2_A_SC-RV3029C2_A_SC] = bin2bcd(tm->tm_sec & 0x7f); - regs[RV3029C2_A_MN-RV3029C2_A_SC] = bin2bcd(tm->tm_min & 0x7f); - regs[RV3029C2_A_HR-RV3029C2_A_SC] = bin2bcd(tm->tm_hour & 0x3f); - regs[RV3029C2_A_DT-RV3029C2_A_SC] = bin2bcd(tm->tm_mday & 0x3f); - regs[RV3029C2_A_MO-RV3029C2_A_SC] = bin2bcd((tm->tm_mon & 0x1f) - 1); - regs[RV3029C2_A_DW-RV3029C2_A_SC] = bin2bcd((tm->tm_wday & 7) - 1); - regs[RV3029C2_A_YR-RV3029C2_A_SC] = bin2bcd((tm->tm_year & 0x7f) - 100); - - ret = rv3029c2_i2c_write_regs(client, RV3029C2_A_SC, regs, - RV3029C2_ALARM_SECTION_LEN); + regs[RV3029_A_SC-RV3029_A_SC] = bin2bcd(tm->tm_sec & 0x7f); + regs[RV3029_A_MN-RV3029_A_SC] = bin2bcd(tm->tm_min & 0x7f); + regs[RV3029_A_HR-RV3029_A_SC] = bin2bcd(tm->tm_hour & 0x3f); + regs[RV3029_A_DT-RV3029_A_SC] = bin2bcd(tm->tm_mday & 0x3f); + regs[RV3029_A_MO-RV3029_A_SC] = bin2bcd((tm->tm_mon & 0x1f) - 1); + regs[RV3029_A_DW-RV3029_A_SC] = bin2bcd((tm->tm_wday & 7) - 1); + regs[RV3029_A_YR-RV3029_A_SC] = bin2bcd((tm->tm_year & 0x7f) - 100); + + ret = rv3029_i2c_write_regs(client, RV3029_A_SC, regs, + RV3029_ALARM_SECTION_LEN); if (ret < 0) return ret; @@ -289,28 +290,28 @@ static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client, u8 buf[1]; /* clear AF flag */ - ret = rv3029c2_i2c_read_regs(client, RV3029C2_IRQ_FLAGS, - buf, 1); + ret = rv3029_i2c_read_regs(client, RV3029_IRQ_FLAGS, + buf, 1); if (ret < 0) { dev_err(&client->dev, "can't read alarm flag\n"); return ret; } - buf[0] &= ~RV3029C2_IRQ_FLAGS_AF; - ret = rv3029c2_i2c_write_regs(client, RV3029C2_IRQ_FLAGS, - buf, 1); + buf[0] &= ~RV3029_IRQ_FLAGS_AF; + ret = rv3029_i2c_write_regs(client, RV3029_IRQ_FLAGS, + buf, 1); if (ret < 0) { dev_err(&client->dev, "can't set alarm flag\n"); return ret; } /* enable AIE irq */ - ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 1); + ret = rv3029_rtc_i2c_alarm_set_irq(client, 1); if (ret) return ret; dev_dbg(&client->dev, "alarm IRQ armed\n"); } else { /* disable AIE irq */ - ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 0); + ret = rv3029_rtc_i2c_alarm_set_irq(client, 0); if (ret) return ret; @@ -320,13 +321,13 @@ static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client, return 0; } -static int rv3029c2_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +static int rv3029_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - return rv3029c2_rtc_i2c_set_alarm(to_i2c_client(dev), alarm); + return rv3029_rtc_i2c_set_alarm(to_i2c_client(dev), alarm); } static int -rv3029c2_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm) +rv3029_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm) { u8 regs[8]; int ret; @@ -339,26 +340,26 @@ rv3029c2_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm) if (tm->tm_year < 100) return -EINVAL; - regs[RV3029C2_W_SEC-RV3029C2_W_SEC] = bin2bcd(tm->tm_sec); - regs[RV3029C2_W_MINUTES-RV3029C2_W_SEC] = bin2bcd(tm->tm_min); - regs[RV3029C2_W_HOURS-RV3029C2_W_SEC] = bin2bcd(tm->tm_hour); - regs[RV3029C2_W_DATE-RV3029C2_W_SEC] = bin2bcd(tm->tm_mday); - regs[RV3029C2_W_MONTHS-RV3029C2_W_SEC] = bin2bcd(tm->tm_mon+1); - regs[RV3029C2_W_DAYS-RV3029C2_W_SEC] = bin2bcd((tm->tm_wday & 7)+1); - regs[RV3029C2_W_YEARS-RV3029C2_W_SEC] = bin2bcd(tm->tm_year - 100); + regs[RV3029_W_SEC-RV3029_W_SEC] = bin2bcd(tm->tm_sec); + regs[RV3029_W_MINUTES-RV3029_W_SEC] = bin2bcd(tm->tm_min); + regs[RV3029_W_HOURS-RV3029_W_SEC] = bin2bcd(tm->tm_hour); + regs[RV3029_W_DATE-RV3029_W_SEC] = bin2bcd(tm->tm_mday); + regs[RV3029_W_MONTHS-RV3029_W_SEC] = bin2bcd(tm->tm_mon+1); + regs[RV3029_W_DAYS-RV3029_W_SEC] = bin2bcd((tm->tm_wday & 7)+1); + regs[RV3029_W_YEARS-RV3029_W_SEC] = bin2bcd(tm->tm_year - 100); - ret = rv3029c2_i2c_write_regs(client, RV3029C2_W_SEC, regs, - RV3029C2_WATCH_SECTION_LEN); + ret = rv3029_i2c_write_regs(client, RV3029_W_SEC, regs, + RV3029_WATCH_SECTION_LEN); if (ret < 0) return ret; - ret = rv3029c2_i2c_get_sr(client, regs); + ret = rv3029_i2c_get_sr(client, regs); if (ret < 0) { dev_err(&client->dev, "%s: reading SR failed\n", __func__); return ret; } /* clear PON bit */ - ret = rv3029c2_i2c_set_sr(client, (regs[0] & ~RV3029C2_STATUS_PON)); + ret = rv3029_i2c_set_sr(client, (regs[0] & ~RV3029_STATUS_PON)); if (ret < 0) { dev_err(&client->dev, "%s: reading SR failed\n", __func__); return ret; @@ -367,26 +368,26 @@ rv3029c2_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm) return 0; } -static int rv3029c2_rtc_set_time(struct device *dev, struct rtc_time *tm) +static int rv3029_rtc_set_time(struct device *dev, struct rtc_time *tm) { - return rv3029c2_i2c_set_time(to_i2c_client(dev), tm); + return rv3029_i2c_set_time(to_i2c_client(dev), tm); } -static const struct rtc_class_ops rv3029c2_rtc_ops = { - .read_time = rv3029c2_rtc_read_time, - .set_time = rv3029c2_rtc_set_time, - .read_alarm = rv3029c2_rtc_read_alarm, - .set_alarm = rv3029c2_rtc_set_alarm, +static const struct rtc_class_ops rv3029_rtc_ops = { + .read_time = rv3029_rtc_read_time, + .set_time = rv3029_rtc_set_time, + .read_alarm = rv3029_rtc_read_alarm, + .set_alarm = rv3029_rtc_set_alarm, }; -static struct i2c_device_id rv3029c2_id[] = { +static struct i2c_device_id rv3029_id[] = { { "rv3029c2", 0 }, { } }; -MODULE_DEVICE_TABLE(i2c, rv3029c2_id); +MODULE_DEVICE_TABLE(i2c, rv3029_id); -static int rv3029c2_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int rv3029_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct rtc_device *rtc; int rc = 0; @@ -395,14 +396,14 @@ static int rv3029c2_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_EMUL)) return -ENODEV; - rc = rv3029c2_i2c_get_sr(client, buf); + rc = rv3029_i2c_get_sr(client, buf); if (rc < 0) { dev_err(&client->dev, "reading status failed\n"); return rc; } rtc = devm_rtc_device_register(&client->dev, client->name, - &rv3029c2_rtc_ops, THIS_MODULE); + &rv3029_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) return PTR_ERR(rtc); @@ -412,16 +413,16 @@ static int rv3029c2_probe(struct i2c_client *client, return 0; } -static struct i2c_driver rv3029c2_driver = { +static struct i2c_driver rv3029_driver = { .driver = { .name = "rtc-rv3029c2", }, - .probe = rv3029c2_probe, - .id_table = rv3029c2_id, + .probe = rv3029_probe, + .id_table = rv3029_id, }; -module_i2c_driver(rv3029c2_driver); +module_i2c_driver(rv3029_driver); MODULE_AUTHOR("Gregory Hermant "); -MODULE_DESCRIPTION("Micro Crystal RV3029C2 RTC driver"); +MODULE_DESCRIPTION("Micro Crystal RV3029 RTC driver"); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From baba623f124423797443401a667cdeb714a26d1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20B=C3=BCsch?= Date: Fri, 4 Mar 2016 22:39:17 +0100 Subject: rtc: rv3029: Add "rv3029" I2C device id The C2 suffix does not appear in the latest datasheet, so add a device ID without it. Signed-off-by: Michael Buesch Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index 3083ace..fc0dbc4 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -381,6 +381,7 @@ static const struct rtc_class_ops rv3029_rtc_ops = { }; static struct i2c_device_id rv3029_id[] = { + { "rv3029", 0 }, { "rv3029c2", 0 }, { } }; -- cgit v0.10.2 From 7697de35faf02b5b04d1cb53e44cd42658610fe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20B=C3=BCsch?= Date: Fri, 4 Mar 2016 22:39:49 +0100 Subject: rtc: rv3029: Add missing register definitions This adds all (according to the data sheet) missing register and bit definitions. It also fixes the definition of the trickle charger bit masks. Signed-off-by: Michael Buesch Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index fc0dbc4..29cc871 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -22,25 +22,42 @@ /* Register map */ /* control section */ #define RV3029_ONOFF_CTRL 0x00 +#define RV3029_ONOFF_CTRL_WE BIT(0) +#define RV3029_ONOFF_CTRL_TE BIT(1) +#define RV3029_ONOFF_CTRL_TAR BIT(2) +#define RV3029_ONOFF_CTRL_EERE BIT(3) +#define RV3029_ONOFF_CTRL_SRON BIT(4) +#define RV3029_ONOFF_CTRL_TD0 BIT(5) +#define RV3029_ONOFF_CTRL_TD1 BIT(6) +#define RV3029_ONOFF_CTRL_CLKINT BIT(7) #define RV3029_IRQ_CTRL 0x01 -#define RV3029_IRQ_CTRL_AIE (1 << 0) +#define RV3029_IRQ_CTRL_AIE BIT(0) +#define RV3029_IRQ_CTRL_TIE BIT(1) +#define RV3029_IRQ_CTRL_V1IE BIT(2) +#define RV3029_IRQ_CTRL_V2IE BIT(3) +#define RV3029_IRQ_CTRL_SRIE BIT(4) #define RV3029_IRQ_FLAGS 0x02 -#define RV3029_IRQ_FLAGS_AF (1 << 0) +#define RV3029_IRQ_FLAGS_AF BIT(0) +#define RV3029_IRQ_FLAGS_TF BIT(1) +#define RV3029_IRQ_FLAGS_V1IF BIT(2) +#define RV3029_IRQ_FLAGS_V2IF BIT(3) +#define RV3029_IRQ_FLAGS_SRF BIT(4) #define RV3029_STATUS 0x03 -#define RV3029_STATUS_VLOW1 (1 << 2) -#define RV3029_STATUS_VLOW2 (1 << 3) -#define RV3029_STATUS_SR (1 << 4) -#define RV3029_STATUS_PON (1 << 5) -#define RV3029_STATUS_EEBUSY (1 << 7) +#define RV3029_STATUS_VLOW1 BIT(2) +#define RV3029_STATUS_VLOW2 BIT(3) +#define RV3029_STATUS_SR BIT(4) +#define RV3029_STATUS_PON BIT(5) +#define RV3029_STATUS_EEBUSY BIT(7) #define RV3029_RST_CTRL 0x04 +#define RV3029_RST_CTRL_SYSR BIT(4) #define RV3029_CONTROL_SECTION_LEN 0x05 /* watch section */ #define RV3029_W_SEC 0x08 #define RV3029_W_MINUTES 0x09 #define RV3029_W_HOURS 0x0A -#define RV3029_REG_HR_12_24 (1<<6) /* 24h/12h mode */ -#define RV3029_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ +#define RV3029_REG_HR_12_24 BIT(6) /* 24h/12h mode */ +#define RV3029_REG_HR_PM BIT(5) /* PM/AM bit in 12h mode */ #define RV3029_W_DATE 0x0B #define RV3029_W_DAYS 0x0C #define RV3029_W_MONTHS 0x0D @@ -67,16 +84,28 @@ /* eeprom data section */ #define RV3029_E2P_EEDATA1 0x28 #define RV3029_E2P_EEDATA2 0x29 +#define RV3029_E2PDATA_SECTION_LEN 0x02 /* eeprom control section */ #define RV3029_CONTROL_E2P_EECTRL 0x30 -#define RV3029_TRICKLE_1K (1<<0) /* 1K resistance */ -#define RV3029_TRICKLE_5K (1<<1) /* 5K resistance */ -#define RV3029_TRICKLE_20K (1<<2) /* 20K resistance */ -#define RV3029_TRICKLE_80K (1<<3) /* 80K resistance */ -#define RV3029_CONTROL_E2P_XTALOFFSET 0x31 -#define RV3029_CONTROL_E2P_QCOEF 0x32 -#define RV3029_CONTROL_E2P_TURNOVER 0x33 +#define RV3029_EECTRL_THP BIT(0) /* temp scan interval */ +#define RV3029_EECTRL_THE BIT(1) /* thermometer enable */ +#define RV3029_EECTRL_FD0 BIT(2) /* CLKOUT */ +#define RV3029_EECTRL_FD1 BIT(3) /* CLKOUT */ +#define RV3029_TRICKLE_1K BIT(4) /* 1.5K resistance */ +#define RV3029_TRICKLE_5K BIT(5) /* 5K resistance */ +#define RV3029_TRICKLE_20K BIT(6) /* 20K resistance */ +#define RV3029_TRICKLE_80K BIT(7) /* 80K resistance */ +#define RV3029_TRICKLE_MASK (RV3029_TRICKLE_1K |\ + RV3029_TRICKLE_5K |\ + RV3029_TRICKLE_20K |\ + RV3029_TRICKLE_80K) +#define RV3029_TRICKLE_SHIFT 4 +#define RV3029_CONTROL_E2P_XOFFS 0x31 /* XTAL offset */ +#define RV3029_CONTROL_E2P_XOFFS_SIGN BIT(7) /* Sign: 1->pos, 0->neg */ +#define RV3029_CONTROL_E2P_QCOEF 0x32 /* XTAL temp drift coef */ +#define RV3029_CONTROL_E2P_TURNOVER 0x33 /* XTAL turnover temp (in *C) */ +#define RV3029_CONTROL_E2P_TOV_MASK 0x3F /* XTAL turnover temp mask */ /* user ram section */ #define RV3029_USR1_RAM_PAGE 0x38 -- cgit v0.10.2 From 2dca3d9e1440162a959d8b2942293bfc6ac14a19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20B=C3=BCsch?= Date: Fri, 4 Mar 2016 22:40:30 +0100 Subject: rtc: rv3029: Add i2c register update-bits helper This simplifies mask/set operations on device I2C registers. Signed-off-by: Michael Buesch Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index 29cc871..a58188e 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -2,6 +2,7 @@ * Micro Crystal RV-3029 rtc class driver * * Author: Gregory Hermant + * Michael Buesch * * based on previously existing rtc class drivers * @@ -143,6 +144,24 @@ rv3029_i2c_write_regs(struct i2c_client *client, u8 reg, u8 const buf[], } static int +rv3029_i2c_update_bits(struct i2c_client *client, u8 reg, u8 mask, u8 set) +{ + u8 buf; + int ret; + + ret = rv3029_i2c_read_regs(client, reg, &buf, 1); + if (ret < 0) + return ret; + buf &= ~mask; + buf |= set & mask; + ret = rv3029_i2c_write_regs(client, reg, &buf, 1); + if (ret < 0) + return ret; + + return 0; +} + +static int rv3029_i2c_get_sr(struct i2c_client *client, u8 *buf) { int ret = rv3029_i2c_read_regs(client, RV3029_STATUS, buf, 1); @@ -260,22 +279,13 @@ static int rv3029_rtc_i2c_alarm_set_irq(struct i2c_client *client, int enable) { int ret; - u8 buf[1]; - - /* enable AIE irq */ - ret = rv3029_i2c_read_regs(client, RV3029_IRQ_CTRL, buf, 1); - if (ret < 0) { - dev_err(&client->dev, "can't read INT reg\n"); - return ret; - } - if (enable) - buf[0] |= RV3029_IRQ_CTRL_AIE; - else - buf[0] &= ~RV3029_IRQ_CTRL_AIE; - ret = rv3029_i2c_write_regs(client, RV3029_IRQ_CTRL, buf, 1); + /* enable/disable AIE irq */ + ret = rv3029_i2c_update_bits(client, RV3029_IRQ_CTRL, + RV3029_IRQ_CTRL_AIE, + (enable ? RV3029_IRQ_CTRL_AIE : 0)); if (ret < 0) { - dev_err(&client->dev, "can't set INT reg\n"); + dev_err(&client->dev, "can't update INT reg\n"); return ret; } @@ -316,20 +326,11 @@ static int rv3029_rtc_i2c_set_alarm(struct i2c_client *client, return ret; if (alarm->enabled) { - u8 buf[1]; - /* clear AF flag */ - ret = rv3029_i2c_read_regs(client, RV3029_IRQ_FLAGS, - buf, 1); - if (ret < 0) { - dev_err(&client->dev, "can't read alarm flag\n"); - return ret; - } - buf[0] &= ~RV3029_IRQ_FLAGS_AF; - ret = rv3029_i2c_write_regs(client, RV3029_IRQ_FLAGS, - buf, 1); + ret = rv3029_i2c_update_bits(client, RV3029_IRQ_FLAGS, + RV3029_IRQ_FLAGS_AF, 0); if (ret < 0) { - dev_err(&client->dev, "can't set alarm flag\n"); + dev_err(&client->dev, "can't clear alarm flag\n"); return ret; } /* enable AIE irq */ @@ -454,5 +455,6 @@ static struct i2c_driver rv3029_driver = { module_i2c_driver(rv3029_driver); MODULE_AUTHOR("Gregory Hermant "); +MODULE_AUTHOR("Michael Buesch "); MODULE_DESCRIPTION("Micro Crystal RV3029 RTC driver"); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From a7f6e287419cf523c769e87bbef748ae7bd856ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20B=C3=BCsch?= Date: Fri, 4 Mar 2016 22:40:55 +0100 Subject: rtc: rv3029: Add functions for EEPROM access This adds functions for access to the EEPROM memory on the rv3029. Signed-off-by: Michael Buesch Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index a58188e..e59b8a5 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -19,6 +19,9 @@ #include #include #include +#include +#include + /* Register map */ /* control section */ @@ -186,6 +189,128 @@ rv3029_i2c_set_sr(struct i2c_client *client, u8 val) return 0; } +static int rv3029_eeprom_busywait(struct i2c_client *client) +{ + int i, ret; + u8 sr; + + for (i = 100; i > 0; i--) { + ret = rv3029_i2c_get_sr(client, &sr); + if (ret < 0) + break; + if (!(sr & RV3029_STATUS_EEBUSY)) + break; + usleep_range(1000, 10000); + } + if (i <= 0) { + dev_err(&client->dev, "EEPROM busy wait timeout.\n"); + return -ETIMEDOUT; + } + + return ret; +} + +static int rv3029_eeprom_exit(struct i2c_client *client) +{ + /* Re-enable eeprom refresh */ + return rv3029_i2c_update_bits(client, RV3029_ONOFF_CTRL, + RV3029_ONOFF_CTRL_EERE, + RV3029_ONOFF_CTRL_EERE); +} + +static int rv3029_eeprom_enter(struct i2c_client *client) +{ + int ret; + u8 sr; + + /* Check whether we are in the allowed voltage range. */ + ret = rv3029_i2c_get_sr(client, &sr); + if (ret < 0) + return ret; + if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) { + /* We clear the bits and retry once just in case + * we had a brown out in early startup. + */ + sr &= ~RV3029_STATUS_VLOW1; + sr &= ~RV3029_STATUS_VLOW2; + ret = rv3029_i2c_set_sr(client, sr); + if (ret < 0) + return ret; + usleep_range(1000, 10000); + ret = rv3029_i2c_get_sr(client, &sr); + if (ret < 0) + return ret; + if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) { + dev_err(&client->dev, + "Supply voltage is too low to safely access the EEPROM.\n"); + return -ENODEV; + } + } + + /* Disable eeprom refresh. */ + ret = rv3029_i2c_update_bits(client, RV3029_ONOFF_CTRL, + RV3029_ONOFF_CTRL_EERE, 0); + if (ret < 0) + return ret; + + /* Wait for any previous eeprom accesses to finish. */ + ret = rv3029_eeprom_busywait(client); + if (ret < 0) + rv3029_eeprom_exit(client); + + return ret; +} + +static int rv3029_eeprom_read(struct i2c_client *client, u8 reg, + u8 buf[], size_t len) +{ + int ret, err; + + err = rv3029_eeprom_enter(client); + if (err < 0) + return err; + + ret = rv3029_i2c_read_regs(client, reg, buf, len); + + err = rv3029_eeprom_exit(client); + if (err < 0) + return err; + + return ret; +} + +static int rv3029_eeprom_write(struct i2c_client *client, u8 reg, + u8 const buf[], size_t len) +{ + int ret, err; + size_t i; + u8 tmp; + + err = rv3029_eeprom_enter(client); + if (err < 0) + return err; + + for (i = 0; i < len; i++, reg++) { + ret = rv3029_i2c_read_regs(client, reg, &tmp, 1); + if (ret < 0) + break; + if (tmp != buf[i]) { + ret = rv3029_i2c_write_regs(client, reg, &buf[i], 1); + if (ret < 0) + break; + } + ret = rv3029_eeprom_busywait(client); + if (ret < 0) + break; + } + + err = rv3029_eeprom_exit(client); + if (err < 0) + return err; + + return ret; +} + static int rv3029_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) { -- cgit v0.10.2 From e27e21603e1ff9f6897e5f2ffa7dec09ab0c955c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20B=C3=BCsch?= Date: Fri, 4 Mar 2016 22:41:19 +0100 Subject: rtc: rv3029: Add device tree property for trickle charger The trickle charger resistor can be enabled via device tree property trickle-resistor-ohms. Signed-off-by: Michael Buesch Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index e59b8a5..b416ed0 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -10,9 +10,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * NOTE: Currently this driver only supports the bare minimum for read - * and write the RTC and alarms. The extra features provided by this chip - * (trickle charger, eeprom, T° compensation) are unavailable. */ #include @@ -528,6 +525,107 @@ static int rv3029_rtc_set_time(struct device *dev, struct rtc_time *tm) return rv3029_i2c_set_time(to_i2c_client(dev), tm); } +static const struct rv3029_trickle_tab_elem { + u32 r; /* resistance in ohms */ + u8 conf; /* trickle config bits */ +} rv3029_trickle_tab[] = { + { + .r = 1076, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | + RV3029_TRICKLE_20K | RV3029_TRICKLE_80K, + }, { + .r = 1091, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | + RV3029_TRICKLE_20K, + }, { + .r = 1137, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | + RV3029_TRICKLE_80K, + }, { + .r = 1154, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K, + }, { + .r = 1371, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K | + RV3029_TRICKLE_80K, + }, { + .r = 1395, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K, + }, { + .r = 1472, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_80K, + }, { + .r = 1500, + .conf = RV3029_TRICKLE_1K, + }, { + .r = 3810, + .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K | + RV3029_TRICKLE_80K, + }, { + .r = 4000, + .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K, + }, { + .r = 4706, + .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_80K, + }, { + .r = 5000, + .conf = RV3029_TRICKLE_5K, + }, { + .r = 16000, + .conf = RV3029_TRICKLE_20K | RV3029_TRICKLE_80K, + }, { + .r = 20000, + .conf = RV3029_TRICKLE_20K, + }, { + .r = 80000, + .conf = RV3029_TRICKLE_80K, + }, +}; + +static void rv3029_trickle_config(struct i2c_client *client) +{ + struct device_node *of_node = client->dev.of_node; + const struct rv3029_trickle_tab_elem *elem; + int i, err; + u32 ohms; + u8 eectrl; + + if (!of_node) + return; + + /* Configure the trickle charger. */ + err = rv3029_eeprom_read(client, RV3029_CONTROL_E2P_EECTRL, + &eectrl, 1); + if (err < 0) { + dev_err(&client->dev, + "Failed to read trickle charger config\n"); + return; + } + err = of_property_read_u32(of_node, "trickle-resistor-ohms", &ohms); + if (err) { + /* Disable trickle charger. */ + eectrl &= ~RV3029_TRICKLE_MASK; + } else { + /* Enable trickle charger. */ + for (i = 0; i < ARRAY_SIZE(rv3029_trickle_tab); i++) { + elem = &rv3029_trickle_tab[i]; + if (elem->r >= ohms) + break; + } + eectrl &= ~RV3029_TRICKLE_MASK; + eectrl |= elem->conf; + dev_info(&client->dev, + "Trickle charger enabled at %d ohms resistance.\n", + elem->r); + } + err = rv3029_eeprom_write(client, RV3029_CONTROL_E2P_EECTRL, + &eectrl, 1); + if (err < 0) { + dev_err(&client->dev, + "Failed to write trickle charger config\n"); + } +} + static const struct rtc_class_ops rv3029_rtc_ops = { .read_time = rv3029_rtc_read_time, .set_time = rv3029_rtc_set_time, @@ -558,6 +656,8 @@ static int rv3029_probe(struct i2c_client *client, return rc; } + rv3029_trickle_config(client); + rtc = devm_rtc_device_register(&client->dev, client->name, &rv3029_rtc_ops, THIS_MODULE); -- cgit v0.10.2 From 832315b05b660427ebdc5987b66e02cb7ec7b4f6 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 10 Mar 2016 05:46:18 +0100 Subject: rtc: pxa: fix Kconfig indentation The pxa section is indented using spaces, use tabs. Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index cf0d085..9babb4c 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1349,10 +1349,10 @@ config RTC_DRV_GENERIC just say Y. config RTC_DRV_PXA - tristate "PXA27x/PXA3xx" - depends on ARCH_PXA - select RTC_DRV_SA1100 - help + tristate "PXA27x/PXA3xx" + depends on ARCH_PXA + select RTC_DRV_SA1100 + help If you say Y here you will get access to the real time clock built into your PXA27x or PXA3xx CPU. This RTC is actually 2 RTCs consisting of an SA1100 compatible RTC and the extended PXA RTC. -- cgit v0.10.2 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 diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 4e99ace..5791f99 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 v0.10.2 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 diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 9babb4c..987c501 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 27229d2..ea28337 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 5791f99..ca43bfc 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 570ab28..0000000 --- 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index ca43bfc..6bf7848 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 6bf7848..321b867 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 321b867..f0ffd3f 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index f0ffd3f..9857287 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 9857287..7edc889 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 v0.10.2 From d5861262210067fc01b2fb4f7af2fd85a3453f15 Mon Sep 17 00:00:00 2001 From: Alexander Kochetkov Date: Sun, 6 Mar 2016 12:43:57 +0300 Subject: rtc: hym8563: fix invalid year calculation Year field must be in BCD format, according to hym8563 datasheet. Due to the bug year 2016 became 2010. Fixes: dcaf03849352 ("rtc: add hym8563 rtc-driver") Signed-off-by: Alexander Kochetkov Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c index 097325d..b1b4746 100644 --- a/drivers/rtc/rtc-hym8563.c +++ b/drivers/rtc/rtc-hym8563.c @@ -144,7 +144,7 @@ static int hym8563_rtc_set_time(struct device *dev, struct rtc_time *tm) * it does not seem to carry it over a subsequent write/read. * So we'll limit ourself to 100 years, starting at 2000 for now. */ - buf[6] = tm->tm_year - 100; + buf[6] = bin2bcd(tm->tm_year - 100); /* * CTL1 only contains TEST-mode bits apart from stop, -- cgit v0.10.2 From 361c6ed6b1536d522815abba82bc676038259f72 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Mon, 7 Mar 2016 09:03:02 -0600 Subject: rtc: ds1685: actually spin forever in poweroff error path objtool reports the following warnings: drivers/rtc/rtc-ds1685.o: warning: objtool: ds1685_rtc_work_queue()+0x0: duplicate frame pointer save drivers/rtc/rtc-ds1685.o: warning: objtool: ds1685_rtc_work_queue()+0x3: duplicate frame pointer setup drivers/rtc/rtc-ds1685.o: warning: objtool: ds1685_rtc_work_queue()+0x0: frame pointer state mismatch The warning message needs to be improved, but what it really means in this case is that ds1685_rtc_poweroff() has a possible code path where it can actually fall through to the next function in the object code, ds1685_rtc_work_queue(). The bug is caused by the use of the unreachable() macro in a place which is actually reachable. That causes gcc to assume that the printk() immediately before the unreachable() macro never returns, when in fact it does. So gcc places the printk() at the very end of the function's object code. When the printk() returns, the next function starts executing. The surrounding comment and printk message state that the code should spin forever, which explains the unreachable() statement. However the actual spin code is missing. Reported-by: kbuild test robot Signed-off-by: Josh Poimboeuf Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 08e0ff8..1e6cfc8 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -2161,6 +2161,7 @@ ds1685_rtc_poweroff(struct platform_device *pdev) /* Check for valid RTC data, else, spin forever. */ if (unlikely(!pdev)) { pr_emerg("platform device data not available, spinning forever ...\n"); + while(1); unreachable(); } else { /* Get the rtc data. */ -- cgit v0.10.2 From 39387dc2cf22bc5e9c310a4991c6a40852df4217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20B=C3=BCsch?= Date: Thu, 10 Mar 2016 18:34:23 +0100 Subject: rtc: rv3029: Add update_bits helper for eeprom access This simplifies the update of single bits in the eeprom. Signed-off-by: Michael Buesch Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index b416ed0..3bbb581 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -308,6 +308,24 @@ static int rv3029_eeprom_write(struct i2c_client *client, u8 reg, return ret; } +static int rv3029_eeprom_update_bits(struct i2c_client *client, + u8 reg, u8 mask, u8 set) +{ + u8 buf; + int ret; + + ret = rv3029_eeprom_read(client, reg, &buf, 1); + if (ret < 0) + return ret; + buf &= ~mask; + buf |= set & mask; + ret = rv3029_eeprom_write(client, reg, &buf, 1); + if (ret < 0) + return ret; + + return 0; +} + static int rv3029_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) { @@ -588,23 +606,16 @@ static void rv3029_trickle_config(struct i2c_client *client) const struct rv3029_trickle_tab_elem *elem; int i, err; u32 ohms; - u8 eectrl; + u8 trickle_set_bits; if (!of_node) return; /* Configure the trickle charger. */ - err = rv3029_eeprom_read(client, RV3029_CONTROL_E2P_EECTRL, - &eectrl, 1); - if (err < 0) { - dev_err(&client->dev, - "Failed to read trickle charger config\n"); - return; - } err = of_property_read_u32(of_node, "trickle-resistor-ohms", &ohms); if (err) { /* Disable trickle charger. */ - eectrl &= ~RV3029_TRICKLE_MASK; + trickle_set_bits = 0; } else { /* Enable trickle charger. */ for (i = 0; i < ARRAY_SIZE(rv3029_trickle_tab); i++) { @@ -612,17 +623,17 @@ static void rv3029_trickle_config(struct i2c_client *client) if (elem->r >= ohms) break; } - eectrl &= ~RV3029_TRICKLE_MASK; - eectrl |= elem->conf; + trickle_set_bits = elem->conf; dev_info(&client->dev, "Trickle charger enabled at %d ohms resistance.\n", elem->r); } - err = rv3029_eeprom_write(client, RV3029_CONTROL_E2P_EECTRL, - &eectrl, 1); + err = rv3029_eeprom_update_bits(client, RV3029_CONTROL_E2P_EECTRL, + RV3029_TRICKLE_MASK, + trickle_set_bits); if (err < 0) { dev_err(&client->dev, - "Failed to write trickle charger config\n"); + "Failed to update trickle charger config\n"); } } -- cgit v0.10.2 From a696b31e2feeaa0ef99242adb9e771b0d3369a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20B=C3=BCsch?= Date: Thu, 10 Mar 2016 18:34:46 +0100 Subject: rtc: rv3029: Add thermometer hwmon support This adds support to - enable/disable the thermometer - set the temperature scanning interval - read the current temperature that is used for temp compensation. via hwmon interface Signed-off-by: Michael Buesch Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 987c501..d2cd206 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -591,6 +591,15 @@ config RTC_DRV_RV3029C2 This driver can also be built as a module. If so, the module will be called rtc-rv3029c2. +config RTC_DRV_RV3029_HWMON + bool "HWMON support for RV3029" + depends on RTC_DRV_RV3029C2 && HWMON + depends on !(RTC_DRV_RV3029C2=y && HWMON=m) + default y + help + Say Y here if you want to expose temperature sensor data on + rtc-rv3029c2. + config RTC_DRV_RV8803 tristate "Micro Crystal RV8803" help diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index 3bbb581..d0cbf08 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include /* Register map */ @@ -637,6 +639,123 @@ static void rv3029_trickle_config(struct i2c_client *client) } } +#ifdef CONFIG_RTC_DRV_RV3029_HWMON + +static int rv3029_read_temp(struct i2c_client *client, int *temp_mC) +{ + int ret; + u8 temp; + + ret = rv3029_i2c_read_regs(client, RV3029_TEMP_PAGE, &temp, 1); + if (ret < 0) + return ret; + + *temp_mC = ((int)temp - 60) * 1000; + + return 0; +} + +static ssize_t rv3029_hwmon_show_temp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = dev_get_drvdata(dev); + int ret, temp_mC; + + ret = rv3029_read_temp(client, &temp_mC); + if (ret < 0) + return ret; + + return sprintf(buf, "%d\n", temp_mC); +} + +static ssize_t rv3029_hwmon_set_update_interval(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct i2c_client *client = dev_get_drvdata(dev); + unsigned long interval_ms; + int ret; + u8 th_set_bits = 0; + + ret = kstrtoul(buf, 10, &interval_ms); + if (ret < 0) + return ret; + + if (interval_ms != 0) { + th_set_bits |= RV3029_EECTRL_THE; + if (interval_ms >= 16000) + th_set_bits |= RV3029_EECTRL_THP; + } + ret = rv3029_eeprom_update_bits(client, RV3029_CONTROL_E2P_EECTRL, + RV3029_EECTRL_THE | RV3029_EECTRL_THP, + th_set_bits); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t rv3029_hwmon_show_update_interval(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = dev_get_drvdata(dev); + int ret, interval_ms; + u8 eectrl; + + ret = rv3029_eeprom_read(client, RV3029_CONTROL_E2P_EECTRL, + &eectrl, 1); + if (ret < 0) + return ret; + + if (eectrl & RV3029_EECTRL_THE) { + if (eectrl & RV3029_EECTRL_THP) + interval_ms = 16000; + else + interval_ms = 1000; + } else { + interval_ms = 0; + } + + return sprintf(buf, "%d\n", interval_ms); +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, rv3029_hwmon_show_temp, + NULL, 0); +static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, + rv3029_hwmon_show_update_interval, + rv3029_hwmon_set_update_interval, 0); + +static struct attribute *rv3029_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_update_interval.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(rv3029_hwmon); + +static void rv3029_hwmon_register(struct i2c_client *client) +{ + struct device *hwmon_dev; + + hwmon_dev = devm_hwmon_device_register_with_groups( + &client->dev, client->name, client, rv3029_hwmon_groups); + if (IS_ERR(hwmon_dev)) { + dev_warn(&client->dev, + "unable to register hwmon device %ld\n", + PTR_ERR(hwmon_dev)); + } +} + +#else /* CONFIG_RTC_DRV_RV3029_HWMON */ + +static void rv3029_hwmon_register(struct i2c_client *client) +{ +} + +#endif /* CONFIG_RTC_DRV_RV3029_HWMON */ + static const struct rtc_class_ops rv3029_rtc_ops = { .read_time = rv3029_rtc_read_time, .set_time = rv3029_rtc_set_time, @@ -668,6 +787,7 @@ static int rv3029_probe(struct i2c_client *client, } rv3029_trickle_config(client); + rv3029_hwmon_register(client); rtc = devm_rtc_device_register(&client->dev, client->name, &rv3029_rtc_ops, THIS_MODULE); -- cgit v0.10.2 From 907b3262583c700ef48f6a45b2b48878b524b2ef Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 14 Mar 2016 23:44:59 +0900 Subject: rtc: pcf2127: convert to use regmap pcf2127 has selectable I2C-bus and SPI-bus interface support. Currently rtc-pcf2127 driver only supports I2C. This is preparation for support for SPI interface. Signed-off-by: Akinobu Mita Cc: Alessandro Zummo Cc: Alexandre Belloni Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 629bfdf..fa492cd 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -19,6 +19,7 @@ #include #include #include +#include #define PCF2127_REG_CTRL1 (0x00) /* Control Register 1 */ #define PCF2127_REG_CTRL2 (0x01) /* Control Register 2 */ @@ -36,29 +37,30 @@ #define PCF2127_OSF BIT(7) /* Oscillator Fail flag */ -static struct i2c_driver pcf2127_driver; - struct pcf2127 { struct rtc_device *rtc; + struct regmap *regmap; }; /* * In the routines that deal directly with the pcf2127 hardware, we use * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. */ -static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) +static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) { - unsigned char buf[10] = { PCF2127_REG_CTRL1 }; + struct pcf2127 *pcf2127 = dev_get_drvdata(dev); + unsigned char buf[10]; + int ret; - /* read registers */ - if (i2c_master_send(client, buf, 1) != 1 || - i2c_master_recv(client, buf, sizeof(buf)) != sizeof(buf)) { - dev_err(&client->dev, "%s: read error\n", __func__); - return -EIO; + ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, buf, + sizeof(buf)); + if (ret) { + dev_err(dev, "%s: read error\n", __func__); + return ret; } if (buf[PCF2127_REG_CTRL3] & PCF2127_REG_CTRL3_BLF) - dev_info(&client->dev, + dev_info(dev, "low voltage detected, check/replace RTC battery.\n"); if (buf[PCF2127_REG_SC] & PCF2127_OSF) { @@ -66,12 +68,12 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) * no need clear the flag here, * it will be cleared once the new date is saved */ - dev_warn(&client->dev, + dev_warn(dev, "oscillator stop detected, date/time is not reliable\n"); return -EINVAL; } - dev_dbg(&client->dev, + dev_dbg(dev, "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, " "sec=%02x, min=%02x, hr=%02x, " "mday=%02x, wday=%02x, mon=%02x, year=%02x\n", @@ -91,7 +93,7 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) if (tm->tm_year < 70) tm->tm_year += 100; /* assume we are in 1970...2069 */ - dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " + dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, @@ -100,20 +102,18 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) return rtc_valid_tm(tm); } -static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) +static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm) { - unsigned char buf[8]; + struct pcf2127 *pcf2127 = dev_get_drvdata(dev); + unsigned char buf[7]; int i = 0, err; - dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " + dev_dbg(dev, "%s: secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); - /* start register address */ - buf[i++] = PCF2127_REG_SC; - /* hours, minutes and seconds */ buf[i++] = bin2bcd(tm->tm_sec); /* this will also clear OSF flag */ buf[i++] = bin2bcd(tm->tm_min); @@ -128,11 +128,11 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) buf[i++] = bin2bcd(tm->tm_year % 100); /* write register's data */ - err = i2c_master_send(client, buf, i); - if (err != i) { - dev_err(&client->dev, + err = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_SC, buf, i); + if (err) { + dev_err(dev, "%s: err=%d", __func__, err); - return -EIO; + return err; } return 0; @@ -142,26 +142,17 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) static int pcf2127_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { - struct i2c_client *client = to_i2c_client(dev); - unsigned char buf = PCF2127_REG_CTRL3; + struct pcf2127 *pcf2127 = dev_get_drvdata(dev); int touser; int ret; switch (cmd) { case RTC_VL_READ: - ret = i2c_master_send(client, &buf, 1); - if (!ret) - ret = -EIO; - if (ret < 0) - return ret; - - ret = i2c_master_recv(client, &buf, 1); - if (!ret) - ret = -EIO; - if (ret < 0) + ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL3, &touser); + if (ret) return ret; - touser = buf & PCF2127_REG_CTRL3_BLF ? 1 : 0; + touser = touser & PCF2127_REG_CTRL3_BLF ? 1 : 0; if (copy_to_user((void __user *)arg, &touser, sizeof(int))) return -EFAULT; @@ -174,52 +165,33 @@ static int pcf2127_rtc_ioctl(struct device *dev, #define pcf2127_rtc_ioctl NULL #endif -static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - return pcf2127_get_datetime(to_i2c_client(dev), tm); -} - -static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - return pcf2127_set_datetime(to_i2c_client(dev), tm); -} - static const struct rtc_class_ops pcf2127_rtc_ops = { .ioctl = pcf2127_rtc_ioctl, .read_time = pcf2127_rtc_read_time, .set_time = pcf2127_rtc_set_time, }; -static int pcf2127_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pcf2127_probe(struct device *dev, struct regmap *regmap, + const char *name) { struct pcf2127 *pcf2127; - dev_dbg(&client->dev, "%s\n", __func__); - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) - return -ENODEV; + dev_dbg(dev, "%s\n", __func__); - pcf2127 = devm_kzalloc(&client->dev, sizeof(struct pcf2127), - GFP_KERNEL); + pcf2127 = devm_kzalloc(dev, sizeof(*pcf2127), GFP_KERNEL); if (!pcf2127) return -ENOMEM; - i2c_set_clientdata(client, pcf2127); + pcf2127->regmap = regmap; - pcf2127->rtc = devm_rtc_device_register(&client->dev, - pcf2127_driver.driver.name, - &pcf2127_rtc_ops, THIS_MODULE); + dev_set_drvdata(dev, pcf2127); + + pcf2127->rtc = devm_rtc_device_register(dev, name, &pcf2127_rtc_ops, + THIS_MODULE); return PTR_ERR_OR_ZERO(pcf2127->rtc); } -static const struct i2c_device_id pcf2127_id[] = { - { "pcf2127", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, pcf2127_id); - #ifdef CONFIG_OF static const struct of_device_id pcf2127_of_match[] = { { .compatible = "nxp,pcf2127" }, @@ -228,16 +200,118 @@ static const struct of_device_id pcf2127_of_match[] = { MODULE_DEVICE_TABLE(of, pcf2127_of_match); #endif -static struct i2c_driver pcf2127_driver = { +static int pcf2127_i2c_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct i2c_client *client = to_i2c_client(dev); + int ret; + + ret = i2c_master_send(client, data, count); + if (ret != count) + return ret < 0 ? ret : -EIO; + + return 0; +} + +static int pcf2127_i2c_gather_write(void *context, + const void *reg, size_t reg_size, + const void *val, size_t val_size) +{ + struct device *dev = context; + struct i2c_client *client = to_i2c_client(dev); + int ret; + void *buf; + + if (WARN_ON(reg_size != 1)) + return -EINVAL; + + buf = kmalloc(val_size + 1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + memcpy(buf, reg, 1); + memcpy(buf + 1, val, val_size); + + ret = i2c_master_send(client, buf, val_size + 1); + if (ret != val_size + 1) + return ret < 0 ? ret : -EIO; + + return 0; +} + +static int pcf2127_i2c_read(void *context, const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct device *dev = context; + struct i2c_client *client = to_i2c_client(dev); + int ret; + + if (WARN_ON(reg_size != 1)) + return -EINVAL; + + ret = i2c_master_send(client, reg, 1); + if (ret != 1) + return ret < 0 ? ret : -EIO; + + ret = i2c_master_recv(client, val, val_size); + if (ret != val_size) + return ret < 0 ? ret : -EIO; + + return 0; +} + +/* + * The reason we need this custom regmap_bus instead of using regmap_init_i2c() + * is that the STOP condition is required between set register address and + * read register data when reading from registers. + */ +static const struct regmap_bus pcf2127_i2c_regmap = { + .write = pcf2127_i2c_write, + .gather_write = pcf2127_i2c_gather_write, + .read = pcf2127_i2c_read, +}; + +static struct i2c_driver pcf2127_i2c_driver; + +static int pcf2127_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, + }; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + regmap = devm_regmap_init(&client->dev, &pcf2127_i2c_regmap, + &client->dev, &config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "%s: regmap allocation failed: %ld\n", + __func__, PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return pcf2127_probe(&client->dev, regmap, + pcf2127_i2c_driver.driver.name); +} + +static const struct i2c_device_id pcf2127_i2c_id[] = { + { "pcf2127", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id); + +static struct i2c_driver pcf2127_i2c_driver = { .driver = { - .name = "rtc-pcf2127", + .name = "rtc-pcf2127-i2c", .of_match_table = of_match_ptr(pcf2127_of_match), }, - .probe = pcf2127_probe, - .id_table = pcf2127_id, + .probe = pcf2127_i2c_probe, + .id_table = pcf2127_i2c_id, }; - -module_i2c_driver(pcf2127_driver); +module_i2c_driver(pcf2127_i2c_driver); MODULE_AUTHOR("Renaud Cerrato "); MODULE_DESCRIPTION("NXP PCF2127 RTC driver"); -- cgit v0.10.2 From 9408ec1af875a83ad75f3dac1aa18d2337a809fe Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 14 Mar 2016 23:45:00 +0900 Subject: rtc: pcf2127: add support for spi interface pcf2127 has selectable I2C-bus and SPI-bus interface support. This adds support for SPI interface. Signed-off-by: Akinobu Mita Cc: Alessandro Zummo Cc: Alexandre Belloni Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index d2cd206..544bd34 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -379,15 +379,6 @@ config RTC_DRV_X1205 This driver can also be built as a module. If so, the module will be called rtc-x1205. -config RTC_DRV_PCF2127 - tristate "NXP PCF2127" - help - If you say yes here you get support for the NXP PCF2127/29 RTC - chips. - - This driver can also be built as a module. If so, the module - will be called rtc-pcf2127. - config RTC_DRV_PCF8523 tristate "NXP PCF8523" help @@ -776,6 +767,16 @@ config RTC_DRV_DS3232 This driver can also be built as a module. If so, the module will be called rtc-ds3232. +config RTC_DRV_PCF2127 + tristate "NXP PCF2127" + depends on RTC_I2C_AND_SPI + help + If you say yes here you get support for the NXP PCF2127/29 RTC + chips. + + This driver can also be built as a module. If so, the module + will be called rtc-pcf2127. + comment "Platform RTC drivers" # this 'CMOS' RTC driver is arch dependent because diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index fa492cd..194c440 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -1,5 +1,5 @@ /* - * An I2C driver for the NXP PCF2127 RTC + * An I2C and SPI driver for the NXP PCF2127 RTC * Copyright 2013 Til-Technologies * * Author: Renaud Cerrato @@ -14,6 +14,7 @@ */ #include +#include #include #include #include @@ -200,6 +201,8 @@ static const struct of_device_id pcf2127_of_match[] = { MODULE_DEVICE_TABLE(of, pcf2127_of_match); #endif +#if IS_ENABLED(CONFIG_I2C) + static int pcf2127_i2c_write(void *context, const void *data, size_t count) { struct device *dev = context; @@ -311,7 +314,118 @@ static struct i2c_driver pcf2127_i2c_driver = { .probe = pcf2127_i2c_probe, .id_table = pcf2127_i2c_id, }; -module_i2c_driver(pcf2127_i2c_driver); + +static int pcf2127_i2c_register_driver(void) +{ + return i2c_add_driver(&pcf2127_i2c_driver); +} + +static void pcf2127_i2c_unregister_driver(void) +{ + i2c_del_driver(&pcf2127_i2c_driver); +} + +#else + +static int pcf2127_i2c_register_driver(void) +{ + return 0; +} + +static void pcf2127_i2c_unregister_driver(void) +{ +} + +#endif + +#if IS_ENABLED(CONFIG_SPI_MASTER) + +static struct spi_driver pcf2127_spi_driver; + +static int pcf2127_spi_probe(struct spi_device *spi) +{ + static const struct regmap_config config = { + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = 0xa0, + .write_flag_mask = 0x20, + }; + 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); + } + + return pcf2127_probe(&spi->dev, regmap, pcf2127_spi_driver.driver.name); +} + +static const struct spi_device_id pcf2127_spi_id[] = { + { "pcf2127", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, pcf2127_spi_id); + +static struct spi_driver pcf2127_spi_driver = { + .driver = { + .name = "rtc-pcf2127-spi", + .of_match_table = of_match_ptr(pcf2127_of_match), + }, + .probe = pcf2127_spi_probe, + .id_table = pcf2127_spi_id, +}; + +static int pcf2127_spi_register_driver(void) +{ + return spi_register_driver(&pcf2127_spi_driver); +} + +static void pcf2127_spi_unregister_driver(void) +{ + spi_unregister_driver(&pcf2127_spi_driver); +} + +#else + +static int pcf2127_spi_register_driver(void) +{ + return 0; +} + +static void pcf2127_spi_unregister_driver(void) +{ +} + +#endif + +static int __init pcf2127_init(void) +{ + int ret; + + ret = pcf2127_i2c_register_driver(); + if (ret) { + pr_err("Failed to register pcf2127 i2c driver: %d\n", ret); + return ret; + } + + ret = pcf2127_spi_register_driver(); + if (ret) { + pr_err("Failed to register pcf2127 spi driver: %d\n", ret); + pcf2127_i2c_unregister_driver(); + } + + return ret; +} +module_init(pcf2127_init) + +static void __exit pcf2127_exit(void) +{ + pcf2127_spi_unregister_driver(); + pcf2127_i2c_unregister_driver(); +} +module_exit(pcf2127_exit) MODULE_AUTHOR("Renaud Cerrato "); MODULE_DESCRIPTION("NXP PCF2127 RTC driver"); -- cgit v0.10.2 From cee2cc21550648679d222cbe2637fcc6d0f730ef Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 14 Mar 2016 23:45:01 +0900 Subject: rtc: pcf2127: add pcf2129 device id There are only a few differences between PCF2127 and PCF2129 (PCF2127 has 512 bytes of general purpose SRAM and count-down timer). The rtc-pcf2127 driver currently doesn't use the PCF2127 specific functionality and Kconfig help text already says this driver supports PCF2127/29, so we can simply add pcf2129 to device id list. Signed-off-by: Akinobu Mita Cc: Alessandro Zummo Cc: Alexandre Belloni Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 194c440..2bfdf63 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -1,12 +1,12 @@ /* - * An I2C and SPI driver for the NXP PCF2127 RTC + * An I2C and SPI driver for the NXP PCF2127/29 RTC * Copyright 2013 Til-Technologies * * Author: Renaud Cerrato * * based on the other drivers in this same directory. * - * http://www.nxp.com/documents/data_sheet/PCF2127AT.pdf + * Datasheet: http://cache.nxp.com/documents/data_sheet/PCF2127.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 @@ -196,6 +196,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, #ifdef CONFIG_OF static const struct of_device_id pcf2127_of_match[] = { { .compatible = "nxp,pcf2127" }, + { .compatible = "nxp,pcf2129" }, {} }; MODULE_DEVICE_TABLE(of, pcf2127_of_match); @@ -302,6 +303,7 @@ static int pcf2127_i2c_probe(struct i2c_client *client, static const struct i2c_device_id pcf2127_i2c_id[] = { { "pcf2127", 0 }, + { "pcf2129", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id); @@ -364,6 +366,7 @@ static int pcf2127_spi_probe(struct spi_device *spi) static const struct spi_device_id pcf2127_spi_id[] = { { "pcf2127", 0 }, + { "pcf2129", 0 }, { } }; MODULE_DEVICE_TABLE(spi, pcf2127_spi_id); @@ -428,5 +431,5 @@ static void __exit pcf2127_exit(void) module_exit(pcf2127_exit) MODULE_AUTHOR("Renaud Cerrato "); -MODULE_DESCRIPTION("NXP PCF2127 RTC driver"); +MODULE_DESCRIPTION("NXP PCF2127/29 RTC driver"); MODULE_LICENSE("GPL v2"); -- cgit v0.10.2