18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Linaro Ltd. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Linus Walleij <linus.walleij@linaro.org> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/bitops.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/err.h> 118c2ecf20Sopenharmony_ci#include <linux/mfd/stmpe.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/of.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci#include <linux/pwm.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define STMPE24XX_PWMCS 0x30 198c2ecf20Sopenharmony_ci#define PWMCS_EN_PWM0 BIT(0) 208c2ecf20Sopenharmony_ci#define PWMCS_EN_PWM1 BIT(1) 218c2ecf20Sopenharmony_ci#define PWMCS_EN_PWM2 BIT(2) 228c2ecf20Sopenharmony_ci#define STMPE24XX_PWMIC0 0x38 238c2ecf20Sopenharmony_ci#define STMPE24XX_PWMIC1 0x39 248c2ecf20Sopenharmony_ci#define STMPE24XX_PWMIC2 0x3a 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define STMPE_PWM_24XX_PINBASE 21 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct stmpe_pwm { 298c2ecf20Sopenharmony_ci struct stmpe *stmpe; 308c2ecf20Sopenharmony_ci struct pwm_chip chip; 318c2ecf20Sopenharmony_ci u8 last_duty; 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic inline struct stmpe_pwm *to_stmpe_pwm(struct pwm_chip *chip) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci return container_of(chip, struct stmpe_pwm, chip); 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic int stmpe_24xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct stmpe_pwm *stmpe_pwm = to_stmpe_pwm(chip); 428c2ecf20Sopenharmony_ci u8 value; 438c2ecf20Sopenharmony_ci int ret; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci ret = stmpe_reg_read(stmpe_pwm->stmpe, STMPE24XX_PWMCS); 468c2ecf20Sopenharmony_ci if (ret < 0) { 478c2ecf20Sopenharmony_ci dev_err(chip->dev, "error reading PWM#%u control\n", 488c2ecf20Sopenharmony_ci pwm->hwpwm); 498c2ecf20Sopenharmony_ci return ret; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci value = ret | BIT(pwm->hwpwm); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci ret = stmpe_reg_write(stmpe_pwm->stmpe, STMPE24XX_PWMCS, value); 558c2ecf20Sopenharmony_ci if (ret) { 568c2ecf20Sopenharmony_ci dev_err(chip->dev, "error writing PWM#%u control\n", 578c2ecf20Sopenharmony_ci pwm->hwpwm); 588c2ecf20Sopenharmony_ci return ret; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return 0; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic void stmpe_24xx_pwm_disable(struct pwm_chip *chip, 658c2ecf20Sopenharmony_ci struct pwm_device *pwm) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct stmpe_pwm *stmpe_pwm = to_stmpe_pwm(chip); 688c2ecf20Sopenharmony_ci u8 value; 698c2ecf20Sopenharmony_ci int ret; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci ret = stmpe_reg_read(stmpe_pwm->stmpe, STMPE24XX_PWMCS); 728c2ecf20Sopenharmony_ci if (ret < 0) { 738c2ecf20Sopenharmony_ci dev_err(chip->dev, "error reading PWM#%u control\n", 748c2ecf20Sopenharmony_ci pwm->hwpwm); 758c2ecf20Sopenharmony_ci return; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci value = ret & ~BIT(pwm->hwpwm); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci ret = stmpe_reg_write(stmpe_pwm->stmpe, STMPE24XX_PWMCS, value); 818c2ecf20Sopenharmony_ci if (ret) { 828c2ecf20Sopenharmony_ci dev_err(chip->dev, "error writing PWM#%u control\n", 838c2ecf20Sopenharmony_ci pwm->hwpwm); 848c2ecf20Sopenharmony_ci return; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* STMPE 24xx PWM instructions */ 898c2ecf20Sopenharmony_ci#define SMAX 0x007f 908c2ecf20Sopenharmony_ci#define SMIN 0x00ff 918c2ecf20Sopenharmony_ci#define GTS 0x0000 928c2ecf20Sopenharmony_ci#define LOAD BIT(14) /* Only available on 2403 */ 938c2ecf20Sopenharmony_ci#define RAMPUP 0x0000 948c2ecf20Sopenharmony_ci#define RAMPDOWN BIT(7) 958c2ecf20Sopenharmony_ci#define PRESCALE_512 BIT(14) 968c2ecf20Sopenharmony_ci#define STEPTIME_1 BIT(8) 978c2ecf20Sopenharmony_ci#define BRANCH (BIT(15) | BIT(13)) 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 1008c2ecf20Sopenharmony_ci int duty_ns, int period_ns) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct stmpe_pwm *stmpe_pwm = to_stmpe_pwm(chip); 1038c2ecf20Sopenharmony_ci unsigned int i, pin; 1048c2ecf20Sopenharmony_ci u16 program[3] = { 1058c2ecf20Sopenharmony_ci SMAX, 1068c2ecf20Sopenharmony_ci GTS, 1078c2ecf20Sopenharmony_ci GTS, 1088c2ecf20Sopenharmony_ci }; 1098c2ecf20Sopenharmony_ci u8 offset; 1108c2ecf20Sopenharmony_ci int ret; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* Make sure we are disabled */ 1138c2ecf20Sopenharmony_ci if (pwm_is_enabled(pwm)) { 1148c2ecf20Sopenharmony_ci stmpe_24xx_pwm_disable(chip, pwm); 1158c2ecf20Sopenharmony_ci } else { 1168c2ecf20Sopenharmony_ci /* Connect the PWM to the pin */ 1178c2ecf20Sopenharmony_ci pin = pwm->hwpwm; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* On STMPE2401 and 2403 pins 21,22,23 are used */ 1208c2ecf20Sopenharmony_ci if (stmpe_pwm->stmpe->partnum == STMPE2401 || 1218c2ecf20Sopenharmony_ci stmpe_pwm->stmpe->partnum == STMPE2403) 1228c2ecf20Sopenharmony_ci pin += STMPE_PWM_24XX_PINBASE; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci ret = stmpe_set_altfunc(stmpe_pwm->stmpe, BIT(pin), 1258c2ecf20Sopenharmony_ci STMPE_BLOCK_PWM); 1268c2ecf20Sopenharmony_ci if (ret) { 1278c2ecf20Sopenharmony_ci dev_err(chip->dev, "unable to connect PWM#%u to pin\n", 1288c2ecf20Sopenharmony_ci pwm->hwpwm); 1298c2ecf20Sopenharmony_ci return ret; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* STMPE24XX */ 1348c2ecf20Sopenharmony_ci switch (pwm->hwpwm) { 1358c2ecf20Sopenharmony_ci case 0: 1368c2ecf20Sopenharmony_ci offset = STMPE24XX_PWMIC0; 1378c2ecf20Sopenharmony_ci break; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci case 1: 1408c2ecf20Sopenharmony_ci offset = STMPE24XX_PWMIC1; 1418c2ecf20Sopenharmony_ci break; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci case 2: 1448c2ecf20Sopenharmony_ci offset = STMPE24XX_PWMIC2; 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci default: 1488c2ecf20Sopenharmony_ci /* Should not happen as npwm is 3 */ 1498c2ecf20Sopenharmony_ci return -ENODEV; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "PWM#%u: config duty %d ns, period %d ns\n", 1538c2ecf20Sopenharmony_ci pwm->hwpwm, duty_ns, period_ns); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (duty_ns == 0) { 1568c2ecf20Sopenharmony_ci if (stmpe_pwm->stmpe->partnum == STMPE2401) 1578c2ecf20Sopenharmony_ci program[0] = SMAX; /* off all the time */ 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (stmpe_pwm->stmpe->partnum == STMPE2403) 1608c2ecf20Sopenharmony_ci program[0] = LOAD | 0xff; /* LOAD 0xff */ 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci stmpe_pwm->last_duty = 0x00; 1638c2ecf20Sopenharmony_ci } else if (duty_ns == period_ns) { 1648c2ecf20Sopenharmony_ci if (stmpe_pwm->stmpe->partnum == STMPE2401) 1658c2ecf20Sopenharmony_ci program[0] = SMIN; /* on all the time */ 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (stmpe_pwm->stmpe->partnum == STMPE2403) 1688c2ecf20Sopenharmony_ci program[0] = LOAD | 0x00; /* LOAD 0x00 */ 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci stmpe_pwm->last_duty = 0xff; 1718c2ecf20Sopenharmony_ci } else { 1728c2ecf20Sopenharmony_ci u8 value, last = stmpe_pwm->last_duty; 1738c2ecf20Sopenharmony_ci unsigned long duty; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* 1768c2ecf20Sopenharmony_ci * Counter goes from 0x00 to 0xff repeatedly at 32768 Hz, 1778c2ecf20Sopenharmony_ci * (means a period of 30517 ns) then this is compared to the 1788c2ecf20Sopenharmony_ci * counter from the ramp, if this is >= PWM counter the output 1798c2ecf20Sopenharmony_ci * is high. With LOAD we can define how much of the cycle it 1808c2ecf20Sopenharmony_ci * is on. 1818c2ecf20Sopenharmony_ci * 1828c2ecf20Sopenharmony_ci * Prescale = 0 -> 2 kHz -> T = 1/f = 488281.25 ns 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* Scale to 0..0xff */ 1868c2ecf20Sopenharmony_ci duty = duty_ns * 256; 1878c2ecf20Sopenharmony_ci duty = DIV_ROUND_CLOSEST(duty, period_ns); 1888c2ecf20Sopenharmony_ci value = duty; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (value == last) { 1918c2ecf20Sopenharmony_ci /* Run the old program */ 1928c2ecf20Sopenharmony_ci if (pwm_is_enabled(pwm)) 1938c2ecf20Sopenharmony_ci stmpe_24xx_pwm_enable(chip, pwm); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return 0; 1968c2ecf20Sopenharmony_ci } else if (stmpe_pwm->stmpe->partnum == STMPE2403) { 1978c2ecf20Sopenharmony_ci /* STMPE2403 can simply set the right PWM value */ 1988c2ecf20Sopenharmony_ci program[0] = LOAD | value; 1998c2ecf20Sopenharmony_ci program[1] = 0x0000; 2008c2ecf20Sopenharmony_ci } else if (stmpe_pwm->stmpe->partnum == STMPE2401) { 2018c2ecf20Sopenharmony_ci /* STMPE2401 need a complex program */ 2028c2ecf20Sopenharmony_ci u16 incdec = 0x0000; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (last < value) 2058c2ecf20Sopenharmony_ci /* Count up */ 2068c2ecf20Sopenharmony_ci incdec = RAMPUP | (value - last); 2078c2ecf20Sopenharmony_ci else 2088c2ecf20Sopenharmony_ci /* Count down */ 2098c2ecf20Sopenharmony_ci incdec = RAMPDOWN | (last - value); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* Step to desired value, smoothly */ 2128c2ecf20Sopenharmony_ci program[0] = PRESCALE_512 | STEPTIME_1 | incdec; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* Loop eternally to 0x00 */ 2158c2ecf20Sopenharmony_ci program[1] = BRANCH; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci dev_dbg(chip->dev, 2198c2ecf20Sopenharmony_ci "PWM#%u: value = %02x, last_duty = %02x, program=%04x,%04x,%04x\n", 2208c2ecf20Sopenharmony_ci pwm->hwpwm, value, last, program[0], program[1], 2218c2ecf20Sopenharmony_ci program[2]); 2228c2ecf20Sopenharmony_ci stmpe_pwm->last_duty = value; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* 2268c2ecf20Sopenharmony_ci * We can write programs of up to 64 16-bit words into this channel. 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(program); i++) { 2298c2ecf20Sopenharmony_ci u8 value; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci value = (program[i] >> 8) & 0xff; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci ret = stmpe_reg_write(stmpe_pwm->stmpe, offset, value); 2348c2ecf20Sopenharmony_ci if (ret) { 2358c2ecf20Sopenharmony_ci dev_err(chip->dev, "error writing register %02x: %d\n", 2368c2ecf20Sopenharmony_ci offset, ret); 2378c2ecf20Sopenharmony_ci return ret; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci value = program[i] & 0xff; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci ret = stmpe_reg_write(stmpe_pwm->stmpe, offset, value); 2438c2ecf20Sopenharmony_ci if (ret) { 2448c2ecf20Sopenharmony_ci dev_err(chip->dev, "error writing register %02x: %d\n", 2458c2ecf20Sopenharmony_ci offset, ret); 2468c2ecf20Sopenharmony_ci return ret; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* If we were enabled, re-enable this PWM */ 2518c2ecf20Sopenharmony_ci if (pwm_is_enabled(pwm)) 2528c2ecf20Sopenharmony_ci stmpe_24xx_pwm_enable(chip, pwm); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* Sleep for 200ms so we're sure it will take effect */ 2558c2ecf20Sopenharmony_ci msleep(200); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "programmed PWM#%u, %u bytes\n", pwm->hwpwm, i); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci return 0; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic const struct pwm_ops stmpe_24xx_pwm_ops = { 2638c2ecf20Sopenharmony_ci .config = stmpe_24xx_pwm_config, 2648c2ecf20Sopenharmony_ci .enable = stmpe_24xx_pwm_enable, 2658c2ecf20Sopenharmony_ci .disable = stmpe_24xx_pwm_disable, 2668c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2678c2ecf20Sopenharmony_ci}; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int __init stmpe_pwm_probe(struct platform_device *pdev) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); 2728c2ecf20Sopenharmony_ci struct stmpe_pwm *pwm; 2738c2ecf20Sopenharmony_ci int ret; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); 2768c2ecf20Sopenharmony_ci if (!pwm) 2778c2ecf20Sopenharmony_ci return -ENOMEM; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci pwm->stmpe = stmpe; 2808c2ecf20Sopenharmony_ci pwm->chip.dev = &pdev->dev; 2818c2ecf20Sopenharmony_ci pwm->chip.base = -1; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (stmpe->partnum == STMPE2401 || stmpe->partnum == STMPE2403) { 2848c2ecf20Sopenharmony_ci pwm->chip.ops = &stmpe_24xx_pwm_ops; 2858c2ecf20Sopenharmony_ci pwm->chip.npwm = 3; 2868c2ecf20Sopenharmony_ci } else { 2878c2ecf20Sopenharmony_ci if (stmpe->partnum == STMPE1601) 2888c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "STMPE1601 not yet supported\n"); 2898c2ecf20Sopenharmony_ci else 2908c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unknown STMPE PWM\n"); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return -ENODEV; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci ret = stmpe_enable(stmpe, STMPE_BLOCK_PWM); 2968c2ecf20Sopenharmony_ci if (ret) 2978c2ecf20Sopenharmony_ci return ret; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci ret = pwmchip_add(&pwm->chip); 3008c2ecf20Sopenharmony_ci if (ret) { 3018c2ecf20Sopenharmony_ci stmpe_disable(stmpe, STMPE_BLOCK_PWM); 3028c2ecf20Sopenharmony_ci return ret; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, pwm); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci return 0; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic struct platform_driver stmpe_pwm_driver = { 3118c2ecf20Sopenharmony_ci .driver = { 3128c2ecf20Sopenharmony_ci .name = "stmpe-pwm", 3138c2ecf20Sopenharmony_ci }, 3148c2ecf20Sopenharmony_ci}; 3158c2ecf20Sopenharmony_cibuiltin_platform_driver_probe(stmpe_pwm_driver, stmpe_pwm_probe); 316