|
11 | 11 | #include <linux/bcd.h>
|
12 | 12 | #include <linux/of.h>
|
13 | 13 | #include <linux/regmap.h>
|
| 14 | +#include <linux/bitfield.h> |
14 | 15 | #include <linux/hwmon.h>
|
15 | 16 | #include <linux/hwmon-sysfs.h>
|
16 | 17 |
|
|
57 | 58 |
|
58 | 59 | #define ABEOZ9_SEC_LEN 7
|
59 | 60 |
|
| 61 | +#define ABEOZ9_REG_ALARM_SEC 0x10 |
| 62 | +#define ABEOZ9_BIT_ALARM_SEC GENMASK(6, 0) |
| 63 | +#define ABEOZ9_REG_ALARM_MIN 0x11 |
| 64 | +#define ABEOZ9_BIT_ALARM_MIN GENMASK(6, 0) |
| 65 | +#define ABEOZ9_REG_ALARM_HOURS 0x12 |
| 66 | +#define ABEOZ9_BIT_ALARM_HOURS_PM BIT(5) |
| 67 | +#define ABEOZ9_BIT_ALARM_HOURS GENMASK(4, 0) |
| 68 | +#define ABEOZ9_REG_ALARM_DAYS 0x13 |
| 69 | +#define ABEOZ9_BIT_ALARM_DAYS GENMASK(5, 0) |
| 70 | +#define ABEOZ9_REG_ALARM_WEEKDAYS 0x14 |
| 71 | +#define ABEOZ9_BIT_ALARM_WEEKDAYS GENMASK(2, 0) |
| 72 | +#define ABEOZ9_REG_ALARM_MONTHS 0x15 |
| 73 | +#define ABEOZ9_BIT_ALARM_MONTHS GENMASK(4, 0) |
| 74 | +#define ABEOZ9_REG_ALARM_YEARS 0x16 |
| 75 | + |
| 76 | +#define ABEOZ9_ALARM_LEN 7 |
| 77 | +#define ABEOZ9_BIT_ALARM_AE BIT(7) |
| 78 | + |
60 | 79 | #define ABEOZ9_REG_REG_TEMP 0x20
|
61 | 80 | #define ABEOZ953_TEMP_MAX 120
|
62 | 81 | #define ABEOZ953_TEMP_MIN -60
|
@@ -186,6 +205,98 @@ static int abeoz9_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
186 | 205 | return abeoz9_reset_validity(regmap);
|
187 | 206 | }
|
188 | 207 |
|
| 208 | +static int abeoz9_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) |
| 209 | +{ |
| 210 | + struct abeoz9_rtc_data *data = dev_get_drvdata(dev); |
| 211 | + struct regmap *regmap = data->regmap; |
| 212 | + u8 regs[ABEOZ9_ALARM_LEN]; |
| 213 | + u8 val[2]; |
| 214 | + int ret; |
| 215 | + |
| 216 | + ret = abeoz9_check_validity(dev); |
| 217 | + if (ret) |
| 218 | + return ret; |
| 219 | + |
| 220 | + ret = regmap_bulk_read(regmap, ABEOZ9_REG_CTRL_INT, val, sizeof(val)); |
| 221 | + if (ret) |
| 222 | + return ret; |
| 223 | + |
| 224 | + alarm->enabled = val[0] & ABEOZ9_REG_CTRL_INT_AIE; |
| 225 | + alarm->pending = val[1] & ABEOZ9_REG_CTRL_INT_FLAG_AF; |
| 226 | + |
| 227 | + ret = regmap_bulk_read(regmap, ABEOZ9_REG_ALARM_SEC, regs, sizeof(regs)); |
| 228 | + if (ret) |
| 229 | + return ret; |
| 230 | + |
| 231 | + alarm->time.tm_sec = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_SEC, regs[0])); |
| 232 | + alarm->time.tm_min = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_MIN, regs[1])); |
| 233 | + alarm->time.tm_hour = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_HOURS, regs[2])); |
| 234 | + if (FIELD_GET(ABEOZ9_BIT_ALARM_HOURS_PM, regs[2])) |
| 235 | + alarm->time.tm_hour += 12; |
| 236 | + |
| 237 | + alarm->time.tm_mday = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_DAYS, regs[3])); |
| 238 | + |
| 239 | + return 0; |
| 240 | +} |
| 241 | + |
| 242 | +static int abeoz9_rtc_alarm_irq_enable(struct device *dev, u32 enable) |
| 243 | +{ |
| 244 | + struct abeoz9_rtc_data *data = dev_get_drvdata(dev); |
| 245 | + |
| 246 | + return regmap_update_bits(data->regmap, ABEOZ9_REG_CTRL_INT, |
| 247 | + ABEOZ9_REG_CTRL_INT_AIE, |
| 248 | + FIELD_PREP(ABEOZ9_REG_CTRL_INT_AIE, enable)); |
| 249 | +} |
| 250 | + |
| 251 | +static int abeoz9_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) |
| 252 | +{ |
| 253 | + struct abeoz9_rtc_data *data = dev_get_drvdata(dev); |
| 254 | + u8 regs[ABEOZ9_ALARM_LEN] = {0}; |
| 255 | + int ret; |
| 256 | + |
| 257 | + ret = regmap_update_bits(data->regmap, ABEOZ9_REG_CTRL_INT_FLAG, |
| 258 | + ABEOZ9_REG_CTRL_INT_FLAG_AF, 0); |
| 259 | + if (ret) |
| 260 | + return ret; |
| 261 | + |
| 262 | + regs[0] = ABEOZ9_BIT_ALARM_AE | FIELD_PREP(ABEOZ9_BIT_ALARM_SEC, |
| 263 | + bin2bcd(alarm->time.tm_sec)); |
| 264 | + regs[1] = ABEOZ9_BIT_ALARM_AE | FIELD_PREP(ABEOZ9_BIT_ALARM_MIN, |
| 265 | + bin2bcd(alarm->time.tm_min)); |
| 266 | + regs[2] = ABEOZ9_BIT_ALARM_AE | FIELD_PREP(ABEOZ9_BIT_ALARM_HOURS, |
| 267 | + bin2bcd(alarm->time.tm_hour)); |
| 268 | + regs[3] = ABEOZ9_BIT_ALARM_AE | FIELD_PREP(ABEOZ9_BIT_ALARM_DAYS, |
| 269 | + bin2bcd(alarm->time.tm_mday)); |
| 270 | + |
| 271 | + ret = regmap_bulk_write(data->regmap, ABEOZ9_REG_ALARM_SEC, regs, |
| 272 | + sizeof(regs)); |
| 273 | + if (ret) |
| 274 | + return ret; |
| 275 | + |
| 276 | + return abeoz9_rtc_alarm_irq_enable(dev, alarm->enabled); |
| 277 | +} |
| 278 | + |
| 279 | +static irqreturn_t abeoz9_rtc_irq(int irq, void *dev) |
| 280 | +{ |
| 281 | + struct abeoz9_rtc_data *data = dev_get_drvdata(dev); |
| 282 | + unsigned int val; |
| 283 | + int ret; |
| 284 | + |
| 285 | + ret = regmap_read(data->regmap, ABEOZ9_REG_CTRL_INT_FLAG, &val); |
| 286 | + if (ret) |
| 287 | + return IRQ_NONE; |
| 288 | + |
| 289 | + if (!FIELD_GET(ABEOZ9_REG_CTRL_INT_FLAG_AF, val)) |
| 290 | + return IRQ_NONE; |
| 291 | + |
| 292 | + regmap_update_bits(data->regmap, ABEOZ9_REG_CTRL_INT_FLAG, |
| 293 | + ABEOZ9_REG_CTRL_INT_FLAG_AF, 0); |
| 294 | + |
| 295 | + rtc_update_irq(data->rtc, 1, RTC_IRQF | RTC_AF); |
| 296 | + |
| 297 | + return IRQ_HANDLED; |
| 298 | +} |
| 299 | + |
189 | 300 | static int abeoz9_trickle_parse_dt(struct device_node *node)
|
190 | 301 | {
|
191 | 302 | u32 ohms = 0;
|
@@ -258,12 +369,16 @@ static int abeoz9_rtc_setup(struct device *dev, struct device_node *node)
|
258 | 369 |
|
259 | 370 | static const struct rtc_class_ops rtc_ops = {
|
260 | 371 | .read_time = abeoz9_rtc_get_time,
|
261 |
| - .set_time = abeoz9_rtc_set_time, |
| 372 | + .set_time = abeoz9_rtc_set_time, |
| 373 | + .read_alarm = abeoz9_rtc_read_alarm, |
| 374 | + .set_alarm = abeoz9_rtc_set_alarm, |
| 375 | + .alarm_irq_enable = abeoz9_rtc_alarm_irq_enable, |
262 | 376 | };
|
263 | 377 |
|
264 | 378 | static const struct regmap_config abeoz9_rtc_regmap_config = {
|
265 | 379 | .reg_bits = 8,
|
266 | 380 | .val_bits = 8,
|
| 381 | + .max_register = 0x3f, |
267 | 382 | };
|
268 | 383 |
|
269 | 384 | #if IS_REACHABLE(CONFIG_HWMON)
|
@@ -419,6 +534,24 @@ static int abeoz9_probe(struct i2c_client *client,
|
419 | 534 | data->rtc->ops = &rtc_ops;
|
420 | 535 | data->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
421 | 536 | data->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
| 537 | + data->rtc->uie_unsupported = 1; |
| 538 | + clear_bit(RTC_FEATURE_ALARM, data->rtc->features); |
| 539 | + |
| 540 | + if (client->irq > 0) { |
| 541 | + ret = devm_request_threaded_irq(dev, client->irq, NULL, |
| 542 | + abeoz9_rtc_irq, |
| 543 | + IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
| 544 | + dev_name(dev), dev); |
| 545 | + if (ret) { |
| 546 | + dev_err(dev, "failed to request alarm irq\n"); |
| 547 | + return ret; |
| 548 | + } |
| 549 | + } |
| 550 | + |
| 551 | + if (client->irq > 0 || device_property_read_bool(dev, "wakeup-source")) { |
| 552 | + ret = device_init_wakeup(dev, true); |
| 553 | + set_bit(RTC_FEATURE_ALARM, data->rtc->features); |
| 554 | + } |
422 | 555 |
|
423 | 556 | ret = devm_rtc_register_device(data->rtc);
|
424 | 557 | if (ret)
|
|
0 commit comments