brintos

brintos / linux-shallow public Read only

0
0
Text · 7.7 KiB · 4c76ca5 Raw
297 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2019 Spreadtrum Communications Inc.4 */5 6#include <linux/clk.h>7#include <linux/err.h>8#include <linux/io.h>9#include <linux/math64.h>10#include <linux/mod_devicetable.h>11#include <linux/module.h>12#include <linux/platform_device.h>13#include <linux/pwm.h>14 15#define SPRD_PWM_PRESCALE	0x016#define SPRD_PWM_MOD		0x417#define SPRD_PWM_DUTY		0x818#define SPRD_PWM_ENABLE		0x1819 20#define SPRD_PWM_MOD_MAX	GENMASK(7, 0)21#define SPRD_PWM_DUTY_MSK	GENMASK(15, 0)22#define SPRD_PWM_PRESCALE_MSK	GENMASK(7, 0)23#define SPRD_PWM_ENABLE_BIT	BIT(0)24 25#define SPRD_PWM_CHN_NUM	426#define SPRD_PWM_REGS_SHIFT	527#define SPRD_PWM_CHN_CLKS_NUM	228#define SPRD_PWM_CHN_OUTPUT_CLK	129 30struct sprd_pwm_chn {31	struct clk_bulk_data clks[SPRD_PWM_CHN_CLKS_NUM];32	u32 clk_rate;33};34 35struct sprd_pwm_chip {36	void __iomem *base;37	struct sprd_pwm_chn chn[SPRD_PWM_CHN_NUM];38};39 40static inline struct sprd_pwm_chip* sprd_pwm_from_chip(struct pwm_chip *chip)41{42	return pwmchip_get_drvdata(chip);43}44 45/*46 * The list of clocks required by PWM channels, and each channel has 2 clocks:47 * enable clock and pwm clock.48 */49static const char * const sprd_pwm_clks[] = {50	"enable0", "pwm0",51	"enable1", "pwm1",52	"enable2", "pwm2",53	"enable3", "pwm3",54};55 56static u32 sprd_pwm_read(struct sprd_pwm_chip *spc, u32 hwid, u32 reg)57{58	u32 offset = reg + (hwid << SPRD_PWM_REGS_SHIFT);59 60	return readl_relaxed(spc->base + offset);61}62 63static void sprd_pwm_write(struct sprd_pwm_chip *spc, u32 hwid,64			   u32 reg, u32 val)65{66	u32 offset = reg + (hwid << SPRD_PWM_REGS_SHIFT);67 68	writel_relaxed(val, spc->base + offset);69}70 71static int sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,72			      struct pwm_state *state)73{74	struct sprd_pwm_chip *spc = sprd_pwm_from_chip(chip);75	struct sprd_pwm_chn *chn = &spc->chn[pwm->hwpwm];76	u32 val, duty, prescale;77	u64 tmp;78	int ret;79 80	/*81	 * The clocks to PWM channel has to be enabled first before82	 * reading to the registers.83	 */84	ret = clk_bulk_prepare_enable(SPRD_PWM_CHN_CLKS_NUM, chn->clks);85	if (ret) {86		dev_err(pwmchip_parent(chip), "failed to enable pwm%u clocks\n",87			pwm->hwpwm);88		return ret;89	}90 91	val = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_ENABLE);92	if (val & SPRD_PWM_ENABLE_BIT)93		state->enabled = true;94	else95		state->enabled = false;96 97	/*98	 * The hardware provides a counter that is feed by the source clock.99	 * The period length is (PRESCALE + 1) * MOD counter steps.100	 * The duty cycle length is (PRESCALE + 1) * DUTY counter steps.101	 * Thus the period_ns and duty_ns calculation formula should be:102	 * period_ns = NSEC_PER_SEC * (prescale + 1) * mod / clk_rate103	 * duty_ns = NSEC_PER_SEC * (prescale + 1) * duty / clk_rate104	 */105	val = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_PRESCALE);106	prescale = val & SPRD_PWM_PRESCALE_MSK;107	tmp = (prescale + 1) * NSEC_PER_SEC * SPRD_PWM_MOD_MAX;108	state->period = DIV_ROUND_CLOSEST_ULL(tmp, chn->clk_rate);109 110	val = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_DUTY);111	duty = val & SPRD_PWM_DUTY_MSK;112	tmp = (prescale + 1) * NSEC_PER_SEC * duty;113	state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, chn->clk_rate);114	state->polarity = PWM_POLARITY_NORMAL;115 116	/* Disable PWM clocks if the PWM channel is not in enable state. */117	if (!state->enabled)118		clk_bulk_disable_unprepare(SPRD_PWM_CHN_CLKS_NUM, chn->clks);119 120	return 0;121}122 123static int sprd_pwm_config(struct sprd_pwm_chip *spc, struct pwm_device *pwm,124			   int duty_ns, int period_ns)125{126	struct sprd_pwm_chn *chn = &spc->chn[pwm->hwpwm];127	u32 prescale, duty;128	u64 tmp;129 130	/*131	 * The hardware provides a counter that is feed by the source clock.132	 * The period length is (PRESCALE + 1) * MOD counter steps.133	 * The duty cycle length is (PRESCALE + 1) * DUTY counter steps.134	 *135	 * To keep the maths simple we're always using MOD = SPRD_PWM_MOD_MAX.136	 * The value for PRESCALE is selected such that the resulting period137	 * gets the maximal length not bigger than the requested one with the138	 * given settings (MOD = SPRD_PWM_MOD_MAX and input clock).139	 */140	duty = duty_ns * SPRD_PWM_MOD_MAX / period_ns;141 142	tmp = (u64)chn->clk_rate * period_ns;143	do_div(tmp, NSEC_PER_SEC);144	prescale = DIV_ROUND_CLOSEST_ULL(tmp, SPRD_PWM_MOD_MAX) - 1;145	if (prescale > SPRD_PWM_PRESCALE_MSK)146		prescale = SPRD_PWM_PRESCALE_MSK;147 148	/*149	 * Note: Writing DUTY triggers the hardware to actually apply the150	 * values written to MOD and DUTY to the output, so must keep writing151	 * DUTY last.152	 *153	 * The hardware can ensures that current running period is completed154	 * before changing a new configuration to avoid mixed settings.155	 */156	sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_PRESCALE, prescale);157	sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_MOD, SPRD_PWM_MOD_MAX);158	sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_DUTY, duty);159 160	return 0;161}162 163static int sprd_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,164			  const struct pwm_state *state)165{166	struct sprd_pwm_chip *spc = sprd_pwm_from_chip(chip);167	struct sprd_pwm_chn *chn = &spc->chn[pwm->hwpwm];168	struct pwm_state *cstate = &pwm->state;169	int ret;170 171	if (state->polarity != PWM_POLARITY_NORMAL)172		return -EINVAL;173 174	if (state->enabled) {175		if (!cstate->enabled) {176			/*177			 * The clocks to PWM channel has to be enabled first178			 * before writing to the registers.179			 */180			ret = clk_bulk_prepare_enable(SPRD_PWM_CHN_CLKS_NUM,181						      chn->clks);182			if (ret) {183				dev_err(pwmchip_parent(chip),184					"failed to enable pwm%u clocks\n",185					pwm->hwpwm);186				return ret;187			}188		}189 190		ret = sprd_pwm_config(spc, pwm, state->duty_cycle,191				      state->period);192		if (ret)193			return ret;194 195		sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_ENABLE, 1);196	} else if (cstate->enabled) {197		/*198		 * Note: After setting SPRD_PWM_ENABLE to zero, the controller199		 * will not wait for current period to be completed, instead it200		 * will stop the PWM channel immediately.201		 */202		sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_ENABLE, 0);203 204		clk_bulk_disable_unprepare(SPRD_PWM_CHN_CLKS_NUM, chn->clks);205	}206 207	return 0;208}209 210static const struct pwm_ops sprd_pwm_ops = {211	.apply = sprd_pwm_apply,212	.get_state = sprd_pwm_get_state,213};214 215static int sprd_pwm_clk_init(struct device *dev,216			     struct sprd_pwm_chn chn[SPRD_PWM_CHN_NUM])217{218	struct clk *clk_pwm;219	int ret, i;220 221	for (i = 0; i < SPRD_PWM_CHN_NUM; i++) {222		int j;223 224		for (j = 0; j < SPRD_PWM_CHN_CLKS_NUM; ++j)225			chn[i].clks[j].id =226				sprd_pwm_clks[i * SPRD_PWM_CHN_CLKS_NUM + j];227 228		ret = devm_clk_bulk_get(dev, SPRD_PWM_CHN_CLKS_NUM,229					chn[i].clks);230		if (ret) {231			if (ret == -ENOENT)232				break;233 234			return dev_err_probe(dev, ret,235					     "failed to get channel clocks\n");236		}237 238		clk_pwm = chn[i].clks[SPRD_PWM_CHN_OUTPUT_CLK].clk;239		chn[i].clk_rate = clk_get_rate(clk_pwm);240	}241 242	if (!i)243		return dev_err_probe(dev, -ENODEV, "no available PWM channels\n");244 245	return i;246}247 248static int sprd_pwm_probe(struct platform_device *pdev)249{250	struct pwm_chip *chip;251	struct sprd_pwm_chip *spc;252	struct sprd_pwm_chn chn[SPRD_PWM_CHN_NUM];253	int ret, npwm;254 255	npwm = sprd_pwm_clk_init(&pdev->dev, chn);256	if (npwm < 0)257		return npwm;258 259	chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*spc));260	if (IS_ERR(chip))261		return PTR_ERR(chip);262	spc = sprd_pwm_from_chip(chip);263 264	spc->base = devm_platform_ioremap_resource(pdev, 0);265	if (IS_ERR(spc->base))266		return PTR_ERR(spc->base);267 268	memcpy(spc->chn, chn, sizeof(chn));269 270	chip->ops = &sprd_pwm_ops;271 272	ret = devm_pwmchip_add(&pdev->dev, chip);273	if (ret)274		dev_err(&pdev->dev, "failed to add PWM chip\n");275 276	return ret;277}278 279static const struct of_device_id sprd_pwm_of_match[] = {280	{ .compatible = "sprd,ums512-pwm", },281	{ },282};283MODULE_DEVICE_TABLE(of, sprd_pwm_of_match);284 285static struct platform_driver sprd_pwm_driver = {286	.driver = {287		.name = "sprd-pwm",288		.of_match_table = sprd_pwm_of_match,289	},290	.probe = sprd_pwm_probe,291};292 293module_platform_driver(sprd_pwm_driver);294 295MODULE_DESCRIPTION("Spreadtrum PWM Driver");296MODULE_LICENSE("GPL v2");297