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