| 1 | |
| 2 | |
| 3 | *
|
| 4 | * Driver for ST M41T93 SPI RTC
|
| 5 | *
|
| 6 | * (c) 2010 Nikolaus Voss, Weinmann Medical GmbH
|
| 7 |
|
| 8 |
|
| 9 | #include <linux/bcd.h>
|
| 10 | #include <linux/kernel.h>
|
| 11 | #include <linux/module.h>
|
| 12 | #include <linux/platform_device.h>
|
| 13 | #include <linux/rtc.h>
|
| 14 | #include <linux/spi/spi.h>
|
| 15 | #include <linux/regmap.h>
|
| 16 | #include <linux/clk-provider.h>
|
| 17 | #include <linux/watchdog.h>
|
| 18 |
|
| 19 | #define M41T93_REG_SSEC 0
|
| 20 | #define M41T93_REG_ST_SEC 1
|
| 21 | #define M41T93_REG_MIN 2
|
| 22 | #define M41T93_REG_CENT_HOUR 3
|
| 23 | #define M41T93_REG_WDAY 4
|
| 24 | #define M41T93_REG_DAY 5
|
| 25 | #define M41T93_REG_MON 6
|
| 26 | #define M41T93_REG_YEAR 7
|
| 27 | #define M41T93_REG_AL1_MONTH 0xa
|
| 28 | #define M41T93_REG_AL1_DATE 0xb
|
| 29 | #define M41T93_REG_AL1_HOUR 0xc
|
| 30 | #define M41T93_REG_AL1_MIN 0xd
|
| 31 | #define M41T93_REG_AL1_SEC 0xe
|
| 32 | #define M41T93_BIT_A1IE BIT(7)
|
| 33 | #define M41T93_BIT_ABE BIT(5)
|
| 34 | #define M41T93_FLAG_AF1 BIT(6)
|
| 35 | #define M41T93_SRAM_BASE 0x19
|
| 36 | #define M41T93_REG_SQW 0x13
|
| 37 | #define M41T93_SQW_RS_MASK 0xf0
|
| 38 | #define M41T93_SQW_RS_SHIFT 4
|
| 39 | #define M41T93_BIT_SQWE BIT(6)
|
| 40 | #define M41T93_REG_WATCHDOG 0x9
|
| 41 | #define M41T93_WDT_RB_MASK 0x3
|
| 42 | #define M41T93_WDT_BMB_MASK 0x7c
|
| 43 | #define M41T93_WDT_BMB_SHIFT 2
|
| 44 |
|
| 45 | #define M41T93_REG_ALM_HOUR_HT 0xc
|
| 46 | #define M41T93_REG_FLAGS 0xf
|
| 47 |
|
| 48 | #define M41T93_FLAG_ST (1 << 7)
|
| 49 | #define M41T93_FLAG_OF (1 << 2)
|
| 50 | #define M41T93_FLAG_BL (1 << 4)
|
| 51 | #define M41T93_FLAG_HT (1 << 6)
|
| 52 |
|
| 53 | struct m41t93_data {
|
| 54 | struct rtc_device *rtc;
|
| 55 | struct regmap *regmap;
|
| 56 | #ifdef CONFIG_COMMON_CLK
|
| 57 | struct clk_hw clks;
|
| 58 | #endif
|
| 59 | #ifdef CONFIG_WATCHDOG
|
| 60 | struct watchdog_device wdd;
|
| 61 | #endif
|
| 62 | };
|
| 63 |
|
| 64 | static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
|
| 65 | {
|
| 66 | struct m41t93_data *m41t93 = dev_get_drvdata(dev);
|
| 67 | int tmp, ret;
|
| 68 | u8 buf[8] = {0};
|
| 69 | u8 * const data = &buf[0];
|
| 70 |
|
| 71 | dev_dbg(dev, "%s secs=%d, mins=%d, "
|
| 72 | "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
|
| 73 | "write", tm->tm_sec, tm->tm_min,
|
| 74 | tm->tm_hour, tm->tm_mday,
|
| 75 | tm->tm_mon, tm->tm_year, tm->tm_wday);
|
| 76 |
|
| 77 | if (tm->tm_year < 100) {
|
| 78 | dev_warn(dev, "unsupported date (before 2000-01-01).\n");
|
| 79 | return -EINVAL;
|
| 80 | }
|
| 81 |
|
| 82 | ret = regmap_read(m41t93->regmap, M41T93_REG_FLAGS, &tmp);
|
| 83 | if (ret < 0)
|
| 84 | return ret;
|
| 85 |
|
| 86 | if (tmp & M41T93_FLAG_OF) {
|
| 87 | dev_warn(dev, "OF bit is set, resetting.\n");
|
| 88 | regmap_write(m41t93->regmap, M41T93_REG_FLAGS, tmp & ~M41T93_FLAG_OF);
|
| 89 |
|
| 90 | ret = regmap_read(m41t93->regmap, M41T93_REG_FLAGS, &tmp);
|
| 91 | if (ret < 0) {
|
| 92 | return ret;
|
| 93 | } else if (tmp & M41T93_FLAG_OF) {
|
| 94 | |
| 95 | * restarted.
|
| 96 | u8 reset_osc = buf[M41T93_REG_ST_SEC] | M41T93_FLAG_ST;
|
| 97 |
|
| 98 | dev_warn(dev,
|
| 99 | "OF bit is still set, kickstarting clock.\n");
|
| 100 | regmap_write(m41t93->regmap, M41T93_REG_ST_SEC, reset_osc);
|
| 101 | reset_osc &= ~M41T93_FLAG_ST;
|
| 102 | regmap_write(m41t93->regmap, M41T93_REG_ST_SEC, reset_osc);
|
| 103 | }
|
| 104 | }
|
| 105 |
|
| 106 | data[M41T93_REG_SSEC] = 0;
|
| 107 | data[M41T93_REG_ST_SEC] = bin2bcd(tm->tm_sec);
|
| 108 | data[M41T93_REG_MIN] = bin2bcd(tm->tm_min);
|
| 109 | data[M41T93_REG_CENT_HOUR] = bin2bcd(tm->tm_hour) |
|
| 110 | ((tm->tm_year/100-1) << 6);
|
| 111 | data[M41T93_REG_DAY] = bin2bcd(tm->tm_mday);
|
| 112 | data[M41T93_REG_WDAY] = bin2bcd(tm->tm_wday + 1);
|
| 113 | data[M41T93_REG_MON] = bin2bcd(tm->tm_mon + 1);
|
| 114 | data[M41T93_REG_YEAR] = bin2bcd(tm->tm_year % 100);
|
| 115 |
|
| 116 | return regmap_bulk_write(m41t93->regmap, M41T93_REG_SSEC, buf, sizeof(buf));
|
| 117 | }
|
| 118 |
|
| 119 |
|
| 120 | static int m41t93_get_time(struct device *dev, struct rtc_time *tm)
|
| 121 | {
|
| 122 | struct m41t93_data *m41t93 = dev_get_drvdata(dev);
|
| 123 | u8 buf[8];
|
| 124 | int century_after_1900;
|
| 125 | int tmp;
|
| 126 | int ret = 0;
|
| 127 |
|
| 128 | |
| 129 | 1. halt bit (HT) is set: the clock is running but update of readout
|
| 130 | registers has been disabled due to power failure. This is normal
|
| 131 | case after poweron. Time is valid after resetting HT bit.
|
| 132 | 2. oscillator fail bit (OF) is set: time is invalid.
|
| 133 |
|
| 134 | ret = regmap_read(m41t93->regmap, M41T93_REG_ALM_HOUR_HT, &tmp);
|
| 135 | if (ret < 0)
|
| 136 | return ret;
|
| 137 |
|
| 138 | if (tmp & M41T93_FLAG_HT) {
|
| 139 | dev_dbg(dev, "HT bit is set, reenable clock update.\n");
|
| 140 | regmap_write(m41t93->regmap, M41T93_REG_ALM_HOUR_HT,
|
| 141 | tmp & ~M41T93_FLAG_HT);
|
| 142 | }
|
| 143 |
|
| 144 | ret = regmap_read(m41t93->regmap, M41T93_REG_FLAGS, &tmp);
|
| 145 | if (ret < 0)
|
| 146 | return ret;
|
| 147 |
|
| 148 | if (tmp & M41T93_FLAG_OF) {
|
| 149 | ret = -EINVAL;
|
| 150 | dev_warn(dev, "OF bit is set, write time to restart.\n");
|
| 151 | }
|
| 152 |
|
| 153 | if (tmp & M41T93_FLAG_BL)
|
| 154 | dev_warn(dev, "BL bit is set, replace battery.\n");
|
| 155 |
|
| 156 |
|
| 157 | ret = regmap_bulk_read(m41t93->regmap, M41T93_REG_SSEC, buf, sizeof(buf));
|
| 158 | if (ret < 0)
|
| 159 | return ret;
|
| 160 |
|
| 161 | tm->tm_sec = bcd2bin(buf[M41T93_REG_ST_SEC]);
|
| 162 | tm->tm_min = bcd2bin(buf[M41T93_REG_MIN]);
|
| 163 | tm->tm_hour = bcd2bin(buf[M41T93_REG_CENT_HOUR] & 0x3f);
|
| 164 | tm->tm_mday = bcd2bin(buf[M41T93_REG_DAY]);
|
| 165 | tm->tm_mon = bcd2bin(buf[M41T93_REG_MON]) - 1;
|
| 166 | tm->tm_wday = bcd2bin(buf[M41T93_REG_WDAY] & 0x0f) - 1;
|
| 167 |
|
| 168 | century_after_1900 = (buf[M41T93_REG_CENT_HOUR] >> 6) + 1;
|
| 169 | tm->tm_year = bcd2bin(buf[M41T93_REG_YEAR]) + century_after_1900 * 100;
|
| 170 |
|
| 171 | dev_dbg(dev, "%s secs=%d, mins=%d, "
|
| 172 | "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
|
| 173 | "read", tm->tm_sec, tm->tm_min,
|
| 174 | tm->tm_hour, tm->tm_mday,
|
| 175 | tm->tm_mon, tm->tm_year, tm->tm_wday);
|
| 176 |
|
| 177 | return ret;
|
| 178 | }
|
| 179 |
|
| 180 | static int m41t93_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
| 181 | {
|
| 182 | struct m41t93_data *m41t93 = dev_get_drvdata(dev);
|
| 183 | int ret;
|
| 184 | unsigned int val;
|
| 185 | u8 alarm_vals[5] = {0};
|
| 186 |
|
| 187 | ret = regmap_bulk_write(m41t93->regmap, M41T93_REG_AL1_DATE, alarm_vals, 4);
|
| 188 | if (ret)
|
| 189 | return ret;
|
| 190 |
|
| 191 |
|
| 192 | alarm_vals[0] = bin2bcd(alrm->time.tm_mon + 1) & 0x1f;
|
| 193 | alarm_vals[1] = bin2bcd(alrm->time.tm_mday) & 0x3f;
|
| 194 | alarm_vals[2] = bin2bcd(alrm->time.tm_hour) & 0x3f;
|
| 195 | alarm_vals[3] = bin2bcd(alrm->time.tm_min) & 0x7f;
|
| 196 | alarm_vals[4] = bin2bcd(alrm->time.tm_sec) & 0x7f;
|
| 197 |
|
| 198 | if (alrm->enabled) {
|
| 199 |
|
| 200 | alarm_vals[0] |= M41T93_BIT_A1IE | M41T93_BIT_ABE;
|
| 201 | }
|
| 202 |
|
| 203 |
|
| 204 | ret = regmap_read(m41t93->regmap, M41T93_REG_AL1_MONTH, &val);
|
| 205 | if (ret)
|
| 206 | return ret;
|
| 207 |
|
| 208 | alarm_vals[0] |= val & 0x40;
|
| 209 |
|
| 210 | ret = regmap_bulk_write(m41t93->regmap, M41T93_REG_AL1_MONTH,
|
| 211 | alarm_vals, sizeof(alarm_vals));
|
| 212 | if (ret)
|
| 213 | return ret;
|
| 214 |
|
| 215 | |
| 216 | * to finish setting alarm, as recommended by the datasheet.
|
| 217 | * We do read of AL1_MONTH register to achieve this.
|
| 218 |
|
| 219 | ret = regmap_read(m41t93->regmap, M41T93_REG_AL1_MONTH, &val);
|
| 220 | if (ret)
|
| 221 | return ret;
|
| 222 |
|
| 223 | if (bcd2bin(val & 0x1f) == (alrm->time.tm_mon & 0x1f))
|
| 224 | dev_notice(dev, "Alarm set successfully\n");
|
| 225 |
|
| 226 | return 0;
|
| 227 | }
|
| 228 |
|
| 229 | static int m41t93_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
| 230 | {
|
| 231 | struct m41t93_data *m41t93 = dev_get_drvdata(dev);
|
| 232 | int ret;
|
| 233 | unsigned int val;
|
| 234 | u8 alarm_vals[5] = {0};
|
| 235 |
|
| 236 | ret = regmap_bulk_read(m41t93->regmap, M41T93_REG_AL1_MONTH,
|
| 237 | alarm_vals, sizeof(alarm_vals));
|
| 238 | if (ret)
|
| 239 | return ret;
|
| 240 |
|
| 241 | alrm->time.tm_mon = bcd2bin(alarm_vals[0] & 0x1f) - 1;
|
| 242 | alrm->time.tm_mday = bcd2bin(alarm_vals[1] & 0x3f);
|
| 243 | alrm->time.tm_hour = bcd2bin(alarm_vals[2] & 0x3f);
|
| 244 | alrm->time.tm_min = bcd2bin(alarm_vals[3] & 0x7f);
|
| 245 | alrm->time.tm_sec = bcd2bin(alarm_vals[4] & 0x7f);
|
| 246 |
|
| 247 | alrm->enabled = !!(alarm_vals[0] & M41T93_BIT_A1IE);
|
| 248 |
|
| 249 | ret = regmap_read(m41t93->regmap, M41T93_REG_FLAGS, &val);
|
| 250 | if (ret)
|
| 251 | return ret;
|
| 252 |
|
| 253 | alrm->pending = (val & M41T93_FLAG_AF1) && alrm->enabled;
|
| 254 |
|
| 255 | return 0;
|
| 256 | }
|
| 257 |
|
| 258 | static int m41t93_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
| 259 | {
|
| 260 | struct m41t93_data *m41t93 = dev_get_drvdata(dev);
|
| 261 | unsigned int val;
|
| 262 | int ret;
|
| 263 |
|
| 264 | val = enabled ? M41T93_BIT_A1IE | M41T93_BIT_ABE : 0;
|
| 265 |
|
| 266 | ret = regmap_update_bits(m41t93->regmap, M41T93_REG_AL1_MONTH,
|
| 267 | M41T93_BIT_A1IE | M41T93_BIT_ABE, val);
|
| 268 | if (ret)
|
| 269 | return ret;
|
| 270 |
|
| 271 | return 0;
|
| 272 | }
|
| 273 |
|
| 274 |
|
| 275 | static const struct rtc_class_ops m41t93_rtc_ops = {
|
| 276 | .read_time = m41t93_get_time,
|
| 277 | .set_time = m41t93_set_time,
|
| 278 | .set_alarm = m41t93_set_alarm,
|
| 279 | .read_alarm = m41t93_get_alarm,
|
| 280 | .alarm_irq_enable = m41t93_alarm_irq_enable,
|
| 281 | };
|
| 282 |
|
| 283 | #ifdef CONFIG_COMMON_CLK
|
| 284 | #define clk_sqw_to_m41t93_data(clk) \
|
| 285 | container_of(clk, struct m41t93_data, clks)
|
| 286 |
|
| 287 |
|
| 288 | static unsigned long m41t93_clk_rates[] = {
|
| 289 | 0,
|
| 290 | 32768,
|
| 291 | 8192,
|
| 292 | 4096,
|
| 293 | 2048,
|
| 294 | 1024,
|
| 295 | 512,
|
| 296 | 256,
|
| 297 | 128,
|
| 298 | 64,
|
| 299 | 32,
|
| 300 | 16,
|
| 301 | 8,
|
| 302 | 4,
|
| 303 | 2,
|
| 304 | 1,
|
| 305 | };
|
| 306 |
|
| 307 | static unsigned long m41t93_clk_sqw_recalc_rate(struct clk_hw *hw,
|
| 308 | unsigned long parent_rate)
|
| 309 | {
|
| 310 | int ret;
|
| 311 | unsigned int rate_id;
|
| 312 | struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
|
| 313 |
|
| 314 | ret = regmap_read(m41t93->regmap, M41T93_REG_SQW, &rate_id);
|
| 315 | if (ret)
|
| 316 | return ret;
|
| 317 |
|
| 318 | rate_id &= M41T93_SQW_RS_MASK;
|
| 319 | rate_id >>= M41T93_SQW_RS_SHIFT;
|
| 320 |
|
| 321 | return m41t93_clk_rates[rate_id];
|
| 322 | }
|
| 323 |
|
| 324 | static int m41t93_clk_sqw_determine_rate(struct clk_hw *hw,
|
| 325 | struct clk_rate_request *req)
|
| 326 | {
|
| 327 | int i;
|
| 328 |
|
| 329 | for (i = 1; i < ARRAY_SIZE(m41t93_clk_rates); i++) {
|
| 330 | if (req->rate >= m41t93_clk_rates[i]) {
|
| 331 | req->rate = m41t93_clk_rates[i];
|
| 332 | return 0;
|
| 333 | }
|
| 334 | }
|
| 335 |
|
| 336 | return 0;
|
| 337 | }
|
| 338 |
|
| 339 | static int m41t93_clk_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
|
| 340 | unsigned long parent_rate)
|
| 341 | {
|
| 342 | int id, ret;
|
| 343 | struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
|
| 344 |
|
| 345 | for (id = 0; id < ARRAY_SIZE(m41t93_clk_rates); id++) {
|
| 346 | if (m41t93_clk_rates[id] == rate)
|
| 347 | break;
|
| 348 | }
|
| 349 |
|
| 350 | if (id >= ARRAY_SIZE(m41t93_clk_rates))
|
| 351 | return -EINVAL;
|
| 352 |
|
| 353 | ret = regmap_update_bits(m41t93->regmap, M41T93_REG_SQW,
|
| 354 | M41T93_SQW_RS_MASK, id << M41T93_SQW_RS_SHIFT);
|
| 355 |
|
| 356 | return ret;
|
| 357 | }
|
| 358 |
|
| 359 | static int m41t93_clk_sqw_prepare(struct clk_hw *hw)
|
| 360 | {
|
| 361 | int ret;
|
| 362 | struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
|
| 363 |
|
| 364 | ret = regmap_update_bits(m41t93->regmap, M41T93_REG_AL1_MONTH,
|
| 365 | M41T93_BIT_SQWE, M41T93_BIT_SQWE);
|
| 366 |
|
| 367 | return ret;
|
| 368 | }
|
| 369 |
|
| 370 | static void m41t93_clk_sqw_unprepare(struct clk_hw *hw)
|
| 371 | {
|
| 372 | struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
|
| 373 |
|
| 374 | regmap_update_bits(m41t93->regmap, M41T93_REG_AL1_MONTH,
|
| 375 | M41T93_BIT_SQWE, 0);
|
| 376 | }
|
| 377 |
|
| 378 | static int m41t93_clk_sqw_is_prepared(struct clk_hw *hw)
|
| 379 | {
|
| 380 | int ret;
|
| 381 | struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
|
| 382 | unsigned int status;
|
| 383 |
|
| 384 | ret = regmap_read(m41t93->regmap, M41T93_REG_AL1_MONTH, &status);
|
| 385 | if (ret)
|
| 386 | return ret;
|
| 387 |
|
| 388 | return !!(status & M41T93_BIT_SQWE);
|
| 389 | }
|
| 390 |
|
| 391 | static const struct clk_ops m41t93_clk_sqw_ops = {
|
| 392 | .prepare = m41t93_clk_sqw_prepare,
|
| 393 | .unprepare = m41t93_clk_sqw_unprepare,
|
| 394 | .is_prepared = m41t93_clk_sqw_is_prepared,
|
| 395 | .recalc_rate = m41t93_clk_sqw_recalc_rate,
|
| 396 | .set_rate = m41t93_clk_sqw_set_rate,
|
| 397 | .determine_rate = m41t93_clk_sqw_determine_rate,
|
| 398 | };
|
| 399 |
|
| 400 | static int rtc_m41t93_clks_register(struct device *dev, struct m41t93_data *m41t93)
|
| 401 | {
|
| 402 | struct device_node *node = dev->of_node;
|
| 403 | struct clk *clk;
|
| 404 | struct clk_init_data init = {0};
|
| 405 |
|
| 406 | init.name = "m41t93_clk_sqw";
|
| 407 | init.ops = &m41t93_clk_sqw_ops;
|
| 408 |
|
| 409 | m41t93->clks.init = &init;
|
| 410 |
|
| 411 |
|
| 412 | clk = devm_clk_register(dev, &m41t93->clks);
|
| 413 | if (IS_ERR(clk))
|
| 414 | return PTR_ERR(clk);
|
| 415 |
|
| 416 | if (node)
|
| 417 | of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
| 418 |
|
| 419 | return 0;
|
| 420 | }
|
| 421 | #endif
|
| 422 |
|
| 423 | #ifdef CONFIG_WATCHDOG
|
| 424 | static int m41t93_wdt_ping(struct watchdog_device *wdd)
|
| 425 | {
|
| 426 | u8 resolution, mult;
|
| 427 | u8 val = 0;
|
| 428 | int ret;
|
| 429 | struct m41t93_data *m41t93 = watchdog_get_drvdata(wdd);
|
| 430 |
|
| 431 | |
| 432 | * 0b00 : 1/16 seconds
|
| 433 | * 0b01 : 1/4 second
|
| 434 | * 0b10 : 1 second
|
| 435 | * 0b11 : 4 seconds
|
| 436 |
|
| 437 | resolution = 0x2;
|
| 438 | mult = wdd->timeout;
|
| 439 | val = resolution | (mult << M41T93_WDT_BMB_SHIFT & M41T93_WDT_BMB_MASK);
|
| 440 |
|
| 441 | ret = regmap_write_bits(m41t93->regmap, M41T93_REG_WATCHDOG,
|
| 442 | M41T93_WDT_RB_MASK | M41T93_WDT_BMB_MASK, val);
|
| 443 |
|
| 444 | return ret;
|
| 445 | }
|
| 446 |
|
| 447 | static int m41t93_wdt_start(struct watchdog_device *wdd)
|
| 448 | {
|
| 449 | return m41t93_wdt_ping(wdd);
|
| 450 | }
|
| 451 |
|
| 452 | static int m41t93_wdt_stop(struct watchdog_device *wdd)
|
| 453 | {
|
| 454 | struct m41t93_data *m41t93 = watchdog_get_drvdata(wdd);
|
| 455 |
|
| 456 |
|
| 457 | return regmap_write_bits(m41t93->regmap, M41T93_REG_WATCHDOG,
|
| 458 | M41T93_WDT_RB_MASK | M41T93_WDT_BMB_MASK, 0);
|
| 459 | }
|
| 460 |
|
| 461 | static int m41t93_wdt_set_timeout(struct watchdog_device *wdd,
|
| 462 | unsigned int new_timeout)
|
| 463 | {
|
| 464 | wdd->timeout = new_timeout;
|
| 465 |
|
| 466 | return 0;
|
| 467 | }
|
| 468 |
|
| 469 | static const struct watchdog_info m41t93_wdt_info = {
|
| 470 | .identity = "m41t93 rtc Watchdog",
|
| 471 | .options = WDIOF_ALARMONLY | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
|
| 472 | };
|
| 473 |
|
| 474 | static const struct watchdog_ops m41t93_watchdog_ops = {
|
| 475 | .owner = THIS_MODULE,
|
| 476 | .start = m41t93_wdt_start,
|
| 477 | .stop = m41t93_wdt_stop,
|
| 478 | .ping = m41t93_wdt_ping,
|
| 479 | .set_timeout = m41t93_wdt_set_timeout,
|
| 480 | };
|
| 481 |
|
| 482 | static int m41t93_watchdog_register(struct device *dev, struct m41t93_data *m41t93)
|
| 483 | {
|
| 484 | int ret;
|
| 485 |
|
| 486 | m41t93->wdd.parent = dev;
|
| 487 | m41t93->wdd.info = &m41t93_wdt_info;
|
| 488 | m41t93->wdd.ops = &m41t93_watchdog_ops;
|
| 489 | m41t93->wdd.min_timeout = 0;
|
| 490 | m41t93->wdd.max_timeout = 10;
|
| 491 | m41t93->wdd.timeout = 3;
|
| 492 | m41t93->wdd.status = WATCHDOG_NOWAYOUT_INIT_STATUS;
|
| 493 |
|
| 494 | watchdog_set_drvdata(&m41t93->wdd, m41t93);
|
| 495 |
|
| 496 | ret = devm_watchdog_register_device(dev, &m41t93->wdd);
|
| 497 | if (ret) {
|
| 498 | dev_warn(dev, "Failed to register watchdog\n");
|
| 499 | return ret;
|
| 500 | }
|
| 501 |
|
| 502 |
|
| 503 | ret = m41t93_wdt_stop(&m41t93->wdd);
|
| 504 |
|
| 505 | return ret;
|
| 506 | }
|
| 507 | #endif
|
| 508 |
|
| 509 | static struct spi_driver m41t93_driver;
|
| 510 |
|
| 511 | static const struct regmap_config regmap_config = {
|
| 512 | .reg_bits = 8,
|
| 513 | .val_bits = 8,
|
| 514 | .read_flag_mask = 0x00,
|
| 515 | .write_flag_mask = 0x80,
|
| 516 | .zero_flag_mask = true,
|
| 517 | };
|
| 518 |
|
| 519 | static int m41t93_probe(struct spi_device *spi)
|
| 520 | {
|
| 521 | int res, ret;
|
| 522 | struct m41t93_data *m41t93;
|
| 523 |
|
| 524 | spi->bits_per_word = 8;
|
| 525 | spi_setup(spi);
|
| 526 |
|
| 527 | m41t93 = devm_kzalloc(&spi->dev, sizeof(struct m41t93_data), GFP_KERNEL);
|
| 528 |
|
| 529 | if (!m41t93)
|
| 530 | return -ENOMEM;
|
| 531 |
|
| 532 |
|
| 533 | m41t93->regmap = devm_regmap_init_spi(spi, ®map_config);
|
| 534 | if (IS_ERR(m41t93->regmap)) {
|
| 535 | dev_err(&spi->dev, "regmap init failure\n");
|
| 536 | return PTR_ERR(m41t93->regmap);
|
| 537 | }
|
| 538 |
|
| 539 | ret = regmap_read(m41t93->regmap, M41T93_REG_WDAY, &res);
|
| 540 | if (ret < 0) {
|
| 541 | dev_err(&spi->dev, "IO error\n");
|
| 542 | return -EIO;
|
| 543 | }
|
| 544 |
|
| 545 | if (res < 0 || (res & 0xf8) != 0) {
|
| 546 | dev_err(&spi->dev, "not found 0x%x.\n", res);
|
| 547 | return -ENODEV;
|
| 548 | }
|
| 549 |
|
| 550 | spi_set_drvdata(spi, m41t93);
|
| 551 |
|
| 552 | m41t93->rtc = devm_rtc_device_register(&spi->dev, m41t93_driver.driver.name,
|
| 553 | &m41t93_rtc_ops, THIS_MODULE);
|
| 554 | if (IS_ERR(m41t93->rtc))
|
| 555 | return PTR_ERR(m41t93->rtc);
|
| 556 |
|
| 557 | #ifdef CONFIG_COMMON_CLK
|
| 558 | ret = rtc_m41t93_clks_register(&spi->dev, m41t93);
|
| 559 | if (ret)
|
| 560 | dev_warn(&spi->dev, "Unable to register clock\n");
|
| 561 | #endif
|
| 562 | #ifdef CONFIG_WATCHDOG
|
| 563 | ret = m41t93_watchdog_register(&spi->dev, m41t93);
|
| 564 | if (ret)
|
| 565 | dev_warn(&spi->dev, "Unable to register watchdog\n");
|
| 566 | #endif
|
| 567 |
|
| 568 | return 0;
|
| 569 | }
|
| 570 |
|
| 571 | static const struct of_device_id m41t93_dt_match[] = {
|
| 572 | { .compatible = "st,m41t93" },
|
| 573 | { }
|
| 574 | };
|
| 575 | MODULE_DEVICE_TABLE(of, m41t93_dt_match);
|
| 576 |
|
| 577 | static struct spi_driver m41t93_driver = {
|
| 578 | .driver = {
|
| 579 | .name = "rtc-m41t93",
|
| 580 | .of_match_table = m41t93_dt_match,
|
| 581 | },
|
| 582 | .probe = m41t93_probe,
|
| 583 | };
|
| 584 |
|
| 585 | module_spi_driver(m41t93_driver);
|
| 586 |
|
| 587 | MODULE_AUTHOR("Nikolaus Voss <[email protected]>");
|
| 588 | MODULE_DESCRIPTION("Driver for ST M41T93 SPI RTC");
|
| 589 | MODULE_LICENSE("GPL");
|
| 590 | MODULE_ALIAS("spi:rtc-m41t93");
|