Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.20 282 lines 6.8 kB view raw
1/* 2 * Copyright (C) 2017 Sanechips Technology Co., Ltd. 3 * Copyright 2017 Linaro Ltd. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 */ 9 10#include <linux/clk.h> 11#include <linux/err.h> 12#include <linux/io.h> 13#include <linux/kernel.h> 14#include <linux/module.h> 15#include <linux/platform_device.h> 16#include <linux/pwm.h> 17#include <linux/slab.h> 18 19#define ZX_PWM_MODE 0x0 20#define ZX_PWM_CLKDIV_SHIFT 2 21#define ZX_PWM_CLKDIV_MASK GENMASK(11, 2) 22#define ZX_PWM_CLKDIV(x) (((x) << ZX_PWM_CLKDIV_SHIFT) & \ 23 ZX_PWM_CLKDIV_MASK) 24#define ZX_PWM_POLAR BIT(1) 25#define ZX_PWM_EN BIT(0) 26#define ZX_PWM_PERIOD 0x4 27#define ZX_PWM_DUTY 0x8 28 29#define ZX_PWM_CLKDIV_MAX 1023 30#define ZX_PWM_PERIOD_MAX 65535 31 32struct zx_pwm_chip { 33 struct pwm_chip chip; 34 struct clk *pclk; 35 struct clk *wclk; 36 void __iomem *base; 37}; 38 39static inline struct zx_pwm_chip *to_zx_pwm_chip(struct pwm_chip *chip) 40{ 41 return container_of(chip, struct zx_pwm_chip, chip); 42} 43 44static inline u32 zx_pwm_readl(struct zx_pwm_chip *zpc, unsigned int hwpwm, 45 unsigned int offset) 46{ 47 return readl(zpc->base + (hwpwm + 1) * 0x10 + offset); 48} 49 50static inline void zx_pwm_writel(struct zx_pwm_chip *zpc, unsigned int hwpwm, 51 unsigned int offset, u32 value) 52{ 53 writel(value, zpc->base + (hwpwm + 1) * 0x10 + offset); 54} 55 56static void zx_pwm_set_mask(struct zx_pwm_chip *zpc, unsigned int hwpwm, 57 unsigned int offset, u32 mask, u32 value) 58{ 59 u32 data; 60 61 data = zx_pwm_readl(zpc, hwpwm, offset); 62 data &= ~mask; 63 data |= value & mask; 64 zx_pwm_writel(zpc, hwpwm, offset, data); 65} 66 67static void zx_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, 68 struct pwm_state *state) 69{ 70 struct zx_pwm_chip *zpc = to_zx_pwm_chip(chip); 71 unsigned long rate; 72 unsigned int div; 73 u32 value; 74 u64 tmp; 75 76 value = zx_pwm_readl(zpc, pwm->hwpwm, ZX_PWM_MODE); 77 78 if (value & ZX_PWM_POLAR) 79 state->polarity = PWM_POLARITY_NORMAL; 80 else 81 state->polarity = PWM_POLARITY_INVERSED; 82 83 if (value & ZX_PWM_EN) 84 state->enabled = true; 85 else 86 state->enabled = false; 87 88 div = (value & ZX_PWM_CLKDIV_MASK) >> ZX_PWM_CLKDIV_SHIFT; 89 rate = clk_get_rate(zpc->wclk); 90 91 tmp = zx_pwm_readl(zpc, pwm->hwpwm, ZX_PWM_PERIOD); 92 tmp *= div * NSEC_PER_SEC; 93 state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate); 94 95 tmp = zx_pwm_readl(zpc, pwm->hwpwm, ZX_PWM_DUTY); 96 tmp *= div * NSEC_PER_SEC; 97 state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate); 98} 99 100static int zx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 101 unsigned int duty_ns, unsigned int period_ns) 102{ 103 struct zx_pwm_chip *zpc = to_zx_pwm_chip(chip); 104 unsigned int period_cycles, duty_cycles; 105 unsigned long long c; 106 unsigned int div = 1; 107 unsigned long rate; 108 109 /* Find out the best divider */ 110 rate = clk_get_rate(zpc->wclk); 111 112 while (1) { 113 c = rate / div; 114 c = c * period_ns; 115 do_div(c, NSEC_PER_SEC); 116 117 if (c < ZX_PWM_PERIOD_MAX) 118 break; 119 120 div++; 121 122 if (div > ZX_PWM_CLKDIV_MAX) 123 return -ERANGE; 124 } 125 126 /* Calculate duty cycles */ 127 period_cycles = c; 128 c *= duty_ns; 129 do_div(c, period_ns); 130 duty_cycles = c; 131 132 /* 133 * If the PWM is being enabled, we have to temporarily disable it 134 * before configuring the registers. 135 */ 136 if (pwm_is_enabled(pwm)) 137 zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, ZX_PWM_EN, 0); 138 139 /* Set up registers */ 140 zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, ZX_PWM_CLKDIV_MASK, 141 ZX_PWM_CLKDIV(div)); 142 zx_pwm_writel(zpc, pwm->hwpwm, ZX_PWM_PERIOD, period_cycles); 143 zx_pwm_writel(zpc, pwm->hwpwm, ZX_PWM_DUTY, duty_cycles); 144 145 /* Re-enable the PWM if needed */ 146 if (pwm_is_enabled(pwm)) 147 zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, 148 ZX_PWM_EN, ZX_PWM_EN); 149 150 return 0; 151} 152 153static int zx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, 154 struct pwm_state *state) 155{ 156 struct zx_pwm_chip *zpc = to_zx_pwm_chip(chip); 157 struct pwm_state cstate; 158 int ret; 159 160 pwm_get_state(pwm, &cstate); 161 162 if (state->polarity != cstate.polarity) 163 zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, ZX_PWM_POLAR, 164 (state->polarity == PWM_POLARITY_INVERSED) ? 165 0 : ZX_PWM_POLAR); 166 167 if (state->period != cstate.period || 168 state->duty_cycle != cstate.duty_cycle) { 169 ret = zx_pwm_config(chip, pwm, state->duty_cycle, 170 state->period); 171 if (ret) 172 return ret; 173 } 174 175 if (state->enabled != cstate.enabled) { 176 if (state->enabled) { 177 ret = clk_prepare_enable(zpc->wclk); 178 if (ret) 179 return ret; 180 181 zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, 182 ZX_PWM_EN, ZX_PWM_EN); 183 } else { 184 zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, 185 ZX_PWM_EN, 0); 186 clk_disable_unprepare(zpc->wclk); 187 } 188 } 189 190 return 0; 191} 192 193static const struct pwm_ops zx_pwm_ops = { 194 .apply = zx_pwm_apply, 195 .get_state = zx_pwm_get_state, 196 .owner = THIS_MODULE, 197}; 198 199static int zx_pwm_probe(struct platform_device *pdev) 200{ 201 struct zx_pwm_chip *zpc; 202 struct resource *res; 203 unsigned int i; 204 int ret; 205 206 zpc = devm_kzalloc(&pdev->dev, sizeof(*zpc), GFP_KERNEL); 207 if (!zpc) 208 return -ENOMEM; 209 210 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 211 zpc->base = devm_ioremap_resource(&pdev->dev, res); 212 if (IS_ERR(zpc->base)) 213 return PTR_ERR(zpc->base); 214 215 zpc->pclk = devm_clk_get(&pdev->dev, "pclk"); 216 if (IS_ERR(zpc->pclk)) 217 return PTR_ERR(zpc->pclk); 218 219 zpc->wclk = devm_clk_get(&pdev->dev, "wclk"); 220 if (IS_ERR(zpc->wclk)) 221 return PTR_ERR(zpc->wclk); 222 223 ret = clk_prepare_enable(zpc->pclk); 224 if (ret) 225 return ret; 226 227 zpc->chip.dev = &pdev->dev; 228 zpc->chip.ops = &zx_pwm_ops; 229 zpc->chip.base = -1; 230 zpc->chip.npwm = 4; 231 zpc->chip.of_xlate = of_pwm_xlate_with_flags; 232 zpc->chip.of_pwm_n_cells = 3; 233 234 /* 235 * PWM devices may be enabled by firmware, and let's disable all of 236 * them initially to save power. 237 */ 238 for (i = 0; i < zpc->chip.npwm; i++) 239 zx_pwm_set_mask(zpc, i, ZX_PWM_MODE, ZX_PWM_EN, 0); 240 241 ret = pwmchip_add(&zpc->chip); 242 if (ret < 0) { 243 dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); 244 return ret; 245 } 246 247 platform_set_drvdata(pdev, zpc); 248 249 return 0; 250} 251 252static int zx_pwm_remove(struct platform_device *pdev) 253{ 254 struct zx_pwm_chip *zpc = platform_get_drvdata(pdev); 255 int ret; 256 257 ret = pwmchip_remove(&zpc->chip); 258 clk_disable_unprepare(zpc->pclk); 259 260 return ret; 261} 262 263static const struct of_device_id zx_pwm_dt_ids[] = { 264 { .compatible = "zte,zx296718-pwm", }, 265 { /* sentinel */ } 266}; 267MODULE_DEVICE_TABLE(of, zx_pwm_dt_ids); 268 269static struct platform_driver zx_pwm_driver = { 270 .driver = { 271 .name = "zx-pwm", 272 .of_match_table = zx_pwm_dt_ids, 273 }, 274 .probe = zx_pwm_probe, 275 .remove = zx_pwm_remove, 276}; 277module_platform_driver(zx_pwm_driver); 278 279MODULE_ALIAS("platform:zx-pwm"); 280MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>"); 281MODULE_DESCRIPTION("ZTE ZX PWM Driver"); 282MODULE_LICENSE("GPL v2");