Lines Matching +full:convert +full:- +full:rate
2 * RTC Driver for X-Powers AC100
4 * Copyright (c) 2016 Chen-Yu Tsai
6 * Chen-Yu Tsai <wens@csie.org>
19 #include <linux/clk-provider.h>
70 * the year 1900. This macro is used to convert this offset to another one
73 * The year range is 1970 - 2069. This range is selected to match Allwinner's
78 #define AC100_YEAR_OFF (AC100_YEAR_MIN - 1900)
88 #define AC100_RTC_32K_NAME "ac100-rtc-32k"
93 "ac100-cko1-rtc",
94 "ac100-cko2-rtc",
95 "ac100-cko3-rtc",
133 regmap_read(clk->regmap, clk->offset, ®); in ac100_clkout_recalc_rate()
135 /* Handle pre-divider first */ in ac100_clkout_recalc_rate()
138 ((1 << AC100_CLKOUT_PRE_DIV_WIDTH) - 1); in ac100_clkout_recalc_rate()
145 (BIT(AC100_CLKOUT_DIV_WIDTH) - 1); in ac100_clkout_recalc_rate()
151 static long ac100_clkout_round_rate(struct clk_hw *hw, unsigned long rate, in ac100_clkout_round_rate() argument
158 return divider_round_rate(hw, rate, &prate, NULL, in ac100_clkout_round_rate()
164 tmp_rate = divider_round_rate(hw, rate, &tmp_prate, NULL, in ac100_clkout_round_rate()
168 if (tmp_rate > rate) in ac100_clkout_round_rate()
170 if (rate - tmp_rate < best_rate - tmp_rate) in ac100_clkout_round_rate()
202 * we get the parent rate, so we could use the RTC in ac100_clkout_determine_rate()
210 tmp = ac100_clkout_round_rate(hw, req->rate, prate); in ac100_clkout_determine_rate()
212 if (tmp > req->rate) in ac100_clkout_determine_rate()
214 if (req->rate - tmp < req->rate - best) { in ac100_clkout_determine_rate()
221 return -EINVAL; in ac100_clkout_determine_rate()
223 req->best_parent_hw = best_parent; in ac100_clkout_determine_rate()
224 req->best_parent_rate = best; in ac100_clkout_determine_rate()
225 req->rate = best; in ac100_clkout_determine_rate()
230 static int ac100_clkout_set_rate(struct clk_hw *hw, unsigned long rate, in ac100_clkout_set_rate() argument
237 div = divider_get_val(rate * ac100_clkout_prediv[pre_div].div, in ac100_clkout_set_rate()
250 regmap_update_bits(clk->regmap, clk->offset, in ac100_clkout_set_rate()
251 ((1 << AC100_CLKOUT_DIV_WIDTH) - 1) << AC100_CLKOUT_DIV_SHIFT | in ac100_clkout_set_rate()
252 ((1 << AC100_CLKOUT_PRE_DIV_WIDTH) - 1) << AC100_CLKOUT_PRE_DIV_SHIFT, in ac100_clkout_set_rate()
253 (div - 1) << AC100_CLKOUT_DIV_SHIFT | in ac100_clkout_set_rate()
254 (pre_div - 1) << AC100_CLKOUT_PRE_DIV_SHIFT); in ac100_clkout_set_rate()
263 return regmap_update_bits(clk->regmap, clk->offset, AC100_CLKOUT_EN, in ac100_clkout_prepare()
271 regmap_update_bits(clk->regmap, clk->offset, AC100_CLKOUT_EN, 0); in ac100_clkout_unprepare()
279 regmap_read(clk->regmap, clk->offset, ®); in ac100_clkout_is_prepared()
289 regmap_read(clk->regmap, clk->offset, ®); in ac100_clkout_get_parent()
298 return regmap_update_bits(clk->regmap, clk->offset, in ac100_clkout_set_parent()
316 struct device_node *np = chip->dev->of_node; in ac100_rtc_register_clks()
320 chip->clk_data = devm_kzalloc(chip->dev, in ac100_rtc_register_clks()
321 struct_size(chip->clk_data, hws, in ac100_rtc_register_clks()
324 if (!chip->clk_data) in ac100_rtc_register_clks()
325 return -ENOMEM; in ac100_rtc_register_clks()
327 chip->rtc_32k_clk = clk_hw_register_fixed_rate(chip->dev, in ac100_rtc_register_clks()
331 if (IS_ERR(chip->rtc_32k_clk)) { in ac100_rtc_register_clks()
332 ret = PTR_ERR(chip->rtc_32k_clk); in ac100_rtc_register_clks()
333 dev_err(chip->dev, "Failed to register RTC-32k clock: %d\n", in ac100_rtc_register_clks()
340 dev_err(chip->dev, "Failed to get ADDA 4M clock\n"); in ac100_rtc_register_clks()
341 return -EINVAL; in ac100_rtc_register_clks()
345 struct ac100_clkout *clk = &chip->clks[i]; in ac100_rtc_register_clks()
354 of_property_read_string_index(np, "clock-output-names", in ac100_rtc_register_clks()
356 clk->regmap = chip->regmap; in ac100_rtc_register_clks()
357 clk->offset = AC100_CLKOUT_CTRL1 + i; in ac100_rtc_register_clks()
358 clk->hw.init = &init; in ac100_rtc_register_clks()
360 ret = devm_clk_hw_register(chip->dev, &clk->hw); in ac100_rtc_register_clks()
362 dev_err(chip->dev, "Failed to register clk '%s': %d\n", in ac100_rtc_register_clks()
367 chip->clk_data->hws[i] = &clk->hw; in ac100_rtc_register_clks()
370 chip->clk_data->num = i; in ac100_rtc_register_clks()
371 ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, chip->clk_data); in ac100_rtc_register_clks()
378 clk_unregister_fixed_rate(chip->rtc_32k_clk->clk); in ac100_rtc_register_clks()
385 of_clk_del_provider(chip->dev->of_node); in ac100_rtc_unregister_clks()
386 clk_unregister_fixed_rate(chip->rtc_32k_clk->clk); in ac100_rtc_unregister_clks()
395 struct regmap *regmap = chip->regmap; in ac100_rtc_get_time()
403 rtc_tm->tm_sec = bcd2bin(reg[0] & AC100_RTC_SEC_MASK); in ac100_rtc_get_time()
404 rtc_tm->tm_min = bcd2bin(reg[1] & AC100_RTC_MIN_MASK); in ac100_rtc_get_time()
405 rtc_tm->tm_hour = bcd2bin(reg[2] & AC100_RTC_HOU_MASK); in ac100_rtc_get_time()
406 rtc_tm->tm_wday = bcd2bin(reg[3] & AC100_RTC_WEE_MASK); in ac100_rtc_get_time()
407 rtc_tm->tm_mday = bcd2bin(reg[4] & AC100_RTC_DAY_MASK); in ac100_rtc_get_time()
408 rtc_tm->tm_mon = bcd2bin(reg[5] & AC100_RTC_MON_MASK) - 1; in ac100_rtc_get_time()
409 rtc_tm->tm_year = bcd2bin(reg[6] & AC100_RTC_YEA_MASK) + in ac100_rtc_get_time()
418 struct regmap *regmap = chip->regmap; in ac100_rtc_set_time()
423 year = rtc_tm->tm_year - AC100_YEAR_OFF; in ac100_rtc_set_time()
424 if (year < 0 || year > (AC100_YEAR_MAX - 1900)) { in ac100_rtc_set_time()
425 dev_err(dev, "rtc only supports year in range %d - %d\n", in ac100_rtc_set_time()
427 return -EINVAL; in ac100_rtc_set_time()
430 /* convert to BCD */ in ac100_rtc_set_time()
431 reg[0] = bin2bcd(rtc_tm->tm_sec) & AC100_RTC_SEC_MASK; in ac100_rtc_set_time()
432 reg[1] = bin2bcd(rtc_tm->tm_min) & AC100_RTC_MIN_MASK; in ac100_rtc_set_time()
433 reg[2] = bin2bcd(rtc_tm->tm_hour) & AC100_RTC_HOU_MASK; in ac100_rtc_set_time()
434 reg[3] = bin2bcd(rtc_tm->tm_wday) & AC100_RTC_WEE_MASK; in ac100_rtc_set_time()
435 reg[4] = bin2bcd(rtc_tm->tm_mday) & AC100_RTC_DAY_MASK; in ac100_rtc_set_time()
436 reg[5] = bin2bcd(rtc_tm->tm_mon + 1) & AC100_RTC_MON_MASK; in ac100_rtc_set_time()
451 struct regmap *regmap = chip->regmap; in ac100_rtc_alarm_irq_enable()
462 struct regmap *regmap = chip->regmap; in ac100_rtc_get_alarm()
463 struct rtc_time *alrm_tm = &alrm->time; in ac100_rtc_get_alarm()
472 alrm->enabled = !!(val & AC100_ALM_INT_ENABLE); in ac100_rtc_get_alarm()
478 alrm_tm->tm_sec = bcd2bin(reg[0] & AC100_ALM_SEC_MASK); in ac100_rtc_get_alarm()
479 alrm_tm->tm_min = bcd2bin(reg[1] & AC100_ALM_MIN_MASK); in ac100_rtc_get_alarm()
480 alrm_tm->tm_hour = bcd2bin(reg[2] & AC100_ALM_HOU_MASK); in ac100_rtc_get_alarm()
481 alrm_tm->tm_wday = bcd2bin(reg[3] & AC100_ALM_WEE_MASK); in ac100_rtc_get_alarm()
482 alrm_tm->tm_mday = bcd2bin(reg[4] & AC100_ALM_DAY_MASK); in ac100_rtc_get_alarm()
483 alrm_tm->tm_mon = bcd2bin(reg[5] & AC100_ALM_MON_MASK) - 1; in ac100_rtc_get_alarm()
484 alrm_tm->tm_year = bcd2bin(reg[6] & AC100_ALM_YEA_MASK) + in ac100_rtc_get_alarm()
493 struct regmap *regmap = chip->regmap; in ac100_rtc_set_alarm()
494 struct rtc_time *alrm_tm = &alrm->time; in ac100_rtc_set_alarm()
500 year = alrm_tm->tm_year - AC100_YEAR_OFF; in ac100_rtc_set_alarm()
501 if (year < 0 || year > (AC100_YEAR_MAX - 1900)) { in ac100_rtc_set_alarm()
502 dev_err(dev, "alarm only supports year in range %d - %d\n", in ac100_rtc_set_alarm()
504 return -EINVAL; in ac100_rtc_set_alarm()
507 /* convert to BCD */ in ac100_rtc_set_alarm()
508 reg[0] = (bin2bcd(alrm_tm->tm_sec) & AC100_ALM_SEC_MASK) | in ac100_rtc_set_alarm()
510 reg[1] = (bin2bcd(alrm_tm->tm_min) & AC100_ALM_MIN_MASK) | in ac100_rtc_set_alarm()
512 reg[2] = (bin2bcd(alrm_tm->tm_hour) & AC100_ALM_HOU_MASK) | in ac100_rtc_set_alarm()
515 reg[3] = bin2bcd(alrm_tm->tm_wday) & AC100_ALM_WEE_MASK; in ac100_rtc_set_alarm()
516 reg[4] = (bin2bcd(alrm_tm->tm_mday) & AC100_ALM_DAY_MASK) | in ac100_rtc_set_alarm()
518 reg[5] = (bin2bcd(alrm_tm->tm_mon + 1) & AC100_ALM_MON_MASK) | in ac100_rtc_set_alarm()
529 return ac100_rtc_alarm_irq_enable(dev, alrm->enabled); in ac100_rtc_set_alarm()
535 struct regmap *regmap = chip->regmap; in ac100_rtc_irq()
539 mutex_lock(&chip->rtc->ops_lock); in ac100_rtc_irq()
548 rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF); in ac100_rtc_irq()
556 ret = ac100_rtc_alarm_irq_enable(chip->dev, 0); in ac100_rtc_irq()
562 mutex_unlock(&chip->rtc->ops_lock); in ac100_rtc_irq()
576 struct ac100_dev *ac100 = dev_get_drvdata(pdev->dev.parent); in ac100_rtc_probe()
580 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); in ac100_rtc_probe()
582 return -ENOMEM; in ac100_rtc_probe()
585 chip->dev = &pdev->dev; in ac100_rtc_probe()
586 chip->regmap = ac100->regmap; in ac100_rtc_probe()
588 chip->irq = platform_get_irq(pdev, 0); in ac100_rtc_probe()
589 if (chip->irq < 0) { in ac100_rtc_probe()
590 dev_err(&pdev->dev, "No IRQ resource\n"); in ac100_rtc_probe()
591 return chip->irq; in ac100_rtc_probe()
594 chip->rtc = devm_rtc_allocate_device(&pdev->dev); in ac100_rtc_probe()
595 if (IS_ERR(chip->rtc)) in ac100_rtc_probe()
596 return PTR_ERR(chip->rtc); in ac100_rtc_probe()
598 chip->rtc->ops = &ac100_rtc_ops; in ac100_rtc_probe()
600 ret = devm_request_threaded_irq(&pdev->dev, chip->irq, NULL, in ac100_rtc_probe()
603 dev_name(&pdev->dev), chip); in ac100_rtc_probe()
605 dev_err(&pdev->dev, "Could not request IRQ\n"); in ac100_rtc_probe()
610 regmap_write_bits(chip->regmap, AC100_RTC_CTRL, AC100_RTC_CTRL_24HOUR, in ac100_rtc_probe()
614 regmap_write(chip->regmap, AC100_ALM_INT_ENA, 0); in ac100_rtc_probe()
617 regmap_write(chip->regmap, AC100_ALM_INT_STA, AC100_ALM_INT_ENABLE); in ac100_rtc_probe()
623 ret = rtc_register_device(chip->rtc); in ac100_rtc_probe()
625 dev_err(&pdev->dev, "unable to register device\n"); in ac100_rtc_probe()
629 dev_info(&pdev->dev, "RTC enabled\n"); in ac100_rtc_probe()
644 { .compatible = "x-powers,ac100-rtc" },
653 .name = "ac100-rtc",
659 MODULE_DESCRIPTION("X-Powers AC100 RTC driver");
660 MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");