cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pwm-vt8500.c (7391B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * drivers/pwm/pwm-vt8500.c
      4 *
      5 * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
      6 * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
      7 */
      8
      9#include <linux/module.h>
     10#include <linux/kernel.h>
     11#include <linux/platform_device.h>
     12#include <linux/slab.h>
     13#include <linux/err.h>
     14#include <linux/io.h>
     15#include <linux/pwm.h>
     16#include <linux/delay.h>
     17#include <linux/clk.h>
     18
     19#include <asm/div64.h>
     20
     21#include <linux/of.h>
     22#include <linux/of_device.h>
     23#include <linux/of_address.h>
     24
     25/*
     26 * SoC architecture allocates register space for 4 PWMs but only
     27 * 2 are currently implemented.
     28 */
     29#define VT8500_NR_PWMS	2
     30
     31#define REG_CTRL(pwm)		(((pwm) << 4) + 0x00)
     32#define REG_SCALAR(pwm)		(((pwm) << 4) + 0x04)
     33#define REG_PERIOD(pwm)		(((pwm) << 4) + 0x08)
     34#define REG_DUTY(pwm)		(((pwm) << 4) + 0x0C)
     35#define REG_STATUS		0x40
     36
     37#define CTRL_ENABLE		BIT(0)
     38#define CTRL_INVERT		BIT(1)
     39#define CTRL_AUTOLOAD		BIT(2)
     40#define CTRL_STOP_IMM		BIT(3)
     41#define CTRL_LOAD_PRESCALE	BIT(4)
     42#define CTRL_LOAD_PERIOD	BIT(5)
     43
     44#define STATUS_CTRL_UPDATE	BIT(0)
     45#define STATUS_SCALAR_UPDATE	BIT(1)
     46#define STATUS_PERIOD_UPDATE	BIT(2)
     47#define STATUS_DUTY_UPDATE	BIT(3)
     48#define STATUS_ALL_UPDATE	0x0F
     49
     50struct vt8500_chip {
     51	struct pwm_chip chip;
     52	void __iomem *base;
     53	struct clk *clk;
     54};
     55
     56#define to_vt8500_chip(chip)	container_of(chip, struct vt8500_chip, chip)
     57
     58#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
     59static inline void vt8500_pwm_busy_wait(struct vt8500_chip *vt8500, int nr, u8 bitmask)
     60{
     61	int loops = msecs_to_loops(10);
     62	u32 mask = bitmask << (nr << 8);
     63
     64	while ((readl(vt8500->base + REG_STATUS) & mask) && --loops)
     65		cpu_relax();
     66
     67	if (unlikely(!loops))
     68		dev_warn(vt8500->chip.dev, "Waiting for status bits 0x%x to clear timed out\n",
     69			 mask);
     70}
     71
     72static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
     73		u64 duty_ns, u64 period_ns)
     74{
     75	struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
     76	unsigned long long c;
     77	unsigned long period_cycles, prescale, pv, dc;
     78	int err;
     79	u32 val;
     80
     81	err = clk_enable(vt8500->clk);
     82	if (err < 0) {
     83		dev_err(chip->dev, "failed to enable clock\n");
     84		return err;
     85	}
     86
     87	c = clk_get_rate(vt8500->clk);
     88	c = c * period_ns;
     89	do_div(c, 1000000000);
     90	period_cycles = c;
     91
     92	if (period_cycles < 1)
     93		period_cycles = 1;
     94	prescale = (period_cycles - 1) / 4096;
     95	pv = period_cycles / (prescale + 1) - 1;
     96	if (pv > 4095)
     97		pv = 4095;
     98
     99	if (prescale > 1023) {
    100		clk_disable(vt8500->clk);
    101		return -EINVAL;
    102	}
    103
    104	c = (unsigned long long)pv * duty_ns;
    105
    106	dc = div64_u64(c, period_ns);
    107
    108	writel(prescale, vt8500->base + REG_SCALAR(pwm->hwpwm));
    109	vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_SCALAR_UPDATE);
    110
    111	writel(pv, vt8500->base + REG_PERIOD(pwm->hwpwm));
    112	vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_PERIOD_UPDATE);
    113
    114	writel(dc, vt8500->base + REG_DUTY(pwm->hwpwm));
    115	vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_DUTY_UPDATE);
    116
    117	val = readl(vt8500->base + REG_CTRL(pwm->hwpwm));
    118	val |= CTRL_AUTOLOAD;
    119	writel(val, vt8500->base + REG_CTRL(pwm->hwpwm));
    120	vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE);
    121
    122	clk_disable(vt8500->clk);
    123	return 0;
    124}
    125
    126static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
    127{
    128	struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
    129	int err;
    130	u32 val;
    131
    132	err = clk_enable(vt8500->clk);
    133	if (err < 0) {
    134		dev_err(chip->dev, "failed to enable clock\n");
    135		return err;
    136	}
    137
    138	val = readl(vt8500->base + REG_CTRL(pwm->hwpwm));
    139	val |= CTRL_ENABLE;
    140	writel(val, vt8500->base + REG_CTRL(pwm->hwpwm));
    141	vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE);
    142
    143	return 0;
    144}
    145
    146static void vt8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
    147{
    148	struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
    149	u32 val;
    150
    151	val = readl(vt8500->base + REG_CTRL(pwm->hwpwm));
    152	val &= ~CTRL_ENABLE;
    153	writel(val, vt8500->base + REG_CTRL(pwm->hwpwm));
    154	vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE);
    155
    156	clk_disable(vt8500->clk);
    157}
    158
    159static int vt8500_pwm_set_polarity(struct pwm_chip *chip,
    160				   struct pwm_device *pwm,
    161				   enum pwm_polarity polarity)
    162{
    163	struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
    164	u32 val;
    165
    166	val = readl(vt8500->base + REG_CTRL(pwm->hwpwm));
    167
    168	if (polarity == PWM_POLARITY_INVERSED)
    169		val |= CTRL_INVERT;
    170	else
    171		val &= ~CTRL_INVERT;
    172
    173	writel(val, vt8500->base + REG_CTRL(pwm->hwpwm));
    174	vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE);
    175
    176	return 0;
    177}
    178
    179static int vt8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
    180			    const struct pwm_state *state)
    181{
    182	int err;
    183	bool enabled = pwm->state.enabled;
    184
    185	if (state->polarity != pwm->state.polarity) {
    186		/*
    187		 * Changing the polarity of a running PWM is only allowed when
    188		 * the PWM driver implements ->apply().
    189		 */
    190		if (enabled) {
    191			vt8500_pwm_disable(chip, pwm);
    192
    193			enabled = false;
    194		}
    195
    196		err = vt8500_pwm_set_polarity(chip, pwm, state->polarity);
    197		if (err)
    198			return err;
    199	}
    200
    201	if (!state->enabled) {
    202		if (enabled)
    203			vt8500_pwm_disable(chip, pwm);
    204
    205		return 0;
    206	}
    207
    208	/*
    209	 * We cannot skip calling ->config even if state->period ==
    210	 * pwm->state.period && state->duty_cycle == pwm->state.duty_cycle
    211	 * because we might have exited early in the last call to
    212	 * pwm_apply_state because of !state->enabled and so the two values in
    213	 * pwm->state might not be configured in hardware.
    214	 */
    215	err = vt8500_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
    216	if (err)
    217		return err;
    218
    219	if (!enabled)
    220		err = vt8500_pwm_enable(chip, pwm);
    221
    222	return err;
    223}
    224
    225static const struct pwm_ops vt8500_pwm_ops = {
    226	.apply = vt8500_pwm_apply,
    227	.owner = THIS_MODULE,
    228};
    229
    230static const struct of_device_id vt8500_pwm_dt_ids[] = {
    231	{ .compatible = "via,vt8500-pwm", },
    232	{ /* Sentinel */ }
    233};
    234MODULE_DEVICE_TABLE(of, vt8500_pwm_dt_ids);
    235
    236static int vt8500_pwm_probe(struct platform_device *pdev)
    237{
    238	struct vt8500_chip *vt8500;
    239	struct device_node *np = pdev->dev.of_node;
    240	int ret;
    241
    242	if (!np) {
    243		dev_err(&pdev->dev, "invalid devicetree node\n");
    244		return -EINVAL;
    245	}
    246
    247	vt8500 = devm_kzalloc(&pdev->dev, sizeof(*vt8500), GFP_KERNEL);
    248	if (vt8500 == NULL)
    249		return -ENOMEM;
    250
    251	vt8500->chip.dev = &pdev->dev;
    252	vt8500->chip.ops = &vt8500_pwm_ops;
    253	vt8500->chip.npwm = VT8500_NR_PWMS;
    254
    255	vt8500->clk = devm_clk_get(&pdev->dev, NULL);
    256	if (IS_ERR(vt8500->clk)) {
    257		dev_err(&pdev->dev, "clock source not specified\n");
    258		return PTR_ERR(vt8500->clk);
    259	}
    260
    261	vt8500->base = devm_platform_ioremap_resource(pdev, 0);
    262	if (IS_ERR(vt8500->base))
    263		return PTR_ERR(vt8500->base);
    264
    265	ret = clk_prepare(vt8500->clk);
    266	if (ret < 0) {
    267		dev_err(&pdev->dev, "failed to prepare clock\n");
    268		return ret;
    269	}
    270
    271	ret = pwmchip_add(&vt8500->chip);
    272	if (ret < 0) {
    273		dev_err(&pdev->dev, "failed to add PWM chip\n");
    274		clk_unprepare(vt8500->clk);
    275		return ret;
    276	}
    277
    278	platform_set_drvdata(pdev, vt8500);
    279	return ret;
    280}
    281
    282static int vt8500_pwm_remove(struct platform_device *pdev)
    283{
    284	struct vt8500_chip *vt8500 = platform_get_drvdata(pdev);
    285
    286	pwmchip_remove(&vt8500->chip);
    287
    288	clk_unprepare(vt8500->clk);
    289
    290	return 0;
    291}
    292
    293static struct platform_driver vt8500_pwm_driver = {
    294	.probe		= vt8500_pwm_probe,
    295	.remove		= vt8500_pwm_remove,
    296	.driver		= {
    297		.name	= "vt8500-pwm",
    298		.of_match_table = vt8500_pwm_dt_ids,
    299	},
    300};
    301module_platform_driver(vt8500_pwm_driver);
    302
    303MODULE_DESCRIPTION("VT8500 PWM Driver");
    304MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
    305MODULE_LICENSE("GPL v2");