Lines Matching +full:ac100 +full:- +full:codec

1 // SPDX-License-Identifier: GPL-2.0-only
3 * RTC Driver for X-Powers AC100
5 * Copyright (c) 2016 Chen-Yu Tsai
7 * Chen-Yu Tsai <wens@csie.org>
11 #include <linux/clk-provider.h>
15 #include <linux/mfd/ac100.h>
65 * The year range is 1970 - 2069. This range is selected to match Allwinner's
70 #define AC100_YEAR_OFF (AC100_YEAR_MIN - 1900)
80 #define AC100_RTC_32K_NAME "ac100-rtc-32k"
85 "ac100-cko1-rtc",
86 "ac100-cko2-rtc",
87 "ac100-cko3-rtc",
125 regmap_read(clk->regmap, clk->offset, &reg); in ac100_clkout_recalc_rate()
127 /* Handle pre-divider first */ in ac100_clkout_recalc_rate()
130 ((1 << AC100_CLKOUT_PRE_DIV_WIDTH) - 1); in ac100_clkout_recalc_rate()
137 (BIT(AC100_CLKOUT_DIV_WIDTH) - 1); in ac100_clkout_recalc_rate()
162 if (rate - tmp_rate < best_rate - tmp_rate) in ac100_clkout_round_rate()
182 * internally registered by the ac100 driver. The other parent in ac100_clkout_determine_rate()
183 * is a clock from the codec side of the chip, which we in ac100_clkout_determine_rate()
195 * without waiting for the codec to be supported. in ac100_clkout_determine_rate()
202 tmp = ac100_clkout_round_rate(hw, req->rate, prate); in ac100_clkout_determine_rate()
204 if (tmp > req->rate) in ac100_clkout_determine_rate()
206 if (req->rate - tmp < req->rate - best) { in ac100_clkout_determine_rate()
213 return -EINVAL; in ac100_clkout_determine_rate()
215 req->best_parent_hw = best_parent; in ac100_clkout_determine_rate()
216 req->best_parent_rate = best; in ac100_clkout_determine_rate()
217 req->rate = best; in ac100_clkout_determine_rate()
242 regmap_update_bits(clk->regmap, clk->offset, in ac100_clkout_set_rate()
243 ((1 << AC100_CLKOUT_DIV_WIDTH) - 1) << AC100_CLKOUT_DIV_SHIFT | in ac100_clkout_set_rate()
244 ((1 << AC100_CLKOUT_PRE_DIV_WIDTH) - 1) << AC100_CLKOUT_PRE_DIV_SHIFT, in ac100_clkout_set_rate()
245 (div - 1) << AC100_CLKOUT_DIV_SHIFT | in ac100_clkout_set_rate()
246 (pre_div - 1) << AC100_CLKOUT_PRE_DIV_SHIFT); in ac100_clkout_set_rate()
255 return regmap_update_bits(clk->regmap, clk->offset, AC100_CLKOUT_EN, in ac100_clkout_prepare()
263 regmap_update_bits(clk->regmap, clk->offset, AC100_CLKOUT_EN, 0); in ac100_clkout_unprepare()
271 regmap_read(clk->regmap, clk->offset, &reg); in ac100_clkout_is_prepared()
281 regmap_read(clk->regmap, clk->offset, &reg); in ac100_clkout_get_parent()
290 return regmap_update_bits(clk->regmap, clk->offset, in ac100_clkout_set_parent()
308 struct device_node *np = chip->dev->of_node; in ac100_rtc_register_clks()
312 chip->clk_data = devm_kzalloc(chip->dev, in ac100_rtc_register_clks()
313 struct_size(chip->clk_data, hws, in ac100_rtc_register_clks()
316 if (!chip->clk_data) in ac100_rtc_register_clks()
317 return -ENOMEM; in ac100_rtc_register_clks()
319 chip->rtc_32k_clk = clk_hw_register_fixed_rate(chip->dev, in ac100_rtc_register_clks()
323 if (IS_ERR(chip->rtc_32k_clk)) { in ac100_rtc_register_clks()
324 ret = PTR_ERR(chip->rtc_32k_clk); in ac100_rtc_register_clks()
325 dev_err(chip->dev, "Failed to register RTC-32k clock: %d\n", in ac100_rtc_register_clks()
332 dev_err(chip->dev, "Failed to get ADDA 4M clock\n"); in ac100_rtc_register_clks()
333 return -EINVAL; in ac100_rtc_register_clks()
337 struct ac100_clkout *clk = &chip->clks[i]; in ac100_rtc_register_clks()
346 of_property_read_string_index(np, "clock-output-names", in ac100_rtc_register_clks()
348 clk->regmap = chip->regmap; in ac100_rtc_register_clks()
349 clk->offset = AC100_CLKOUT_CTRL1 + i; in ac100_rtc_register_clks()
350 clk->hw.init = &init; in ac100_rtc_register_clks()
352 ret = devm_clk_hw_register(chip->dev, &clk->hw); in ac100_rtc_register_clks()
354 dev_err(chip->dev, "Failed to register clk '%s': %d\n", in ac100_rtc_register_clks()
359 chip->clk_data->hws[i] = &clk->hw; in ac100_rtc_register_clks()
362 chip->clk_data->num = i; in ac100_rtc_register_clks()
363 ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, chip->clk_data); in ac100_rtc_register_clks()
370 clk_unregister_fixed_rate(chip->rtc_32k_clk->clk); in ac100_rtc_register_clks()
377 of_clk_del_provider(chip->dev->of_node); in ac100_rtc_unregister_clks()
378 clk_unregister_fixed_rate(chip->rtc_32k_clk->clk); in ac100_rtc_unregister_clks()
387 struct regmap *regmap = chip->regmap; in ac100_rtc_get_time()
395 rtc_tm->tm_sec = bcd2bin(reg[0] & AC100_RTC_SEC_MASK); in ac100_rtc_get_time()
396 rtc_tm->tm_min = bcd2bin(reg[1] & AC100_RTC_MIN_MASK); in ac100_rtc_get_time()
397 rtc_tm->tm_hour = bcd2bin(reg[2] & AC100_RTC_HOU_MASK); in ac100_rtc_get_time()
398 rtc_tm->tm_wday = bcd2bin(reg[3] & AC100_RTC_WEE_MASK); in ac100_rtc_get_time()
399 rtc_tm->tm_mday = bcd2bin(reg[4] & AC100_RTC_DAY_MASK); in ac100_rtc_get_time()
400 rtc_tm->tm_mon = bcd2bin(reg[5] & AC100_RTC_MON_MASK) - 1; in ac100_rtc_get_time()
401 rtc_tm->tm_year = bcd2bin(reg[6] & AC100_RTC_YEA_MASK) + in ac100_rtc_get_time()
410 struct regmap *regmap = chip->regmap; in ac100_rtc_set_time()
415 year = rtc_tm->tm_year - AC100_YEAR_OFF; in ac100_rtc_set_time()
416 if (year < 0 || year > (AC100_YEAR_MAX - 1900)) { in ac100_rtc_set_time()
417 dev_err(dev, "rtc only supports year in range %d - %d\n", in ac100_rtc_set_time()
419 return -EINVAL; in ac100_rtc_set_time()
423 reg[0] = bin2bcd(rtc_tm->tm_sec) & AC100_RTC_SEC_MASK; in ac100_rtc_set_time()
424 reg[1] = bin2bcd(rtc_tm->tm_min) & AC100_RTC_MIN_MASK; in ac100_rtc_set_time()
425 reg[2] = bin2bcd(rtc_tm->tm_hour) & AC100_RTC_HOU_MASK; in ac100_rtc_set_time()
426 reg[3] = bin2bcd(rtc_tm->tm_wday) & AC100_RTC_WEE_MASK; in ac100_rtc_set_time()
427 reg[4] = bin2bcd(rtc_tm->tm_mday) & AC100_RTC_DAY_MASK; in ac100_rtc_set_time()
428 reg[5] = bin2bcd(rtc_tm->tm_mon + 1) & AC100_RTC_MON_MASK; in ac100_rtc_set_time()
443 struct regmap *regmap = chip->regmap; in ac100_rtc_alarm_irq_enable()
454 struct regmap *regmap = chip->regmap; in ac100_rtc_get_alarm()
455 struct rtc_time *alrm_tm = &alrm->time; in ac100_rtc_get_alarm()
464 alrm->enabled = !!(val & AC100_ALM_INT_ENABLE); in ac100_rtc_get_alarm()
470 alrm_tm->tm_sec = bcd2bin(reg[0] & AC100_ALM_SEC_MASK); in ac100_rtc_get_alarm()
471 alrm_tm->tm_min = bcd2bin(reg[1] & AC100_ALM_MIN_MASK); in ac100_rtc_get_alarm()
472 alrm_tm->tm_hour = bcd2bin(reg[2] & AC100_ALM_HOU_MASK); in ac100_rtc_get_alarm()
473 alrm_tm->tm_wday = bcd2bin(reg[3] & AC100_ALM_WEE_MASK); in ac100_rtc_get_alarm()
474 alrm_tm->tm_mday = bcd2bin(reg[4] & AC100_ALM_DAY_MASK); in ac100_rtc_get_alarm()
475 alrm_tm->tm_mon = bcd2bin(reg[5] & AC100_ALM_MON_MASK) - 1; in ac100_rtc_get_alarm()
476 alrm_tm->tm_year = bcd2bin(reg[6] & AC100_ALM_YEA_MASK) + in ac100_rtc_get_alarm()
485 struct regmap *regmap = chip->regmap; in ac100_rtc_set_alarm()
486 struct rtc_time *alrm_tm = &alrm->time; in ac100_rtc_set_alarm()
492 year = alrm_tm->tm_year - AC100_YEAR_OFF; in ac100_rtc_set_alarm()
493 if (year < 0 || year > (AC100_YEAR_MAX - 1900)) { in ac100_rtc_set_alarm()
494 dev_err(dev, "alarm only supports year in range %d - %d\n", in ac100_rtc_set_alarm()
496 return -EINVAL; in ac100_rtc_set_alarm()
500 reg[0] = (bin2bcd(alrm_tm->tm_sec) & AC100_ALM_SEC_MASK) | in ac100_rtc_set_alarm()
502 reg[1] = (bin2bcd(alrm_tm->tm_min) & AC100_ALM_MIN_MASK) | in ac100_rtc_set_alarm()
504 reg[2] = (bin2bcd(alrm_tm->tm_hour) & AC100_ALM_HOU_MASK) | in ac100_rtc_set_alarm()
507 reg[3] = bin2bcd(alrm_tm->tm_wday) & AC100_ALM_WEE_MASK; in ac100_rtc_set_alarm()
508 reg[4] = (bin2bcd(alrm_tm->tm_mday) & AC100_ALM_DAY_MASK) | in ac100_rtc_set_alarm()
510 reg[5] = (bin2bcd(alrm_tm->tm_mon + 1) & AC100_ALM_MON_MASK) | in ac100_rtc_set_alarm()
521 return ac100_rtc_alarm_irq_enable(dev, alrm->enabled); in ac100_rtc_set_alarm()
527 struct regmap *regmap = chip->regmap; in ac100_rtc_irq()
531 rtc_lock(chip->rtc); in ac100_rtc_irq()
540 rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF); in ac100_rtc_irq()
548 ret = ac100_rtc_alarm_irq_enable(chip->dev, 0); in ac100_rtc_irq()
554 rtc_unlock(chip->rtc); in ac100_rtc_irq()
568 struct ac100_dev *ac100 = dev_get_drvdata(pdev->dev.parent); in ac100_rtc_probe() local
572 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); in ac100_rtc_probe()
574 return -ENOMEM; in ac100_rtc_probe()
577 chip->dev = &pdev->dev; in ac100_rtc_probe()
578 chip->regmap = ac100->regmap; in ac100_rtc_probe()
580 chip->irq = platform_get_irq(pdev, 0); in ac100_rtc_probe()
581 if (chip->irq < 0) in ac100_rtc_probe()
582 return chip->irq; in ac100_rtc_probe()
584 chip->rtc = devm_rtc_allocate_device(&pdev->dev); in ac100_rtc_probe()
585 if (IS_ERR(chip->rtc)) in ac100_rtc_probe()
586 return PTR_ERR(chip->rtc); in ac100_rtc_probe()
588 chip->rtc->ops = &ac100_rtc_ops; in ac100_rtc_probe()
590 ret = devm_request_threaded_irq(&pdev->dev, chip->irq, NULL, in ac100_rtc_probe()
593 dev_name(&pdev->dev), chip); in ac100_rtc_probe()
595 dev_err(&pdev->dev, "Could not request IRQ\n"); in ac100_rtc_probe()
600 regmap_write_bits(chip->regmap, AC100_RTC_CTRL, AC100_RTC_CTRL_24HOUR, in ac100_rtc_probe()
604 regmap_write(chip->regmap, AC100_ALM_INT_ENA, 0); in ac100_rtc_probe()
607 regmap_write(chip->regmap, AC100_ALM_INT_STA, AC100_ALM_INT_ENABLE); in ac100_rtc_probe()
613 return devm_rtc_register_device(chip->rtc); in ac100_rtc_probe()
624 { .compatible = "x-powers,ac100-rtc" },
633 .name = "ac100-rtc",
639 MODULE_DESCRIPTION("X-Powers AC100 RTC driver");
640 MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");