Commit f903129b authored by Javier Martinez Canillas's avatar Javier Martinez Canillas Committed by Alexandre Belloni

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: default avatarKrzysztof Kozlowski <k.kozlowski@samsung.com>
Signed-off-by: default avatarJavier Martinez Canillas <javier@osg.samsung.com>
Acked-by: default avatarLaxman Dewangan <ldewangan@nvidia.com>
Tested-by: default avatarKrzysztof Kozlowski <k.kozlowski@samsung.com>
Reviewed-by: default avatarAndi Shyti <andi.shyti@samsung.com>
Reviewed-by: default avatarKrzysztof Kozlowski <k.kozlowski@samsung.com>
Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@free-electrons.com>
parent 90a5698a
/* /*
* RTC driver for Maxim MAX77686 * RTC driver for Maxim MAX77686 and MAX77802
* *
* Copyright (C) 2012 Samsung Electronics Co.Ltd * Copyright (C) 2012 Samsung Electronics Co.Ltd
* *
...@@ -41,6 +41,15 @@ ...@@ -41,6 +41,15 @@
#define ALARM_ENABLE_SHIFT 7 #define ALARM_ENABLE_SHIFT 7
#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) #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 { enum {
RTC_SEC = 0, RTC_SEC = 0,
RTC_MIN, RTC_MIN,
...@@ -59,6 +68,10 @@ struct max77686_rtc_driver_data { ...@@ -59,6 +68,10 @@ struct max77686_rtc_driver_data {
u8 mask; u8 mask;
/* Registers offset to I2C addresses map */ /* Registers offset to I2C addresses map */
const unsigned int *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 { struct max77686_rtc_info {
...@@ -108,6 +121,7 @@ enum max77686_rtc_reg_offset { ...@@ -108,6 +121,7 @@ enum max77686_rtc_reg_offset {
REG_ALARM2_MONTH, REG_ALARM2_MONTH,
REG_ALARM2_YEAR, REG_ALARM2_YEAR,
REG_ALARM2_DATE, REG_ALARM2_DATE,
REG_RTC_AE1,
REG_RTC_END, REG_RTC_END,
}; };
...@@ -138,12 +152,52 @@ static const unsigned int max77686_map[REG_RTC_END] = { ...@@ -138,12 +152,52 @@ static const unsigned int max77686_map[REG_RTC_END] = {
[REG_ALARM2_MONTH] = MAX77686_ALARM2_MONTH, [REG_ALARM2_MONTH] = MAX77686_ALARM2_MONTH,
[REG_ALARM2_YEAR] = MAX77686_ALARM2_YEAR, [REG_ALARM2_YEAR] = MAX77686_ALARM2_YEAR,
[REG_ALARM2_DATE] = MAX77686_ALARM2_DATE, [REG_ALARM2_DATE] = MAX77686_ALARM2_DATE,
[REG_RTC_AE1] = REG_RTC_NONE,
}; };
static const struct max77686_rtc_driver_data max77686_drv_data = { static const struct max77686_rtc_driver_data max77686_drv_data = {
.delay = 16000, .delay = 16000,
.mask = 0x7f, .mask = 0x7f,
.map = max77686_map, .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, 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, ...@@ -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_wday = ffs(data[RTC_WEEKDAY] & mask) - 1;
tm->tm_mday = data[RTC_DATE] & 0x1f; tm->tm_mday = data[RTC_DATE] & 0x1f;
tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; 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_yday = 0;
tm->tm_isdst = 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_SEC] = tm->tm_sec;
data[RTC_MIN] = tm->tm_min; data[RTC_MIN] = tm->tm_min;
...@@ -178,6 +240,12 @@ static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data) ...@@ -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_WEEKDAY] = 1 << tm->tm_wday;
data[RTC_DATE] = tm->tm_mday; data[RTC_DATE] = tm->tm_mday;
data[RTC_MONTH] = tm->tm_mon + 1; 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; data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0;
if (tm->tm_year < 100) { if (tm->tm_year < 100) {
...@@ -185,6 +253,7 @@ static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data) ...@@ -185,6 +253,7 @@ static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
1900 + tm->tm_year); 1900 + tm->tm_year);
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
} }
...@@ -249,7 +318,7 @@ static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm) ...@@ -249,7 +318,7 @@ static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm)
u8 data[RTC_NR_TIME]; u8 data[RTC_NR_TIME];
int ret; int ret;
ret = max77686_rtc_tm_to_data(tm, data); ret = max77686_rtc_tm_to_data(tm, data, info);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -296,10 +365,31 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -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); max77686_rtc_data_to_tm(data, &alrm->time, info);
alrm->enabled = 0; 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; 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) ...@@ -333,21 +423,35 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info)
if (ret < 0) if (ret < 0)
goto out; goto out;
ret = regmap_bulk_read(info->max77686->rtc_regmap, if (info->drv_data->alarm_enable_reg) {
map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); if (map[REG_RTC_AE1] == REG_RTC_NONE) {
if (ret < 0) { ret = -EINVAL;
dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", 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); __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++) for (i = 0; i < ARRAY_SIZE(data); i++)
data[i] &= ~ALARM_ENABLE_MASK; 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) { if (ret < 0) {
dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
__func__, ret); __func__, ret);
...@@ -373,29 +477,37 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) ...@@ -373,29 +477,37 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info)
if (ret < 0) if (ret < 0)
goto out; goto out;
ret = regmap_bulk_read(info->max77686->rtc_regmap, if (info->drv_data->alarm_enable_reg) {
map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); ret = regmap_write(info->max77686->regmap, map[REG_RTC_AE1],
if (ret < 0) { MAX77802_ALARM_ENABLE_VALUE);
dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", } 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); __func__, ret);
goto out; goto out;
} }
max77686_rtc_data_to_tm(data, &tm, info);
data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT); max77686_rtc_data_to_tm(data, &tm, info);
data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT);
data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT); data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT);
data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT);
if (data[RTC_MONTH] & 0xf) data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT);
data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT); data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK;
if (data[RTC_YEAR] & info->drv_data->mask) if (data[RTC_MONTH] & 0xf)
data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT); data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT);
if (data[RTC_DATE] & 0x1f) if (data[RTC_YEAR] & info->drv_data->mask)
data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); 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) { if (ret < 0) {
dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
__func__, ret); __func__, ret);
...@@ -413,7 +525,7 @@ static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -413,7 +525,7 @@ static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
u8 data[RTC_NR_TIME]; u8 data[RTC_NR_TIME];
int ret; int ret;
ret = max77686_rtc_tm_to_data(&alrm->time, data); ret = max77686_rtc_tm_to_data(&alrm->time, data, info);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -524,6 +636,9 @@ static int max77686_rtc_probe(struct platform_device *pdev) ...@@ -524,6 +636,9 @@ static int max77686_rtc_probe(struct platform_device *pdev)
info->drv_data = (const struct max77686_rtc_driver_data *) info->drv_data = (const struct max77686_rtc_driver_data *)
id->driver_data; id->driver_data;
if (!info->drv_data->separate_i2c_addr)
info->max77686->rtc_regmap = info->max77686->regmap;
platform_set_drvdata(pdev, info); platform_set_drvdata(pdev, info);
ret = max77686_rtc_init_reg(info); ret = max77686_rtc_init_reg(info);
...@@ -535,7 +650,7 @@ static int max77686_rtc_probe(struct platform_device *pdev) ...@@ -535,7 +650,7 @@ static int max77686_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1); 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); &max77686_rtc_ops, THIS_MODULE);
if (IS_ERR(info->rtc_dev)) { if (IS_ERR(info->rtc_dev)) {
...@@ -598,6 +713,7 @@ static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops, ...@@ -598,6 +713,7 @@ static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops,
static const struct platform_device_id rtc_id[] = { static const struct platform_device_id rtc_id[] = {
{ "max77686-rtc", .driver_data = (kernel_ulong_t)&max77686_drv_data, }, { "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); MODULE_DEVICE_TABLE(platform, rtc_id);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment