brintos

brintos / linux-shallow public Read only

0
0
Text · 15.4 KiB · 0125e73 Raw
613 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * EHRPWM PWM driver4 *5 * Copyright (C) 2012 Texas Instruments, Inc. - https://www.ti.com/6 */7 8#include <linux/module.h>9#include <linux/platform_device.h>10#include <linux/pwm.h>11#include <linux/io.h>12#include <linux/err.h>13#include <linux/clk.h>14#include <linux/pm_runtime.h>15#include <linux/of.h>16 17/* EHRPWM registers and bits definitions */18 19/* Time base module registers */20#define TBCTL			0x0021#define TBPRD			0x0A22 23#define TBCTL_PRDLD_MASK	BIT(3)24#define TBCTL_PRDLD_SHDW	025#define TBCTL_PRDLD_IMDT	BIT(3)26#define TBCTL_CLKDIV_MASK	(BIT(12) | BIT(11) | BIT(10) | BIT(9) | \27				BIT(8) | BIT(7))28#define TBCTL_CTRMODE_MASK	(BIT(1) | BIT(0))29#define TBCTL_CTRMODE_UP	030#define TBCTL_CTRMODE_DOWN	BIT(0)31#define TBCTL_CTRMODE_UPDOWN	BIT(1)32#define TBCTL_CTRMODE_FREEZE	(BIT(1) | BIT(0))33 34#define TBCTL_HSPCLKDIV_SHIFT	735#define TBCTL_CLKDIV_SHIFT	1036 37#define CLKDIV_MAX		738#define HSPCLKDIV_MAX		739#define PERIOD_MAX		0xFFFF40 41/* compare module registers */42#define CMPA			0x1243#define CMPB			0x1444 45/* Action qualifier module registers */46#define AQCTLA			0x1647#define AQCTLB			0x1848#define AQSFRC			0x1A49#define AQCSFRC			0x1C50 51#define AQCTL_CBU_MASK		(BIT(9) | BIT(8))52#define AQCTL_CBU_FRCLOW	BIT(8)53#define AQCTL_CBU_FRCHIGH	BIT(9)54#define AQCTL_CBU_FRCTOGGLE	(BIT(9) | BIT(8))55#define AQCTL_CAU_MASK		(BIT(5) | BIT(4))56#define AQCTL_CAU_FRCLOW	BIT(4)57#define AQCTL_CAU_FRCHIGH	BIT(5)58#define AQCTL_CAU_FRCTOGGLE	(BIT(5) | BIT(4))59#define AQCTL_PRD_MASK		(BIT(3) | BIT(2))60#define AQCTL_PRD_FRCLOW	BIT(2)61#define AQCTL_PRD_FRCHIGH	BIT(3)62#define AQCTL_PRD_FRCTOGGLE	(BIT(3) | BIT(2))63#define AQCTL_ZRO_MASK		(BIT(1) | BIT(0))64#define AQCTL_ZRO_FRCLOW	BIT(0)65#define AQCTL_ZRO_FRCHIGH	BIT(1)66#define AQCTL_ZRO_FRCTOGGLE	(BIT(1) | BIT(0))67 68#define AQCTL_CHANA_POLNORMAL	(AQCTL_CAU_FRCLOW | AQCTL_PRD_FRCHIGH | \69				AQCTL_ZRO_FRCHIGH)70#define AQCTL_CHANA_POLINVERSED	(AQCTL_CAU_FRCHIGH | AQCTL_PRD_FRCLOW | \71				AQCTL_ZRO_FRCLOW)72#define AQCTL_CHANB_POLNORMAL	(AQCTL_CBU_FRCLOW | AQCTL_PRD_FRCHIGH | \73				AQCTL_ZRO_FRCHIGH)74#define AQCTL_CHANB_POLINVERSED	(AQCTL_CBU_FRCHIGH | AQCTL_PRD_FRCLOW | \75				AQCTL_ZRO_FRCLOW)76 77#define AQSFRC_RLDCSF_MASK	(BIT(7) | BIT(6))78#define AQSFRC_RLDCSF_ZRO	079#define AQSFRC_RLDCSF_PRD	BIT(6)80#define AQSFRC_RLDCSF_ZROPRD	BIT(7)81#define AQSFRC_RLDCSF_IMDT	(BIT(7) | BIT(6))82 83#define AQCSFRC_CSFB_MASK	(BIT(3) | BIT(2))84#define AQCSFRC_CSFB_FRCDIS	085#define AQCSFRC_CSFB_FRCLOW	BIT(2)86#define AQCSFRC_CSFB_FRCHIGH	BIT(3)87#define AQCSFRC_CSFB_DISSWFRC	(BIT(3) | BIT(2))88#define AQCSFRC_CSFA_MASK	(BIT(1) | BIT(0))89#define AQCSFRC_CSFA_FRCDIS	090#define AQCSFRC_CSFA_FRCLOW	BIT(0)91#define AQCSFRC_CSFA_FRCHIGH	BIT(1)92#define AQCSFRC_CSFA_DISSWFRC	(BIT(1) | BIT(0))93 94#define NUM_PWM_CHANNEL		2	/* EHRPWM channels */95 96struct ehrpwm_context {97	u16 tbctl;98	u16 tbprd;99	u16 cmpa;100	u16 cmpb;101	u16 aqctla;102	u16 aqctlb;103	u16 aqsfrc;104	u16 aqcsfrc;105};106 107struct ehrpwm_pwm_chip {108	unsigned long clk_rate;109	void __iomem *mmio_base;110	unsigned long period_cycles[NUM_PWM_CHANNEL];111	enum pwm_polarity polarity[NUM_PWM_CHANNEL];112	struct clk *tbclk;113	struct ehrpwm_context ctx;114};115 116static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)117{118	return pwmchip_get_drvdata(chip);119}120 121static inline u16 ehrpwm_read(void __iomem *base, unsigned int offset)122{123	return readw(base + offset);124}125 126static inline void ehrpwm_write(void __iomem *base, unsigned int offset,127				u16 value)128{129	writew(value, base + offset);130}131 132static void ehrpwm_modify(void __iomem *base, unsigned int offset, u16 mask,133			  u16 value)134{135	unsigned short val;136 137	val = readw(base + offset);138	val &= ~mask;139	val |= value & mask;140	writew(val, base + offset);141}142 143/**144 * set_prescale_div -	Set up the prescaler divider function145 * @rqst_prescaler:	prescaler value min146 * @prescale_div:	prescaler value set147 * @tb_clk_div:		Time Base Control prescaler bits148 */149static int set_prescale_div(unsigned long rqst_prescaler, u16 *prescale_div,150			    u16 *tb_clk_div)151{152	unsigned int clkdiv, hspclkdiv;153 154	for (clkdiv = 0; clkdiv <= CLKDIV_MAX; clkdiv++) {155		for (hspclkdiv = 0; hspclkdiv <= HSPCLKDIV_MAX; hspclkdiv++) {156			/*157			 * calculations for prescaler value :158			 * prescale_div = HSPCLKDIVIDER * CLKDIVIDER.159			 * HSPCLKDIVIDER =  2 ** hspclkdiv160			 * CLKDIVIDER = (1),		if clkdiv == 0 *OR*161			 *		(2 * clkdiv),	if clkdiv != 0162			 *163			 * Configure prescale_div value such that period164			 * register value is less than 65535.165			 */166 167			*prescale_div = (1 << clkdiv) *168					(hspclkdiv ? (hspclkdiv * 2) : 1);169			if (*prescale_div > rqst_prescaler) {170				*tb_clk_div = (clkdiv << TBCTL_CLKDIV_SHIFT) |171					(hspclkdiv << TBCTL_HSPCLKDIV_SHIFT);172				return 0;173			}174		}175	}176 177	return 1;178}179 180static void configure_polarity(struct ehrpwm_pwm_chip *pc, int chan)181{182	u16 aqctl_val, aqctl_mask;183	unsigned int aqctl_reg;184 185	/*186	 * Configure PWM output to HIGH/LOW level on counter187	 * reaches compare register value and LOW/HIGH level188	 * on counter value reaches period register value and189	 * zero value on counter190	 */191	if (chan == 1) {192		aqctl_reg = AQCTLB;193		aqctl_mask = AQCTL_CBU_MASK;194 195		if (pc->polarity[chan] == PWM_POLARITY_INVERSED)196			aqctl_val = AQCTL_CHANB_POLINVERSED;197		else198			aqctl_val = AQCTL_CHANB_POLNORMAL;199	} else {200		aqctl_reg = AQCTLA;201		aqctl_mask = AQCTL_CAU_MASK;202 203		if (pc->polarity[chan] == PWM_POLARITY_INVERSED)204			aqctl_val = AQCTL_CHANA_POLINVERSED;205		else206			aqctl_val = AQCTL_CHANA_POLNORMAL;207	}208 209	aqctl_mask |= AQCTL_PRD_MASK | AQCTL_ZRO_MASK;210	ehrpwm_modify(pc->mmio_base, aqctl_reg, aqctl_mask, aqctl_val);211}212 213/*214 * period_ns = 10^9 * (ps_divval * period_cycles) / PWM_CLK_RATE215 * duty_ns   = 10^9 * (ps_divval * duty_cycles) / PWM_CLK_RATE216 */217static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,218			     u64 duty_ns, u64 period_ns)219{220	struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);221	u32 period_cycles, duty_cycles;222	u16 ps_divval, tb_divval;223	unsigned int i, cmp_reg;224	unsigned long long c;225 226	if (period_ns > NSEC_PER_SEC)227		return -ERANGE;228 229	c = pc->clk_rate;230	c = c * period_ns;231	do_div(c, NSEC_PER_SEC);232	period_cycles = (unsigned long)c;233 234	if (period_cycles < 1) {235		period_cycles = 1;236		duty_cycles = 1;237	} else {238		c = pc->clk_rate;239		c = c * duty_ns;240		do_div(c, NSEC_PER_SEC);241		duty_cycles = (unsigned long)c;242	}243 244	/*245	 * Period values should be same for multiple PWM channels as IP uses246	 * same period register for multiple channels.247	 */248	for (i = 0; i < NUM_PWM_CHANNEL; i++) {249		if (pc->period_cycles[i] &&250				(pc->period_cycles[i] != period_cycles)) {251			/*252			 * Allow channel to reconfigure period if no other253			 * channels being configured.254			 */255			if (i == pwm->hwpwm)256				continue;257 258			dev_err(pwmchip_parent(chip),259				"period value conflicts with channel %u\n",260				i);261			return -EINVAL;262		}263	}264 265	pc->period_cycles[pwm->hwpwm] = period_cycles;266 267	/* Configure clock prescaler to support Low frequency PWM wave */268	if (set_prescale_div(period_cycles/PERIOD_MAX, &ps_divval,269			     &tb_divval)) {270		dev_err(pwmchip_parent(chip), "Unsupported values\n");271		return -EINVAL;272	}273 274	pm_runtime_get_sync(pwmchip_parent(chip));275 276	/* Update clock prescaler values */277	ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CLKDIV_MASK, tb_divval);278 279	/* Update period & duty cycle with presacler division */280	period_cycles = period_cycles / ps_divval;281	duty_cycles = duty_cycles / ps_divval;282 283	/* Configure shadow loading on Period register */284	ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_PRDLD_MASK, TBCTL_PRDLD_SHDW);285 286	ehrpwm_write(pc->mmio_base, TBPRD, period_cycles);287 288	/* Configure ehrpwm counter for up-count mode */289	ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CTRMODE_MASK,290		      TBCTL_CTRMODE_UP);291 292	if (pwm->hwpwm == 1)293		/* Channel 1 configured with compare B register */294		cmp_reg = CMPB;295	else296		/* Channel 0 configured with compare A register */297		cmp_reg = CMPA;298 299	ehrpwm_write(pc->mmio_base, cmp_reg, duty_cycles);300 301	pm_runtime_put_sync(pwmchip_parent(chip));302 303	return 0;304}305 306static int ehrpwm_pwm_set_polarity(struct pwm_chip *chip,307				   struct pwm_device *pwm,308				   enum pwm_polarity polarity)309{310	struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);311 312	/* Configuration of polarity in hardware delayed, do at enable */313	pc->polarity[pwm->hwpwm] = polarity;314 315	return 0;316}317 318static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)319{320	struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);321	u16 aqcsfrc_val, aqcsfrc_mask;322	int ret;323 324	/* Leave clock enabled on enabling PWM */325	pm_runtime_get_sync(pwmchip_parent(chip));326 327	/* Disabling Action Qualifier on PWM output */328	if (pwm->hwpwm) {329		aqcsfrc_val = AQCSFRC_CSFB_FRCDIS;330		aqcsfrc_mask = AQCSFRC_CSFB_MASK;331	} else {332		aqcsfrc_val = AQCSFRC_CSFA_FRCDIS;333		aqcsfrc_mask = AQCSFRC_CSFA_MASK;334	}335 336	/* Changes to shadow mode */337	ehrpwm_modify(pc->mmio_base, AQSFRC, AQSFRC_RLDCSF_MASK,338		      AQSFRC_RLDCSF_ZRO);339 340	ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);341 342	/* Channels polarity can be configured from action qualifier module */343	configure_polarity(pc, pwm->hwpwm);344 345	/* Enable TBCLK */346	ret = clk_enable(pc->tbclk);347	if (ret) {348		dev_err(pwmchip_parent(chip), "Failed to enable TBCLK for %s: %d\n",349			dev_name(pwmchip_parent(chip)), ret);350		return ret;351	}352 353	return 0;354}355 356static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)357{358	struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);359	u16 aqcsfrc_val, aqcsfrc_mask;360 361	/* Action Qualifier puts PWM output low forcefully */362	if (pwm->hwpwm) {363		aqcsfrc_val = AQCSFRC_CSFB_FRCLOW;364		aqcsfrc_mask = AQCSFRC_CSFB_MASK;365	} else {366		aqcsfrc_val = AQCSFRC_CSFA_FRCLOW;367		aqcsfrc_mask = AQCSFRC_CSFA_MASK;368	}369 370	/* Update shadow register first before modifying active register */371	ehrpwm_modify(pc->mmio_base, AQSFRC, AQSFRC_RLDCSF_MASK,372		      AQSFRC_RLDCSF_ZRO);373	ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);374	/*375	 * Changes to immediate action on Action Qualifier. This puts376	 * Action Qualifier control on PWM output from next TBCLK377	 */378	ehrpwm_modify(pc->mmio_base, AQSFRC, AQSFRC_RLDCSF_MASK,379		      AQSFRC_RLDCSF_IMDT);380 381	ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);382 383	/* Disabling TBCLK on PWM disable */384	clk_disable(pc->tbclk);385 386	/* Disable clock on PWM disable */387	pm_runtime_put_sync(pwmchip_parent(chip));388}389 390static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)391{392	struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);393 394	if (pwm_is_enabled(pwm)) {395		dev_warn(pwmchip_parent(chip), "Removing PWM device without disabling\n");396		pm_runtime_put_sync(pwmchip_parent(chip));397	}398 399	/* set period value to zero on free */400	pc->period_cycles[pwm->hwpwm] = 0;401}402 403static int ehrpwm_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,404			    const struct pwm_state *state)405{406	int err;407	bool enabled = pwm->state.enabled;408 409	if (state->polarity != pwm->state.polarity) {410		if (enabled) {411			ehrpwm_pwm_disable(chip, pwm);412			enabled = false;413		}414 415		err = ehrpwm_pwm_set_polarity(chip, pwm, state->polarity);416		if (err)417			return err;418	}419 420	if (!state->enabled) {421		if (enabled)422			ehrpwm_pwm_disable(chip, pwm);423		return 0;424	}425 426	err = ehrpwm_pwm_config(chip, pwm, state->duty_cycle, state->period);427	if (err)428		return err;429 430	if (!enabled)431		err = ehrpwm_pwm_enable(chip, pwm);432 433	return err;434}435 436static const struct pwm_ops ehrpwm_pwm_ops = {437	.free = ehrpwm_pwm_free,438	.apply = ehrpwm_pwm_apply,439};440 441static const struct of_device_id ehrpwm_of_match[] = {442	{ .compatible = "ti,am3352-ehrpwm" },443	{ .compatible = "ti,am33xx-ehrpwm" },444	{},445};446MODULE_DEVICE_TABLE(of, ehrpwm_of_match);447 448static int ehrpwm_pwm_probe(struct platform_device *pdev)449{450	struct device_node *np = pdev->dev.of_node;451	struct ehrpwm_pwm_chip *pc;452	struct pwm_chip *chip;453	struct clk *clk;454	int ret;455 456	chip = devm_pwmchip_alloc(&pdev->dev, NUM_PWM_CHANNEL, sizeof(*pc));457	if (IS_ERR(chip))458		return PTR_ERR(chip);459	pc = to_ehrpwm_pwm_chip(chip);460 461	clk = devm_clk_get(&pdev->dev, "fck");462	if (IS_ERR(clk)) {463		if (of_device_is_compatible(np, "ti,am33xx-ecap")) {464			dev_warn(&pdev->dev, "Binding is obsolete.\n");465			clk = devm_clk_get(pdev->dev.parent, "fck");466		}467	}468 469	if (IS_ERR(clk))470		return dev_err_probe(&pdev->dev, PTR_ERR(clk), "Failed to get fck\n");471 472	pc->clk_rate = clk_get_rate(clk);473	if (!pc->clk_rate) {474		dev_err(&pdev->dev, "failed to get clock rate\n");475		return -EINVAL;476	}477 478	chip->ops = &ehrpwm_pwm_ops;479 480	pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);481	if (IS_ERR(pc->mmio_base))482		return PTR_ERR(pc->mmio_base);483 484	/* Acquire tbclk for Time Base EHRPWM submodule */485	pc->tbclk = devm_clk_get(&pdev->dev, "tbclk");486	if (IS_ERR(pc->tbclk))487		return dev_err_probe(&pdev->dev, PTR_ERR(pc->tbclk), "Failed to get tbclk\n");488 489	ret = clk_prepare(pc->tbclk);490	if (ret < 0) {491		dev_err(&pdev->dev, "clk_prepare() failed: %d\n", ret);492		return ret;493	}494 495	ret = pwmchip_add(chip);496	if (ret < 0) {497		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);498		goto err_clk_unprepare;499	}500 501	platform_set_drvdata(pdev, chip);502	pm_runtime_enable(&pdev->dev);503 504	return 0;505 506err_clk_unprepare:507	clk_unprepare(pc->tbclk);508 509	return ret;510}511 512static void ehrpwm_pwm_remove(struct platform_device *pdev)513{514	struct pwm_chip *chip = platform_get_drvdata(pdev);515	struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);516 517	pwmchip_remove(chip);518 519	clk_unprepare(pc->tbclk);520 521	pm_runtime_disable(&pdev->dev);522}523 524static void ehrpwm_pwm_save_context(struct pwm_chip *chip)525{526	struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);527 528	pm_runtime_get_sync(pwmchip_parent(chip));529 530	pc->ctx.tbctl = ehrpwm_read(pc->mmio_base, TBCTL);531	pc->ctx.tbprd = ehrpwm_read(pc->mmio_base, TBPRD);532	pc->ctx.cmpa = ehrpwm_read(pc->mmio_base, CMPA);533	pc->ctx.cmpb = ehrpwm_read(pc->mmio_base, CMPB);534	pc->ctx.aqctla = ehrpwm_read(pc->mmio_base, AQCTLA);535	pc->ctx.aqctlb = ehrpwm_read(pc->mmio_base, AQCTLB);536	pc->ctx.aqsfrc = ehrpwm_read(pc->mmio_base, AQSFRC);537	pc->ctx.aqcsfrc = ehrpwm_read(pc->mmio_base, AQCSFRC);538 539	pm_runtime_put_sync(pwmchip_parent(chip));540}541 542static void ehrpwm_pwm_restore_context(struct pwm_chip *chip)543{544	struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);545 546	ehrpwm_write(pc->mmio_base, TBPRD, pc->ctx.tbprd);547	ehrpwm_write(pc->mmio_base, CMPA, pc->ctx.cmpa);548	ehrpwm_write(pc->mmio_base, CMPB, pc->ctx.cmpb);549	ehrpwm_write(pc->mmio_base, AQCTLA, pc->ctx.aqctla);550	ehrpwm_write(pc->mmio_base, AQCTLB, pc->ctx.aqctlb);551	ehrpwm_write(pc->mmio_base, AQSFRC, pc->ctx.aqsfrc);552	ehrpwm_write(pc->mmio_base, AQCSFRC, pc->ctx.aqcsfrc);553	ehrpwm_write(pc->mmio_base, TBCTL, pc->ctx.tbctl);554}555 556static int ehrpwm_pwm_suspend(struct device *dev)557{558	struct pwm_chip *chip = dev_get_drvdata(dev);559	unsigned int i;560 561	ehrpwm_pwm_save_context(chip);562 563	for (i = 0; i < chip->npwm; i++) {564		struct pwm_device *pwm = &chip->pwms[i];565 566		if (!pwm_is_enabled(pwm))567			continue;568 569		/* Disable explicitly if PWM is running */570		pm_runtime_put_sync(dev);571	}572 573	return 0;574}575 576static int ehrpwm_pwm_resume(struct device *dev)577{578	struct pwm_chip *chip = dev_get_drvdata(dev);579	unsigned int i;580 581	for (i = 0; i < chip->npwm; i++) {582		struct pwm_device *pwm = &chip->pwms[i];583 584		if (!pwm_is_enabled(pwm))585			continue;586 587		/* Enable explicitly if PWM was running */588		pm_runtime_get_sync(dev);589	}590 591	ehrpwm_pwm_restore_context(chip);592 593	return 0;594}595 596static DEFINE_SIMPLE_DEV_PM_OPS(ehrpwm_pwm_pm_ops, ehrpwm_pwm_suspend,597				ehrpwm_pwm_resume);598 599static struct platform_driver ehrpwm_pwm_driver = {600	.driver = {601		.name = "ehrpwm",602		.of_match_table = ehrpwm_of_match,603		.pm = pm_ptr(&ehrpwm_pwm_pm_ops),604	},605	.probe = ehrpwm_pwm_probe,606	.remove = ehrpwm_pwm_remove,607};608module_platform_driver(ehrpwm_pwm_driver);609 610MODULE_DESCRIPTION("EHRPWM PWM driver");611MODULE_AUTHOR("Texas Instruments");612MODULE_LICENSE("GPL");613