linux/drivers/rtc/rtc-ac100.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * RTC Driver for X-Powers AC100
   4 *
   5 * Copyright (c) 2016 Chen-Yu Tsai
   6 *
   7 * Chen-Yu Tsai <wens@csie.org>
   8 */
   9
  10#include <linux/bcd.h>
  11#include <linux/clk-provider.h>
  12#include <linux/device.h>
  13#include <linux/interrupt.h>
  14#include <linux/kernel.h>
  15#include <linux/mfd/ac100.h>
  16#include <linux/module.h>
  17#include <linux/mutex.h>
  18#include <linux/of.h>
  19#include <linux/platform_device.h>
  20#include <linux/regmap.h>
  21#include <linux/rtc.h>
  22#include <linux/types.h>
  23
  24/* Control register */
  25#define AC100_RTC_CTRL_24HOUR   BIT(0)
  26
  27/* Clock output register bits */
  28#define AC100_CLKOUT_PRE_DIV_SHIFT      5
  29#define AC100_CLKOUT_PRE_DIV_WIDTH      3
  30#define AC100_CLKOUT_MUX_SHIFT          4
  31#define AC100_CLKOUT_MUX_WIDTH          1
  32#define AC100_CLKOUT_DIV_SHIFT          1
  33#define AC100_CLKOUT_DIV_WIDTH          3
  34#define AC100_CLKOUT_EN                 BIT(0)
  35
  36/* RTC */
  37#define AC100_RTC_SEC_MASK      GENMASK(6, 0)
  38#define AC100_RTC_MIN_MASK      GENMASK(6, 0)
  39#define AC100_RTC_HOU_MASK      GENMASK(5, 0)
  40#define AC100_RTC_WEE_MASK      GENMASK(2, 0)
  41#define AC100_RTC_DAY_MASK      GENMASK(5, 0)
  42#define AC100_RTC_MON_MASK      GENMASK(4, 0)
  43#define AC100_RTC_YEA_MASK      GENMASK(7, 0)
  44#define AC100_RTC_YEA_LEAP      BIT(15)
  45#define AC100_RTC_UPD_TRIGGER   BIT(15)
  46
  47/* Alarm (wall clock) */
  48#define AC100_ALM_INT_ENABLE    BIT(0)
  49
  50#define AC100_ALM_SEC_MASK      GENMASK(6, 0)
  51#define AC100_ALM_MIN_MASK      GENMASK(6, 0)
  52#define AC100_ALM_HOU_MASK      GENMASK(5, 0)
  53#define AC100_ALM_WEE_MASK      GENMASK(2, 0)
  54#define AC100_ALM_DAY_MASK      GENMASK(5, 0)
  55#define AC100_ALM_MON_MASK      GENMASK(4, 0)
  56#define AC100_ALM_YEA_MASK      GENMASK(7, 0)
  57#define AC100_ALM_ENABLE_FLAG   BIT(15)
  58#define AC100_ALM_UPD_TRIGGER   BIT(15)
  59
  60/*
  61 * The year parameter passed to the driver is usually an offset relative to
  62 * the year 1900. This macro is used to convert this offset to another one
  63 * relative to the minimum year allowed by the hardware.
  64 *
  65 * The year range is 1970 - 2069. This range is selected to match Allwinner's
  66 * driver.
  67 */
  68#define AC100_YEAR_MIN                          1970
  69#define AC100_YEAR_MAX                          2069
  70#define AC100_YEAR_OFF                          (AC100_YEAR_MIN - 1900)
  71
  72struct ac100_clkout {
  73        struct clk_hw hw;
  74        struct regmap *regmap;
  75        u8 offset;
  76};
  77
  78#define to_ac100_clkout(_hw) container_of(_hw, struct ac100_clkout, hw)
  79
  80#define AC100_RTC_32K_NAME      "ac100-rtc-32k"
  81#define AC100_RTC_32K_RATE      32768
  82#define AC100_CLKOUT_NUM        3
  83
  84static const char * const ac100_clkout_names[AC100_CLKOUT_NUM] = {
  85        "ac100-cko1-rtc",
  86        "ac100-cko2-rtc",
  87        "ac100-cko3-rtc",
  88};
  89
  90struct ac100_rtc_dev {
  91        struct rtc_device *rtc;
  92        struct device *dev;
  93        struct regmap *regmap;
  94        int irq;
  95        unsigned long alarm;
  96
  97        struct clk_hw *rtc_32k_clk;
  98        struct ac100_clkout clks[AC100_CLKOUT_NUM];
  99        struct clk_hw_onecell_data *clk_data;
 100};
 101
 102/**
 103 * Clock controls for 3 clock output pins
 104 */
 105
 106static const struct clk_div_table ac100_clkout_prediv[] = {
 107        { .val = 0, .div = 1 },
 108        { .val = 1, .div = 2 },
 109        { .val = 2, .div = 4 },
 110        { .val = 3, .div = 8 },
 111        { .val = 4, .div = 16 },
 112        { .val = 5, .div = 32 },
 113        { .val = 6, .div = 64 },
 114        { .val = 7, .div = 122 },
 115        { },
 116};
 117
 118/* Abuse the fact that one parent is 32768 Hz, and the other is 4 MHz */
 119static unsigned long ac100_clkout_recalc_rate(struct clk_hw *hw,
 120                                              unsigned long prate)
 121{
 122        struct ac100_clkout *clk = to_ac100_clkout(hw);
 123        unsigned int reg, div;
 124
 125        regmap_read(clk->regmap, clk->offset, &reg);
 126
 127        /* Handle pre-divider first */
 128        if (prate != AC100_RTC_32K_RATE) {
 129                div = (reg >> AC100_CLKOUT_PRE_DIV_SHIFT) &
 130                        ((1 << AC100_CLKOUT_PRE_DIV_WIDTH) - 1);
 131                prate = divider_recalc_rate(hw, prate, div,
 132                                            ac100_clkout_prediv, 0,
 133                                            AC100_CLKOUT_PRE_DIV_WIDTH);
 134        }
 135
 136        div = (reg >> AC100_CLKOUT_DIV_SHIFT) &
 137                (BIT(AC100_CLKOUT_DIV_WIDTH) - 1);
 138        return divider_recalc_rate(hw, prate, div, NULL,
 139                                   CLK_DIVIDER_POWER_OF_TWO,
 140                                   AC100_CLKOUT_DIV_WIDTH);
 141}
 142
 143static long ac100_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
 144                                    unsigned long prate)
 145{
 146        unsigned long best_rate = 0, tmp_rate, tmp_prate;
 147        int i;
 148
 149        if (prate == AC100_RTC_32K_RATE)
 150                return divider_round_rate(hw, rate, &prate, NULL,
 151                                          AC100_CLKOUT_DIV_WIDTH,
 152                                          CLK_DIVIDER_POWER_OF_TWO);
 153
 154        for (i = 0; ac100_clkout_prediv[i].div; i++) {
 155                tmp_prate = DIV_ROUND_UP(prate, ac100_clkout_prediv[i].val);
 156                tmp_rate = divider_round_rate(hw, rate, &tmp_prate, NULL,
 157                                              AC100_CLKOUT_DIV_WIDTH,
 158                                              CLK_DIVIDER_POWER_OF_TWO);
 159
 160                if (tmp_rate > rate)
 161                        continue;
 162                if (rate - tmp_rate < best_rate - tmp_rate)
 163                        best_rate = tmp_rate;
 164        }
 165
 166        return best_rate;
 167}
 168
 169static int ac100_clkout_determine_rate(struct clk_hw *hw,
 170                                       struct clk_rate_request *req)
 171{
 172        struct clk_hw *best_parent;
 173        unsigned long best = 0;
 174        int i, num_parents = clk_hw_get_num_parents(hw);
 175
 176        for (i = 0; i < num_parents; i++) {
 177                struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i);
 178                unsigned long tmp, prate;
 179
 180                /*
 181                 * The clock has two parents, one is a fixed clock which is
 182                 * internally registered by the ac100 driver. The other parent
 183                 * is a clock from the codec side of the chip, which we
 184                 * properly declare and reference in the devicetree and is
 185                 * not implemented in any driver right now.
 186                 * If the clock core looks for the parent of that second
 187                 * missing clock, it can't find one that is registered and
 188                 * returns NULL.
 189                 * So we end up in a situation where clk_hw_get_num_parents
 190                 * returns the amount of clocks we can be parented to, but
 191                 * clk_hw_get_parent_by_index will not return the orphan
 192                 * clocks.
 193                 * Thus we need to check if the parent exists before
 194                 * we get the parent rate, so we could use the RTC
 195                 * without waiting for the codec to be supported.
 196                 */
 197                if (!parent)
 198                        continue;
 199
 200                prate = clk_hw_get_rate(parent);
 201
 202                tmp = ac100_clkout_round_rate(hw, req->rate, prate);
 203
 204                if (tmp > req->rate)
 205                        continue;
 206                if (req->rate - tmp < req->rate - best) {
 207                        best = tmp;
 208                        best_parent = parent;
 209                }
 210        }
 211
 212        if (!best)
 213                return -EINVAL;
 214
 215        req->best_parent_hw = best_parent;
 216        req->best_parent_rate = best;
 217        req->rate = best;
 218
 219        return 0;
 220}
 221
 222static int ac100_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
 223                                 unsigned long prate)
 224{
 225        struct ac100_clkout *clk = to_ac100_clkout(hw);
 226        int div = 0, pre_div = 0;
 227
 228        do {
 229                div = divider_get_val(rate * ac100_clkout_prediv[pre_div].div,
 230                                      prate, NULL, AC100_CLKOUT_DIV_WIDTH,
 231                                      CLK_DIVIDER_POWER_OF_TWO);
 232                if (div >= 0)
 233                        break;
 234        } while (prate != AC100_RTC_32K_RATE &&
 235                 ac100_clkout_prediv[++pre_div].div);
 236
 237        if (div < 0)
 238                return div;
 239
 240        pre_div = ac100_clkout_prediv[pre_div].val;
 241
 242        regmap_update_bits(clk->regmap, clk->offset,
 243                           ((1 << AC100_CLKOUT_DIV_WIDTH) - 1) << AC100_CLKOUT_DIV_SHIFT |
 244                           ((1 << AC100_CLKOUT_PRE_DIV_WIDTH) - 1) << AC100_CLKOUT_PRE_DIV_SHIFT,
 245                           (div - 1) << AC100_CLKOUT_DIV_SHIFT |
 246                           (pre_div - 1) << AC100_CLKOUT_PRE_DIV_SHIFT);
 247
 248        return 0;
 249}
 250
 251static int ac100_clkout_prepare(struct clk_hw *hw)
 252{
 253        struct ac100_clkout *clk = to_ac100_clkout(hw);
 254
 255        return regmap_update_bits(clk->regmap, clk->offset, AC100_CLKOUT_EN,
 256                                  AC100_CLKOUT_EN);
 257}
 258
 259static void ac100_clkout_unprepare(struct clk_hw *hw)
 260{
 261        struct ac100_clkout *clk = to_ac100_clkout(hw);
 262
 263        regmap_update_bits(clk->regmap, clk->offset, AC100_CLKOUT_EN, 0);
 264}
 265
 266static int ac100_clkout_is_prepared(struct clk_hw *hw)
 267{
 268        struct ac100_clkout *clk = to_ac100_clkout(hw);
 269        unsigned int reg;
 270
 271        regmap_read(clk->regmap, clk->offset, &reg);
 272
 273        return reg & AC100_CLKOUT_EN;
 274}
 275
 276static u8 ac100_clkout_get_parent(struct clk_hw *hw)
 277{
 278        struct ac100_clkout *clk = to_ac100_clkout(hw);
 279        unsigned int reg;
 280
 281        regmap_read(clk->regmap, clk->offset, &reg);
 282
 283        return (reg >> AC100_CLKOUT_MUX_SHIFT) & 0x1;
 284}
 285
 286static int ac100_clkout_set_parent(struct clk_hw *hw, u8 index)
 287{
 288        struct ac100_clkout *clk = to_ac100_clkout(hw);
 289
 290        return regmap_update_bits(clk->regmap, clk->offset,
 291                                  BIT(AC100_CLKOUT_MUX_SHIFT),
 292                                  index ? BIT(AC100_CLKOUT_MUX_SHIFT) : 0);
 293}
 294
 295static const struct clk_ops ac100_clkout_ops = {
 296        .prepare        = ac100_clkout_prepare,
 297        .unprepare      = ac100_clkout_unprepare,
 298        .is_prepared    = ac100_clkout_is_prepared,
 299        .recalc_rate    = ac100_clkout_recalc_rate,
 300        .determine_rate = ac100_clkout_determine_rate,
 301        .get_parent     = ac100_clkout_get_parent,
 302        .set_parent     = ac100_clkout_set_parent,
 303        .set_rate       = ac100_clkout_set_rate,
 304};
 305
 306static int ac100_rtc_register_clks(struct ac100_rtc_dev *chip)
 307{
 308        struct device_node *np = chip->dev->of_node;
 309        const char *parents[2] = {AC100_RTC_32K_NAME};
 310        int i, ret;
 311
 312        chip->clk_data = devm_kzalloc(chip->dev,
 313                                      struct_size(chip->clk_data, hws,
 314                                                  AC100_CLKOUT_NUM),
 315                                      GFP_KERNEL);
 316        if (!chip->clk_data)
 317                return -ENOMEM;
 318
 319        chip->rtc_32k_clk = clk_hw_register_fixed_rate(chip->dev,
 320                                                       AC100_RTC_32K_NAME,
 321                                                       NULL, 0,
 322                                                       AC100_RTC_32K_RATE);
 323        if (IS_ERR(chip->rtc_32k_clk)) {
 324                ret = PTR_ERR(chip->rtc_32k_clk);
 325                dev_err(chip->dev, "Failed to register RTC-32k clock: %d\n",
 326                        ret);
 327                return ret;
 328        }
 329
 330        parents[1] = of_clk_get_parent_name(np, 0);
 331        if (!parents[1]) {
 332                dev_err(chip->dev, "Failed to get ADDA 4M clock\n");
 333                return -EINVAL;
 334        }
 335
 336        for (i = 0; i < AC100_CLKOUT_NUM; i++) {
 337                struct ac100_clkout *clk = &chip->clks[i];
 338                struct clk_init_data init = {
 339                        .name = ac100_clkout_names[i],
 340                        .ops = &ac100_clkout_ops,
 341                        .parent_names = parents,
 342                        .num_parents = ARRAY_SIZE(parents),
 343                        .flags = 0,
 344                };
 345
 346                of_property_read_string_index(np, "clock-output-names",
 347                                              i, &init.name);
 348                clk->regmap = chip->regmap;
 349                clk->offset = AC100_CLKOUT_CTRL1 + i;
 350                clk->hw.init = &init;
 351
 352                ret = devm_clk_hw_register(chip->dev, &clk->hw);
 353                if (ret) {
 354                        dev_err(chip->dev, "Failed to register clk '%s': %d\n",
 355                                init.name, ret);
 356                        goto err_unregister_rtc_32k;
 357                }
 358
 359                chip->clk_data->hws[i] = &clk->hw;
 360        }
 361
 362        chip->clk_data->num = i;
 363        ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, chip->clk_data);
 364        if (ret)
 365                goto err_unregister_rtc_32k;
 366
 367        return 0;
 368
 369err_unregister_rtc_32k:
 370        clk_unregister_fixed_rate(chip->rtc_32k_clk->clk);
 371
 372        return ret;
 373}
 374
 375static void ac100_rtc_unregister_clks(struct ac100_rtc_dev *chip)
 376{
 377        of_clk_del_provider(chip->dev->of_node);
 378        clk_unregister_fixed_rate(chip->rtc_32k_clk->clk);
 379}
 380
 381/**
 382 * RTC related bits
 383 */
 384static int ac100_rtc_get_time(struct device *dev, struct rtc_time *rtc_tm)
 385{
 386        struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
 387        struct regmap *regmap = chip->regmap;
 388        u16 reg[7];
 389        int ret;
 390
 391        ret = regmap_bulk_read(regmap, AC100_RTC_SEC, reg, 7);
 392        if (ret)
 393                return ret;
 394
 395        rtc_tm->tm_sec  = bcd2bin(reg[0] & AC100_RTC_SEC_MASK);
 396        rtc_tm->tm_min  = bcd2bin(reg[1] & AC100_RTC_MIN_MASK);
 397        rtc_tm->tm_hour = bcd2bin(reg[2] & AC100_RTC_HOU_MASK);
 398        rtc_tm->tm_wday = bcd2bin(reg[3] & AC100_RTC_WEE_MASK);
 399        rtc_tm->tm_mday = bcd2bin(reg[4] & AC100_RTC_DAY_MASK);
 400        rtc_tm->tm_mon  = bcd2bin(reg[5] & AC100_RTC_MON_MASK) - 1;
 401        rtc_tm->tm_year = bcd2bin(reg[6] & AC100_RTC_YEA_MASK) +
 402                          AC100_YEAR_OFF;
 403
 404        return 0;
 405}
 406
 407static int ac100_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
 408{
 409        struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
 410        struct regmap *regmap = chip->regmap;
 411        int year;
 412        u16 reg[8];
 413
 414        /* our RTC has a limited year range... */
 415        year = rtc_tm->tm_year - AC100_YEAR_OFF;
 416        if (year < 0 || year > (AC100_YEAR_MAX - 1900)) {
 417                dev_err(dev, "rtc only supports year in range %d - %d\n",
 418                        AC100_YEAR_MIN, AC100_YEAR_MAX);
 419                return -EINVAL;
 420        }
 421
 422        /* convert to BCD */
 423        reg[0] = bin2bcd(rtc_tm->tm_sec)     & AC100_RTC_SEC_MASK;
 424        reg[1] = bin2bcd(rtc_tm->tm_min)     & AC100_RTC_MIN_MASK;
 425        reg[2] = bin2bcd(rtc_tm->tm_hour)    & AC100_RTC_HOU_MASK;
 426        reg[3] = bin2bcd(rtc_tm->tm_wday)    & AC100_RTC_WEE_MASK;
 427        reg[4] = bin2bcd(rtc_tm->tm_mday)    & AC100_RTC_DAY_MASK;
 428        reg[5] = bin2bcd(rtc_tm->tm_mon + 1) & AC100_RTC_MON_MASK;
 429        reg[6] = bin2bcd(year)               & AC100_RTC_YEA_MASK;
 430        /* trigger write */
 431        reg[7] = AC100_RTC_UPD_TRIGGER;
 432
 433        /* Is it a leap year? */
 434        if (is_leap_year(year + AC100_YEAR_OFF + 1900))
 435                reg[6] |= AC100_RTC_YEA_LEAP;
 436
 437        return regmap_bulk_write(regmap, AC100_RTC_SEC, reg, 8);
 438}
 439
 440static int ac100_rtc_alarm_irq_enable(struct device *dev, unsigned int en)
 441{
 442        struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
 443        struct regmap *regmap = chip->regmap;
 444        unsigned int val;
 445
 446        val = en ? AC100_ALM_INT_ENABLE : 0;
 447
 448        return regmap_write(regmap, AC100_ALM_INT_ENA, val);
 449}
 450
 451static int ac100_rtc_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 452{
 453        struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
 454        struct regmap *regmap = chip->regmap;
 455        struct rtc_time *alrm_tm = &alrm->time;
 456        u16 reg[7];
 457        unsigned int val;
 458        int ret;
 459
 460        ret = regmap_read(regmap, AC100_ALM_INT_ENA, &val);
 461        if (ret)
 462                return ret;
 463
 464        alrm->enabled = !!(val & AC100_ALM_INT_ENABLE);
 465
 466        ret = regmap_bulk_read(regmap, AC100_ALM_SEC, reg, 7);
 467        if (ret)
 468                return ret;
 469
 470        alrm_tm->tm_sec  = bcd2bin(reg[0] & AC100_ALM_SEC_MASK);
 471        alrm_tm->tm_min  = bcd2bin(reg[1] & AC100_ALM_MIN_MASK);
 472        alrm_tm->tm_hour = bcd2bin(reg[2] & AC100_ALM_HOU_MASK);
 473        alrm_tm->tm_wday = bcd2bin(reg[3] & AC100_ALM_WEE_MASK);
 474        alrm_tm->tm_mday = bcd2bin(reg[4] & AC100_ALM_DAY_MASK);
 475        alrm_tm->tm_mon  = bcd2bin(reg[5] & AC100_ALM_MON_MASK) - 1;
 476        alrm_tm->tm_year = bcd2bin(reg[6] & AC100_ALM_YEA_MASK) +
 477                           AC100_YEAR_OFF;
 478
 479        return 0;
 480}
 481
 482static int ac100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 483{
 484        struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
 485        struct regmap *regmap = chip->regmap;
 486        struct rtc_time *alrm_tm = &alrm->time;
 487        u16 reg[8];
 488        int year;
 489        int ret;
 490
 491        /* our alarm has a limited year range... */
 492        year = alrm_tm->tm_year - AC100_YEAR_OFF;
 493        if (year < 0 || year > (AC100_YEAR_MAX - 1900)) {
 494                dev_err(dev, "alarm only supports year in range %d - %d\n",
 495                        AC100_YEAR_MIN, AC100_YEAR_MAX);
 496                return -EINVAL;
 497        }
 498
 499        /* convert to BCD */
 500        reg[0] = (bin2bcd(alrm_tm->tm_sec)  & AC100_ALM_SEC_MASK) |
 501                        AC100_ALM_ENABLE_FLAG;
 502        reg[1] = (bin2bcd(alrm_tm->tm_min)  & AC100_ALM_MIN_MASK) |
 503                        AC100_ALM_ENABLE_FLAG;
 504        reg[2] = (bin2bcd(alrm_tm->tm_hour) & AC100_ALM_HOU_MASK) |
 505                        AC100_ALM_ENABLE_FLAG;
 506        /* Do not enable weekday alarm */
 507        reg[3] = bin2bcd(alrm_tm->tm_wday) & AC100_ALM_WEE_MASK;
 508        reg[4] = (bin2bcd(alrm_tm->tm_mday) & AC100_ALM_DAY_MASK) |
 509                        AC100_ALM_ENABLE_FLAG;
 510        reg[5] = (bin2bcd(alrm_tm->tm_mon + 1)  & AC100_ALM_MON_MASK) |
 511                        AC100_ALM_ENABLE_FLAG;
 512        reg[6] = (bin2bcd(year) & AC100_ALM_YEA_MASK) |
 513                        AC100_ALM_ENABLE_FLAG;
 514        /* trigger write */
 515        reg[7] = AC100_ALM_UPD_TRIGGER;
 516
 517        ret = regmap_bulk_write(regmap, AC100_ALM_SEC, reg, 8);
 518        if (ret)
 519                return ret;
 520
 521        return ac100_rtc_alarm_irq_enable(dev, alrm->enabled);
 522}
 523
 524static irqreturn_t ac100_rtc_irq(int irq, void *data)
 525{
 526        struct ac100_rtc_dev *chip = data;
 527        struct regmap *regmap = chip->regmap;
 528        unsigned int val = 0;
 529        int ret;
 530
 531        rtc_lock(chip->rtc);
 532
 533        /* read status */
 534        ret = regmap_read(regmap, AC100_ALM_INT_STA, &val);
 535        if (ret)
 536                goto out;
 537
 538        if (val & AC100_ALM_INT_ENABLE) {
 539                /* signal rtc framework */
 540                rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF);
 541
 542                /* clear status */
 543                ret = regmap_write(regmap, AC100_ALM_INT_STA, val);
 544                if (ret)
 545                        goto out;
 546
 547                /* disable interrupt */
 548                ret = ac100_rtc_alarm_irq_enable(chip->dev, 0);
 549                if (ret)
 550                        goto out;
 551        }
 552
 553out:
 554        rtc_unlock(chip->rtc);
 555        return IRQ_HANDLED;
 556}
 557
 558static const struct rtc_class_ops ac100_rtc_ops = {
 559        .read_time        = ac100_rtc_get_time,
 560        .set_time         = ac100_rtc_set_time,
 561        .read_alarm       = ac100_rtc_get_alarm,
 562        .set_alarm        = ac100_rtc_set_alarm,
 563        .alarm_irq_enable = ac100_rtc_alarm_irq_enable,
 564};
 565
 566static int ac100_rtc_probe(struct platform_device *pdev)
 567{
 568        struct ac100_dev *ac100 = dev_get_drvdata(pdev->dev.parent);
 569        struct ac100_rtc_dev *chip;
 570        int ret;
 571
 572        chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
 573        if (!chip)
 574                return -ENOMEM;
 575
 576        platform_set_drvdata(pdev, chip);
 577        chip->dev = &pdev->dev;
 578        chip->regmap = ac100->regmap;
 579
 580        chip->irq = platform_get_irq(pdev, 0);
 581        if (chip->irq < 0)
 582                return chip->irq;
 583
 584        chip->rtc = devm_rtc_allocate_device(&pdev->dev);
 585        if (IS_ERR(chip->rtc))
 586                return PTR_ERR(chip->rtc);
 587
 588        chip->rtc->ops = &ac100_rtc_ops;
 589
 590        ret = devm_request_threaded_irq(&pdev->dev, chip->irq, NULL,
 591                                        ac100_rtc_irq,
 592                                        IRQF_SHARED | IRQF_ONESHOT,
 593                                        dev_name(&pdev->dev), chip);
 594        if (ret) {
 595                dev_err(&pdev->dev, "Could not request IRQ\n");
 596                return ret;
 597        }
 598
 599        /* always use 24 hour mode */
 600        regmap_write_bits(chip->regmap, AC100_RTC_CTRL, AC100_RTC_CTRL_24HOUR,
 601                          AC100_RTC_CTRL_24HOUR);
 602
 603        /* disable counter alarm interrupt */
 604        regmap_write(chip->regmap, AC100_ALM_INT_ENA, 0);
 605
 606        /* clear counter alarm pending interrupts */
 607        regmap_write(chip->regmap, AC100_ALM_INT_STA, AC100_ALM_INT_ENABLE);
 608
 609        ret = ac100_rtc_register_clks(chip);
 610        if (ret)
 611                return ret;
 612
 613        return devm_rtc_register_device(chip->rtc);
 614}
 615
 616static int ac100_rtc_remove(struct platform_device *pdev)
 617{
 618        struct ac100_rtc_dev *chip = platform_get_drvdata(pdev);
 619
 620        ac100_rtc_unregister_clks(chip);
 621
 622        return 0;
 623}
 624
 625static const struct of_device_id ac100_rtc_match[] = {
 626        { .compatible = "x-powers,ac100-rtc" },
 627        { },
 628};
 629MODULE_DEVICE_TABLE(of, ac100_rtc_match);
 630
 631static struct platform_driver ac100_rtc_driver = {
 632        .probe          = ac100_rtc_probe,
 633        .remove         = ac100_rtc_remove,
 634        .driver         = {
 635                .name           = "ac100-rtc",
 636                .of_match_table = of_match_ptr(ac100_rtc_match),
 637        },
 638};
 639module_platform_driver(ac100_rtc_driver);
 640
 641MODULE_DESCRIPTION("X-Powers AC100 RTC driver");
 642MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
 643MODULE_LICENSE("GPL v2");
 644