Received: by 2002:a05:6a10:16a7:0:0:0:0 with SMTP id gp39csp497981pxb; Thu, 12 Nov 2020 08:50:16 -0800 (PST) X-Google-Smtp-Source: ABdhPJyEvF/bxCc6xmsvTTUqYkr2DpZ9rhmw+zxvMAJLJ3rNO36UgZSF4Mib8iUr+tgjfGPqDYE9 X-Received: by 2002:a17:906:52c6:: with SMTP id w6mr142811ejn.199.1605199815832; Thu, 12 Nov 2020 08:50:15 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1605199815; cv=none; d=google.com; s=arc-20160816; b=H4gfGyryc2gSH3SIAW/llpYxFeRFP4dXzyNzvAHA4909qT3gYEdTGJOsHY8QzxzsZ0 o2RpHQGl5fV+RtuZ74F7M5rlAaU8tomh0Oy0eTR+qBjU75PFlaaK2lTIJBZyQDxRernI dDwfSrjUFTa0eM8WLWjnlb9qyqo8/34R3Vu3VxMVjGUe6YO8ZXd7RWFzJMHQqrwUchaq tBzqXHYaMlCBHkgn+ozSu659uW9nvC4UwmqwiLNQ2zudjVCYxjRZjbIeKDs47WgczC8Q bOpWBUJe2kaBos4hNRc39YBYt7qGrOEKUMmeE3k7C5WWEu7baMISA7+d+65b3xUEzxV8 rXSg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=cIIJ3PiWJn6aNmb5SCNmZ1PfYOyHc3UB+Hid0B9eiTI=; b=B79NGAsaEGgaa41YSw7naHq/Gd8Rs9HSnD97f9EqGku9e54DhNHdwnBi12sQESphc3 fFjX6iapP7Jb8YDL/3qtU1Tu7pp/Y+g0fgaXB5DvMKOIRAaXnwJnbS8LnkTwixcS338+ T+dF/ahOwPzwe9g5GQoyjiO9nKxyyisY+KADqMnKfxjh8xhZBfF9D/w3Sbj/JqSjp1tS BNOmKDcJmyNLO8PpSzT+1y6m3a7hr4G22VoJPrkmOf9bsRuncS0Nyc6G+6c2rTZ9la6V cHpvjnu/MjwjR2NCCqZk4g9IK+E9aJ9DIQEnDDDD39IhssFKSKXeSUDQkh23vECXmb25 eCAA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@pqgruber.com header.s=mail header.b=JmpRwnjn; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=pqgruber.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id j6si4197008edr.531.2020.11.12.08.49.52; Thu, 12 Nov 2020 08:50:15 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@pqgruber.com header.s=mail header.b=JmpRwnjn; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=pqgruber.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729271AbgKLQpn (ORCPT + 99 others); Thu, 12 Nov 2020 11:45:43 -0500 Received: from mail.pqgruber.com ([52.59.78.55]:46386 "EHLO mail.pqgruber.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729260AbgKLQpl (ORCPT ); Thu, 12 Nov 2020 11:45:41 -0500 Received: from workstation.tuxnet (213-47-165-233.cable.dynamic.surfer.at [213.47.165.233]) by mail.pqgruber.com (Postfix) with ESMTPSA id 6F0BDC7D0FA; Thu, 12 Nov 2020 17:38:31 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pqgruber.com; s=mail; t=1605199111; bh=cIIJ3PiWJn6aNmb5SCNmZ1PfYOyHc3UB+Hid0B9eiTI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JmpRwnjnuXlSABAUlyHfI14K20P9aqUTBjtQftWBSZSnMSsfP/jMxKJ24PpLFnJ0d WUInu+s3Cgh3N6BFfnpyzNYt2pZBX9ocvtIiXnJCErGi8PTcE/0gGd36bKswL6hiyv 64iQd6kfgD5l0YALHBBfDb954uUVDN/ceHS4m4FI= From: Clemens Gruber To: linux-pwm@vger.kernel.org Cc: Thierry Reding , u.kleine-koenig@pengutronix.de, Lee Jones , linux-kernel@vger.kernel.org, Clemens Gruber Subject: [PATCH 2/2] pwm: pca9685: support staggered output ON times Date: Thu, 12 Nov 2020 17:37:51 +0100 Message-Id: <20201112163751.204187-2-clemens.gruber@pqgruber.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201112163751.204187-1-clemens.gruber@pqgruber.com> References: <20201112163751.204187-1-clemens.gruber@pqgruber.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The PCA9685 supports staggered LED output ON times to minimize current surges and reduce EMI. When this new option is enabled, the ON times of each channel are delayed by channel number x counter range / 16, which avoids asserting all enabled outputs at the same counter value while still maintaining the configured duty cycle of each output. Signed-off-by: Clemens Gruber --- drivers/pwm/pwm-pca9685.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index df214758256e..b993231ebb5e 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -75,6 +75,7 @@ struct pca9685 { struct pwm_chip chip; struct regmap *regmap; int period_ns; + bool staggered_outputs; #if IS_ENABLED(CONFIG_GPIOLIB) struct mutex lock; struct gpio_chip gpio; @@ -251,6 +252,7 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, { struct pca9685 *pca = to_pca(chip); unsigned long long duty; + unsigned int on, off; unsigned int reg; int prescale; @@ -286,6 +288,32 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, duty = (PCA9685_COUNTER_RANGE - 1) * (unsigned long long)duty_ns; duty = DIV_ROUND_UP_ULL(duty, period_ns); + if (pca->staggered_outputs && pwm->hwpwm < PCA9685_MAXCHAN) { + if (duty_ns > 0) { + /* + * To reduce EMI, the ON times of each channel are + * spread out evenly within the counter range, while + * still maintaining the configured duty cycle + */ + on = pwm->hwpwm * PCA9685_COUNTER_RANGE / + PCA9685_MAXCHAN; + off = (on + duty) % PCA9685_COUNTER_RANGE; + regmap_write(pca->regmap, LED_N_ON_L(pwm->hwpwm), + on & 0xff); + regmap_write(pca->regmap, LED_N_ON_H(pwm->hwpwm), + (on >> 8) & 0xf); + regmap_write(pca->regmap, LED_N_OFF_L(pwm->hwpwm), + off & 0xff); + regmap_write(pca->regmap, LED_N_OFF_H(pwm->hwpwm), + (off >> 8) & 0xf); + return 0; + } + + /* Clear ON times */ + regmap_write(pca->regmap, LED_N_ON_L(pwm->hwpwm), 0); + regmap_write(pca->regmap, LED_N_ON_H(pwm->hwpwm), 0); + } + if (pwm->hwpwm >= PCA9685_MAXCHAN) reg = PCA9685_ALL_LED_OFF_L; else @@ -416,6 +444,9 @@ static int pca9685_pwm_probe(struct i2c_client *client, reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3); regmap_write(pca->regmap, PCA9685_MODE1, reg); + pca->staggered_outputs = device_property_read_bool( + &client->dev, "staggered-outputs"); + /* Clear all "full off" bits */ regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, 0); regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, 0); -- 2.29.2