uboot/drivers/rtc/ht1380.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Holtek HT1380/HT1381 Serial Timekeeper Chip
   4 *
   5 * Communication with the chip is vendor-specific.
   6 * It is done via 3 GPIO pins: reset, clock, and data.
   7 * Describe in .dts this way:
   8 *
   9 * rtc {
  10 *         compatible = "holtek,ht1380";
  11 *         rst-gpios = <&gpio 19 GPIO_ACTIVE_LOW>;
  12 *         clk-gpios = <&gpio 20 GPIO_ACTIVE_HIGH>;
  13 *         dat-gpios = <&gpio 21 GPIO_ACTIVE_HIGH>;
  14 * };
  15 *
  16 */
  17
  18#include <common.h>
  19#include <dm.h>
  20#include <rtc.h>
  21#include <bcd.h>
  22#include <asm/gpio.h>
  23#include <linux/delay.h>
  24
  25struct ht1380_priv {
  26        struct gpio_desc rst_desc;
  27        struct gpio_desc clk_desc;
  28        struct gpio_desc dat_desc;
  29};
  30
  31enum registers {
  32        SEC,
  33        MIN,
  34        HOUR,
  35        MDAY,
  36        MONTH,
  37        WDAY,
  38        YEAR,
  39        WP,
  40        N_REGS
  41};
  42
  43enum hour_mode {
  44        AMPM_MODE = 0x80, /* RTC is in AM/PM mode */
  45        PM_NOW = 0x20,    /* set if PM, clear if AM */
  46};
  47
  48static const int BURST = 0xbe;
  49static const int READ = 1;
  50
  51static void ht1380_half_period_delay(void)
  52{
  53        /*
  54         * Delay for half a period. 1 us complies with the 500 KHz maximum
  55         * input serial clock limit given by the datasheet.
  56         */
  57        udelay(1);
  58}
  59
  60static int ht1380_send_byte(struct ht1380_priv *priv, int byte)
  61{
  62        int ret;
  63
  64        for (int bit = 0; bit < 8; bit++) {
  65                ret = dm_gpio_set_value(&priv->dat_desc, byte >> bit & 1);
  66                if (ret)
  67                        break;
  68                ht1380_half_period_delay();
  69
  70                ret = dm_gpio_set_value(&priv->clk_desc, 1);
  71                if (ret)
  72                        break;
  73                ht1380_half_period_delay();
  74
  75                ret = dm_gpio_set_value(&priv->clk_desc, 0);
  76                if (ret)
  77                        break;
  78        }
  79
  80        return ret;
  81}
  82
  83/*
  84 * Leave reset state. The transfer operation can then be started.
  85 */
  86static int ht1380_reset_off(struct ht1380_priv *priv)
  87{
  88        const unsigned int T_CC = 4; /* us, Reset to Clock Setup */
  89        int ret;
  90
  91        /*
  92         * Leave RESET state.
  93         * Make sure we make the minimal delay required by the datasheet.
  94         */
  95        ret = dm_gpio_set_value(&priv->rst_desc, 0);
  96        udelay(T_CC);
  97
  98        return ret;
  99}
 100
 101/*
 102 * Enter reset state. Completes the transfer operation.
 103 */
 104static int ht1380_reset_on(struct ht1380_priv *priv)
 105{
 106        const unsigned int T_CWH = 4; /* us, Reset Inactive Time */
 107        int ret;
 108
 109        /*
 110         * Enter RESET state.
 111         * Make sure we make the minimal delay required by the datasheet.
 112         */
 113        ret = dm_gpio_set_value(&priv->rst_desc, 1);
 114        udelay(T_CWH);
 115
 116        return ret;
 117}
 118
 119static int ht1380_rtc_get(struct udevice *dev, struct rtc_time *tm)
 120{
 121        struct ht1380_priv *priv = dev_get_priv(dev);
 122        int ret, i, bit, reg[N_REGS];
 123
 124        ret = dm_gpio_set_value(&priv->clk_desc, 0);
 125        if (ret)
 126                return ret;
 127
 128        ret = dm_gpio_set_dir_flags(&priv->dat_desc, GPIOD_IS_OUT);
 129        if (ret)
 130                return ret;
 131
 132        ret = ht1380_reset_off(priv);
 133        if (ret)
 134                goto exit;
 135
 136        ret = ht1380_send_byte(priv, BURST + READ);
 137        if (ret)
 138                goto exit;
 139
 140        ret = dm_gpio_set_dir_flags(&priv->dat_desc, GPIOD_IS_IN);
 141        if (ret)
 142                goto exit;
 143
 144        for (i = 0; i < N_REGS; i++) {
 145                reg[i] = 0;
 146
 147                for (bit = 0; bit < 8; bit++) {
 148                        ht1380_half_period_delay();
 149
 150                        ret = dm_gpio_set_value(&priv->clk_desc, 1);
 151                        if (ret)
 152                                goto exit;
 153                        ht1380_half_period_delay();
 154
 155                        reg[i] |= dm_gpio_get_value(&priv->dat_desc) << bit;
 156                        ret = dm_gpio_set_value(&priv->clk_desc, 0);
 157                        if (ret)
 158                                goto exit;
 159                }
 160        }
 161
 162        ret = -EINVAL;
 163
 164        /* Correctness check: some bits are always zero */
 165        if (reg[MIN] & 0x80 || reg[HOUR] & 0x40 || reg[MDAY] & 0xc0 ||
 166            reg[MONTH] & 0xe0 || reg[WDAY] & 0xf8 || reg[WP] & 0x7f)
 167                goto exit;
 168
 169        /* Correctness check: some registers are always non-zero */
 170        if (!reg[MDAY] || !reg[MONTH] || !reg[WDAY])
 171                goto exit;
 172
 173        tm->tm_sec = bcd2bin(reg[SEC]);
 174        tm->tm_min = bcd2bin(reg[MIN]);
 175        if (reg[HOUR] & AMPM_MODE) {
 176                /* AM-PM Mode, range is 01-12 */
 177                tm->tm_hour = bcd2bin(reg[HOUR] & 0x1f) % 12;
 178                if (reg[HOUR] & PM_NOW) {
 179                        /* it is PM (otherwise AM) */
 180                        tm->tm_hour += 12;
 181                }
 182        } else {
 183                /* 24-hour Mode, range is 0-23 */
 184                tm->tm_hour = bcd2bin(reg[HOUR]);
 185        }
 186        tm->tm_mday = bcd2bin(reg[MDAY]);
 187        tm->tm_mon = bcd2bin(reg[MONTH]);
 188        tm->tm_year = 2000 + bcd2bin(reg[YEAR]);
 189        tm->tm_wday = bcd2bin(reg[WDAY]) - 1;
 190        tm->tm_yday = 0;
 191        tm->tm_isdst = 0;
 192
 193        ret = 0;
 194
 195exit:
 196        ht1380_reset_on(priv);
 197
 198        return ret;
 199}
 200
 201static int ht1380_write_protection_off(struct ht1380_priv *priv)
 202{
 203        int ret;
 204        const int PROTECT = 0x8e;
 205
 206        ret = ht1380_reset_off(priv);
 207        if (ret)
 208                return ret;
 209
 210        ret = ht1380_send_byte(priv, PROTECT);
 211        if (ret)
 212                return ret;
 213        ret = ht1380_send_byte(priv, 0); /* WP bit is 0 */
 214        if (ret)
 215                return ret;
 216
 217        return ht1380_reset_on(priv);
 218}
 219
 220static int ht1380_rtc_set(struct udevice *dev, const struct rtc_time *tm)
 221{
 222        struct ht1380_priv *priv = dev_get_priv(dev);
 223        int ret, i, reg[N_REGS];
 224
 225        ret = dm_gpio_set_value(&priv->clk_desc, 0);
 226        if (ret)
 227                return ret;
 228
 229        ret = dm_gpio_set_dir_flags(&priv->dat_desc, GPIOD_IS_OUT);
 230        if (ret)
 231                goto exit;
 232
 233        ret = ht1380_write_protection_off(priv);
 234        if (ret)
 235                goto exit;
 236
 237        reg[SEC] = bin2bcd(tm->tm_sec);
 238        reg[MIN] = bin2bcd(tm->tm_min);
 239        reg[HOUR] = bin2bcd(tm->tm_hour);
 240        reg[MDAY] = bin2bcd(tm->tm_mday);
 241        reg[MONTH] = bin2bcd(tm->tm_mon);
 242        reg[WDAY] = bin2bcd(tm->tm_wday) + 1;
 243        reg[YEAR] = bin2bcd(tm->tm_year - 2000);
 244        reg[WP] = 0x80; /* WP bit is 1 */
 245
 246        ret = ht1380_reset_off(priv);
 247        if (ret)
 248                goto exit;
 249
 250        ret = ht1380_send_byte(priv, BURST);
 251        for (i = 0; i < N_REGS && ret; i++)
 252                ret = ht1380_send_byte(priv, reg[i]);
 253
 254exit:
 255        ht1380_reset_on(priv);
 256
 257        return ret;
 258}
 259
 260static int ht1380_probe(struct udevice *dev)
 261{
 262        int ret;
 263        struct ht1380_priv *priv;
 264
 265        priv = dev_get_priv(dev);
 266        if (!priv)
 267                return -EINVAL;
 268
 269        ret = gpio_request_by_name(dev, "rst-gpios", 0,
 270                                   &priv->rst_desc, GPIOD_IS_OUT);
 271        if (ret)
 272                goto fail_rst;
 273
 274        ret = gpio_request_by_name(dev, "clk-gpios", 0,
 275                                   &priv->clk_desc, GPIOD_IS_OUT);
 276        if (ret)
 277                goto fail_clk;
 278
 279        ret = gpio_request_by_name(dev, "dat-gpios", 0,
 280                                   &priv->dat_desc, 0);
 281        if (ret)
 282                goto fail_dat;
 283
 284        ret = ht1380_reset_on(priv);
 285        if (ret)
 286                goto fail;
 287
 288        return 0;
 289
 290fail:
 291        dm_gpio_free(dev, &priv->dat_desc);
 292fail_dat:
 293        dm_gpio_free(dev, &priv->clk_desc);
 294fail_clk:
 295        dm_gpio_free(dev, &priv->rst_desc);
 296fail_rst:
 297        return ret;
 298}
 299
 300static int ht1380_remove(struct udevice *dev)
 301{
 302        struct ht1380_priv *priv = dev_get_priv(dev);
 303
 304        dm_gpio_free(dev, &priv->rst_desc);
 305        dm_gpio_free(dev, &priv->clk_desc);
 306        dm_gpio_free(dev, &priv->dat_desc);
 307
 308        return 0;
 309}
 310
 311static const struct rtc_ops ht1380_rtc_ops = {
 312        .get = ht1380_rtc_get,
 313        .set = ht1380_rtc_set,
 314};
 315
 316static const struct udevice_id ht1380_rtc_ids[] = {
 317        { .compatible = "holtek,ht1380" },
 318        { }
 319};
 320
 321U_BOOT_DRIVER(rtc_ht1380) = {
 322        .name = "rtc-ht1380",
 323        .id = UCLASS_RTC,
 324        .probe = ht1380_probe,
 325        .remove = ht1380_remove,
 326        .of_match = ht1380_rtc_ids,
 327        .ops = &ht1380_rtc_ops,
 328        .priv_auto = sizeof(struct ht1380_priv),
 329};
 330