diff options
Diffstat (limited to 'drivers/rtc/rtc-max77686.c')
| -rw-r--r-- | drivers/rtc/rtc-max77686.c | 201 |
1 files changed, 109 insertions, 92 deletions
diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 182fdd00e290..69ea3ce75b5a 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -1,16 +1,10 @@ -/* - * RTC driver for Maxim MAX77686 and MAX77802 - * - * 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. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// RTC driver for Maxim MAX77686 and MAX77802 +// +// Copyright (C) 2012 Samsung Electronics Co.Ltd +// +// based on rtc-max8997.c #include <linux/i2c.h> #include <linux/slab.h> @@ -25,6 +19,7 @@ #define MAX77686_I2C_ADDR_RTC (0x0C >> 1) #define MAX77620_I2C_ADDR_RTC 0x68 +#define MAX77714_I2C_ADDR_RTC 0x48 #define MAX77686_INVALID_I2C_ADDR (-1) /* Define non existing register */ @@ -40,9 +35,6 @@ #define RTC_UDR_MASK BIT(RTC_UDR_SHIFT) #define RTC_RBUDR_SHIFT 4 #define RTC_RBUDR_MASK BIT(RTC_RBUDR_SHIFT) -/* RTC Hour register */ -#define HOUR_PM_SHIFT 6 -#define HOUR_PM_MASK BIT(HOUR_PM_SHIFT) /* RTC Alarm Enable */ #define ALARM_ENABLE_SHIFT 7 #define ALARM_ENABLE_MASK BIT(ALARM_ENABLE_SHIFT) @@ -63,32 +55,36 @@ enum { RTC_WEEKDAY, RTC_MONTH, RTC_YEAR, - RTC_DATE, + RTC_MONTHDAY, RTC_NR_TIME }; +/** + * struct max77686_rtc_driver_data - model-specific configuration + * @delay: Minimum usecs needed for a RTC update + * @mask: Mask used to read RTC registers value + * @map: Registers offset to I2C addresses map + * @alarm_enable_reg: Has a separate alarm enable register? + * @rtc_i2c_addr: I2C address for RTC block + * @rtc_irq_from_platform: RTC interrupt via platform resource + * @alarm_pending_status_reg: Pending alarm status register + * @rtc_irq_chip: RTC IRQ CHIP for regmap + * @regmap_config: regmap configuration for the chip + */ struct max77686_rtc_driver_data { - /* Minimum usecs needed for a RTC update */ unsigned long delay; - /* Mask used to read RTC registers value */ u8 mask; - /* Registers offset to I2C addresses map */ const unsigned int *map; - /* Has a separate alarm enable register? */ 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; + const struct regmap_config *regmap_config; }; struct max77686_rtc_info { struct device *dev; - struct i2c_client *rtc; struct rtc_device *rtc_dev; struct mutex lock; @@ -100,7 +96,6 @@ struct max77686_rtc_info { int rtc_irq; int virq; - int rtc_24hr_mode; }; enum MAX77686_RTC_OP { @@ -120,7 +115,7 @@ enum max77686_rtc_reg_offset { REG_RTC_WEEKDAY, REG_RTC_MONTH, REG_RTC_YEAR, - REG_RTC_DATE, + REG_RTC_MONTHDAY, REG_ALARM1_SEC, REG_ALARM1_MIN, REG_ALARM1_HOUR, @@ -151,7 +146,7 @@ static const unsigned int max77686_map[REG_RTC_END] = { [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_RTC_MONTHDAY] = MAX77686_RTC_MONTHDAY, [REG_ALARM1_SEC] = MAX77686_ALARM1_SEC, [REG_ALARM1_MIN] = MAX77686_ALARM1_MIN, [REG_ALARM1_HOUR] = MAX77686_ALARM1_HOUR, @@ -188,6 +183,11 @@ static const struct regmap_irq_chip max77686_rtc_irq_chip = { .num_irqs = ARRAY_SIZE(max77686_rtc_irqs), }; +static const struct regmap_config max77686_rtc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + static const struct max77686_rtc_driver_data max77686_drv_data = { .delay = 16000, .mask = 0x7f, @@ -197,6 +197,35 @@ static const struct max77686_rtc_driver_data max77686_drv_data = { .alarm_pending_status_reg = MAX77686_REG_STATUS2, .rtc_i2c_addr = MAX77686_I2C_ADDR_RTC, .rtc_irq_chip = &max77686_rtc_irq_chip, + .regmap_config = &max77686_rtc_regmap_config, +}; + +static const struct regmap_irq_chip max77714_rtc_irq_chip = { + .name = "max77714-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) - 1, /* no WTSR on 77714 */ +}; + +static const struct max77686_rtc_driver_data max77714_drv_data = { + .delay = 16000, + .mask = 0x7f, + .map = max77686_map, + .alarm_enable_reg = false, + .rtc_irq_from_platform = false, + /* On MAX77714 RTCA1 is BIT 1 of RTCINT (0x00). Not supported by this driver. */ + .alarm_pending_status_reg = MAX77686_INVALID_REG, + .rtc_i2c_addr = MAX77714_I2C_ADDR_RTC, + .rtc_irq_chip = &max77714_rtc_irq_chip, + .regmap_config = &max77686_rtc_regmap_config, +}; + +static const struct regmap_config max77620_rtc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .use_single_write = true, }; static const struct max77686_rtc_driver_data max77620_drv_data = { @@ -208,6 +237,7 @@ static const struct max77686_rtc_driver_data max77620_drv_data = { .alarm_pending_status_reg = MAX77686_INVALID_REG, .rtc_i2c_addr = MAX77620_I2C_ADDR_RTC, .rtc_irq_chip = &max77686_rtc_irq_chip, + .regmap_config = &max77620_rtc_regmap_config, }; static const unsigned int max77802_map[REG_RTC_END] = { @@ -221,7 +251,7 @@ static const unsigned int max77802_map[REG_RTC_END] = { [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_RTC_MONTHDAY] = MAX77802_RTC_MONTHDAY, [REG_ALARM1_SEC] = MAX77802_ALARM1_SEC, [REG_ALARM1_MIN] = MAX77802_ALARM1_MIN, [REG_ALARM1_HOUR] = MAX77802_ALARM1_HOUR, @@ -266,17 +296,11 @@ 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) { - 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; - } + tm->tm_hour = data[RTC_HOUR] & 0x1f; /* Only a single bit is set in data[], so fls() would be equivalent */ tm->tm_wday = ffs(data[RTC_WEEKDAY] & mask) - 1; - tm->tm_mday = data[RTC_DATE] & 0x1f; + tm->tm_mday = data[RTC_MONTHDAY] & 0x1f; tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; tm->tm_year = data[RTC_YEAR] & mask; tm->tm_yday = 0; @@ -297,7 +321,7 @@ static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data, 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_MONTHDAY] = tm->tm_mday; data[RTC_MONTH] = tm->tm_mon + 1; if (info->drv_data->alarm_enable_reg) { @@ -364,8 +388,6 @@ static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm) max77686_rtc_data_to_tm(data, tm, info); - ret = rtc_valid_tm(tm); - out: mutex_unlock(&info->lock); return ret; @@ -555,8 +577,8 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) 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); + if (data[RTC_MONTHDAY] & 0x1f) + data[RTC_MONTHDAY] |= (1 << ALARM_ENABLE_SHIFT); ret = regmap_bulk_write(info->rtc_regmap, map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); @@ -652,8 +674,6 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info) 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->rtc_regmap, info->drv_data->map[REG_RTC_CONTROLM], data, ARRAY_SIZE(data)); @@ -666,72 +686,55 @@ 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); + struct i2c_client *client; int ret; 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); + if (info->rtc_irq < 0) return info->rtc_irq; - } } else { 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->regmap) + return dev_err_probe(info->dev, -ENODEV, + "Failed to get rtc regmap\n"); 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; - } + client = devm_i2c_new_dummy_device(info->dev, parent_i2c->adapter, + info->drv_data->rtc_i2c_addr); + if (IS_ERR(client)) + return dev_err_probe(info->dev, PTR_ERR(client), + "Failed to allocate I2C device for RTC\n"); - 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; - } + info->rtc_regmap = devm_regmap_init_i2c(client, + info->drv_data->regmap_config); + if (IS_ERR(info->rtc_regmap)) + return dev_err_probe(info->dev, PTR_ERR(info->rtc_regmap), + "Failed to allocate RTC regmap\n"); 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, + 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; - } + if (ret < 0) + return dev_err_probe(info->dev, ret, + "Failed to add RTC irq chip\n"); return 0; - -err_unregister_i2c: - if (info->rtc) - i2c_unregister_device(info->rtc); - return ret; } static int max77686_rtc_probe(struct platform_device *pdev) @@ -762,7 +765,7 @@ static int max77686_rtc_probe(struct platform_device *pdev) goto err_rtc; } - device_init_wakeup(&pdev->dev, 1); + device_init_wakeup(&pdev->dev, true); info->rtc_dev = devm_rtc_device_register(&pdev->dev, id->name, &max77686_rtc_ops, THIS_MODULE); @@ -794,38 +797,51 @@ static int max77686_rtc_probe(struct platform_device *pdev) 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) +static void 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) { + struct max77686_rtc_info *info = dev_get_drvdata(dev); + int ret = 0; + if (device_may_wakeup(dev)) { struct max77686_rtc_info *info = dev_get_drvdata(dev); - return enable_irq_wake(info->virq); + ret = enable_irq_wake(info->virq); } - return 0; + /* + * If the main IRQ (not virtual) is the parent IRQ, then it must be + * disabled during suspend because if it happens while suspended it + * will be handled before resuming I2C. + * + * Since Main IRQ is shared, all its users should disable it to be sure + * it won't fire while one of them is still suspended. + */ + if (!info->drv_data->rtc_irq_from_platform) + disable_irq(info->rtc_irq); + + return ret; } static int max77686_rtc_resume(struct device *dev) { + struct max77686_rtc_info *info = dev_get_drvdata(dev); + + if (!info->drv_data->rtc_irq_from_platform) + enable_irq(info->rtc_irq); + if (device_may_wakeup(dev)) { struct max77686_rtc_info *info = dev_get_drvdata(dev); @@ -843,6 +859,7 @@ 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, }, + { "max77714-rtc", .driver_data = (kernel_ulong_t)&max77714_drv_data, }, {}, }; MODULE_DEVICE_TABLE(platform, rtc_id); |
