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