^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * STM32 Low-Power Timer parent driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) STMicroelectronics 2017
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Inspired by Benjamin Gaignard's stm32-timers driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/mfd/stm32-lptimer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define STM32_LPTIM_MAX_REGISTER 0x3fc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) static const struct regmap_config stm32_lptimer_regmap_cfg = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) .reg_bits = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) .val_bits = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) .reg_stride = sizeof(u32),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) .max_register = STM32_LPTIM_MAX_REGISTER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) .fast_io = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static int stm32_lptimer_detect_encoder(struct stm32_lptimer *ddata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * Quadrature encoder mode bit can only be written and read back when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * Low-Power Timer supports it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) ret = regmap_update_bits(ddata->regmap, STM32_LPTIM_CFGR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) STM32_LPTIM_ENC, STM32_LPTIM_ENC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) ret = regmap_read(ddata->regmap, STM32_LPTIM_CFGR, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) ret = regmap_update_bits(ddata->regmap, STM32_LPTIM_CFGR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) STM32_LPTIM_ENC, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) ddata->has_encoder = !!(val & STM32_LPTIM_ENC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static int stm32_lptimer_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct stm32_lptimer *ddata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) void __iomem *mmio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (!ddata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) mmio = devm_ioremap_resource(dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (IS_ERR(mmio))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return PTR_ERR(mmio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) ddata->regmap = devm_regmap_init_mmio_clk(dev, "mux", mmio,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) &stm32_lptimer_regmap_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (IS_ERR(ddata->regmap))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return PTR_ERR(ddata->regmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) ddata->clk = devm_clk_get(dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (IS_ERR(ddata->clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return PTR_ERR(ddata->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) ret = stm32_lptimer_detect_encoder(ddata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) platform_set_drvdata(pdev, ddata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return devm_of_platform_populate(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static const struct of_device_id stm32_lptimer_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) { .compatible = "st,stm32-lptimer", },
^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) MODULE_DEVICE_TABLE(of, stm32_lptimer_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static struct platform_driver stm32_lptimer_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) .probe = stm32_lptimer_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .name = "stm32-lptimer",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) .of_match_table = stm32_lptimer_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) module_platform_driver(stm32_lptimer_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) MODULE_DESCRIPTION("STMicroelectronics STM32 Low-Power Timer");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) MODULE_ALIAS("platform:stm32-lptimer");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) MODULE_LICENSE("GPL v2");