/* * Copyright (C) 2018 SiFive, Inc * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2, as published by * the Free Software Foundation. */ #include #include #include #include #include #include #include #include /* max channel of pwm */ #define MAX_PWM 8 /* PTC Register offsets */ #define REG_RPTC_CNTR 0x0 #define REG_RPTC_HRC 0x4 #define REG_RPTC_LRC 0x8 #define REG_RPTC_CTRL 0xC /* Bit for PWM clock */ #define BIT_PWM_CLOCK_EN 31 /* Bit for clock gen soft reset */ #define BIT_CLK_GEN_SOFT_RESET 13 #define NS_1 1000000000U /* Access PTC register (cntr hrc lrc and ctrl), need to replace PWM_BASE_ADDR */ #define REG_PTC_BASE_ADDR_SUB(base, N) \ ((base) + (((N) > 3) ? (((N) - 4) * 0x10 + (1 << 15)) : ((N) * 0x10))) #define REG_PTC_RPTC_CNTR(base, N) (REG_PTC_BASE_ADDR_SUB(base, N)) #define REG_PTC_RPTC_HRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x4) #define REG_PTC_RPTC_LRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x8) #define REG_PTC_RPTC_CTRL(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0xC) /* pwm ptc device */ struct sifive_pwm_ptc_device { struct pwm_chip chip; struct clk *clk; void __iomem *regs; }; static inline struct sifive_pwm_ptc_device *chip_to_sifive_ptc(struct pwm_chip *c) { return container_of(c, struct sifive_pwm_ptc_device, chip); } static void sifive_pwm_ptc_get_state(struct pwm_chip *chip, struct pwm_device *dev, struct pwm_state *state) { struct sifive_pwm_ptc_device *pwm = chip_to_sifive_ptc(chip); u32 data_lrc; u32 data_hrc; u32 pwm_clk_ns = 0; /* get lrc and hrc data from registe */ data_lrc = ioread32(REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm)); data_hrc = ioread32(REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm)); /* how many ns does apb clock elapse */ pwm_clk_ns = NS_1 / clk_get_rate(pwm->clk); /* pwm period(ns) */ state->period = data_lrc * pwm_clk_ns; /* duty cycle(ns) means high level eclapse ns if it is normal polarity */ state->duty_cycle = data_hrc * pwm_clk_ns; /* polarity, we don't use it now because it is not in dts */ state->polarity = PWM_POLARITY_NORMAL; /* enabled or not */ state->enabled = 1; dev_dbg(pwm->chip.dev, "%s: no:%d\n", __func__, dev->hwpwm); dev_dbg(pwm->chip.dev, "data_hrc:0x%x 0x%x\n", data_hrc, data_lrc); dev_dbg(pwm->chip.dev, "period:%llu\n", state->period); dev_dbg(pwm->chip.dev, "duty_cycle:%llu\n", state->duty_cycle); dev_dbg(pwm->chip.dev, "polarity:%d\n", state->polarity); dev_dbg(pwm->chip.dev, "enabled:%d\n", state->enabled); } static int sifive_pwm_ptc_apply(struct pwm_chip *chip, struct pwm_device *dev, const struct pwm_state *state) { struct sifive_pwm_ptc_device *pwm = chip_to_sifive_ptc(chip); void __iomem *reg_addr; u32 pwm_clk_ns = 0; u32 data_hrc = 0; u32 data_lrc = 0; u32 period_data = 0; u32 duty_data = 0; dev_dbg(pwm->chip.dev, "%s: no:%d\n", __func__, dev->hwpwm); dev_dbg(pwm->chip.dev, "period:%llu\n", state->period); dev_dbg(pwm->chip.dev, "duty_cycle:%llu\n", state->duty_cycle); dev_dbg(pwm->chip.dev, "polarity:%d\n", state->polarity); dev_dbg(pwm->chip.dev, "enabled:%d\n", state->enabled); /* duty_cycle should be less or equal than period */ if (state->duty_cycle > state->period) return -EINVAL; /* calculate pwm real period (ns) */ pwm_clk_ns = NS_1 / clk_get_rate(pwm->clk); dev_dbg(pwm->chip.dev, "pwm_clk_ns:%u\n", pwm_clk_ns); /* calculate period count */ period_data = div_u64(state->period, pwm_clk_ns); if (!state->enabled) /* if disabled, just set duty_data to 0, which means low level always */ duty_data = 0; else /* calculate duty count */ duty_data = div_u64(state->duty_cycle, pwm_clk_ns); dev_dbg(pwm->chip.dev, "period_data:%u, duty_data:%u\n", period_data, duty_data); if (state->polarity == PWM_POLARITY_NORMAL) /* calculate data_hrc */ data_hrc = period_data - duty_data; else /* calculate data_hrc */ data_hrc = duty_data; data_lrc = period_data; /* set hrc */ reg_addr = REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm); dev_dbg(pwm->chip.dev, "%s: reg_addr:%p, data:%u\n", __func__, reg_addr, data_hrc); iowrite32(data_hrc, reg_addr); dev_dbg(pwm->chip.dev, "%s: hrc ok\n", __func__); /* set lrc */ reg_addr = REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm); dev_dbg(pwm->chip.dev, "%s: reg_addr:%p, data:%u\n", __func__, reg_addr, data_lrc); iowrite32(data_lrc, reg_addr); dev_dbg(pwm->chip.dev, "%s: lrc ok\n", __func__); /* Clear REG_RPTC_CNTR after setting period & duty_cycle */ reg_addr = REG_PTC_RPTC_CNTR(pwm->regs, dev->hwpwm); iowrite32(0, reg_addr); return 0; } static const struct pwm_ops sifive_pwm_ptc_ops = { .get_state = sifive_pwm_ptc_get_state, .apply = sifive_pwm_ptc_apply, .owner = THIS_MODULE, }; static void sifive_pwm_ptc_disable_action(void *data) { clk_disable_unprepare(data); } static int sifive_pwm_ptc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *node = pdev->dev.of_node; struct sifive_pwm_ptc_device *pwm; struct pwm_chip *chip; struct reset_control *rst; int ret; pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL); if (!pwm) return -ENOMEM; platform_set_drvdata(pdev, pwm); chip = &pwm->chip; chip->dev = dev; chip->ops = &sifive_pwm_ptc_ops; /* how many parameters can be transferred to ptc, need to fix */ chip->of_pwm_n_cells = 3; chip->base = -1; /* get pwm channels count, max value is 8 */ ret = of_property_read_u32(node, "starfive,npwm", &chip->npwm); if (ret < 0 || chip->npwm > MAX_PWM) chip->npwm = MAX_PWM; dev_dbg(dev, "%s: npwm:0x%x\n", __func__, chip->npwm); /* get IO base address */ pwm->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pwm->regs)) return dev_err_probe(dev, PTR_ERR(pwm->regs), "Unable to map IO resources\n"); pwm->clk = devm_clk_get(dev, NULL); if (IS_ERR(pwm->clk)) return dev_err_probe(dev, PTR_ERR(pwm->clk), "Unable to get controller clock\n"); ret = clk_prepare_enable(pwm->clk); if (ret) return dev_err_probe(dev, ret, "Unable to enable clock\n"); ret = devm_add_action_or_reset(dev, sifive_pwm_ptc_disable_action, pwm->clk); if (ret) return ret; rst = devm_reset_control_get_exclusive(dev, NULL); if (IS_ERR(rst)) return dev_err_probe(dev, PTR_ERR(rst), "Unable to get reset\n"); ret = reset_control_deassert(rst); if (ret) return dev_err_probe(dev, ret, "Unable to deassert reset\n"); /* * after pwmchip_add it will show up as /sys/class/pwm/pwmchip0, * 0 is chip->base, pwm0 can be seen after running echo 0 > export */ ret = devm_pwmchip_add(dev, chip); if (ret) return dev_err_probe(dev, ret, "cannot register PTC: %d\n", ret); dev_dbg(dev, "SiFive PWM PTC chip registered %d PWMs\n", chip->npwm); return 0; } static const struct of_device_id sifive_pwm_ptc_of_match[] = { { .compatible = "sifive,pwm0" }, { .compatible = "starfive,pwm0" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, sifive_pwm_ptc_of_match); static struct platform_driver sifive_pwm_ptc_driver = { .probe = sifive_pwm_ptc_probe, .driver = { .name = "pwm-sifive-ptc", .of_match_table = sifive_pwm_ptc_of_match, }, }; module_platform_driver(sifive_pwm_ptc_driver); MODULE_DESCRIPTION("SiFive PWM PTC driver"); MODULE_LICENSE("GPL v2");