From patchwork Wed Feb 28 13:32:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dimitri Fedrau X-Patchwork-Id: 207858 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:a81b:b0:108:e6aa:91d0 with SMTP id bq27csp3347302dyb; Wed, 28 Feb 2024 05:33:43 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCUs1TGzZItyR0SBEJgeBld5ty0kDnh8xc4pXYExxT+WjdFvVrZxJ0odXdAp3oI8FQjq85vaS+rJegPHxvTF0tpASTwG8Q== X-Google-Smtp-Source: AGHT+IFFLjczFWcfSgsFmMOV/vmjISsI1a368R2ZxUK4Um1mnsGSWdL8OBJSDVhulFjIwctBceu+ X-Received: by 2002:a05:6402:14d4:b0:565:dce3:66fd with SMTP id f20-20020a05640214d400b00565dce366fdmr6889345edx.23.1709127223160; Wed, 28 Feb 2024 05:33:43 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1709127223; cv=pass; d=google.com; s=arc-20160816; b=LFv84iY7O/W/dEQ6aXPvurjJozBvRi0UgD8YjtmG3YeZMyX5gJkTW0EHudxxH/EGqH 7+74RnCm2cjVzPVkjJYovR03dS07Rr1u645fydPVTYEm8RKNYVCXLqGHPbe/S4ksLlNz P8oggnm7/Pkli7o+NhBOGBb1ixugTz1dxsjVF4FxMGs2OQerqbZ1ZPcBTrzHQcxXV5/2 pbcXT/ASiERjdloJgMesPxzPZNpyzW93sGpgY/feEE36zZiBI7lnOVZsQxqWR0+Qxb/+ T4NFI4eGbcpRG7cRbEshENRW+tpVz+zCFHWWi9iOU9BO+MpyNYlox10KvtkPj+jFxuPX +tiA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=6Rqdfw7u5pplnc2e2TFtlnNGF+ckTKLmulF+IZmE6Uw=; fh=qLsxS2ZdSXALm8yy1EAviy+V1C4u0yKeWcydKRkDO+Q=; b=f9kuZPvhQofyxcX0AXUZZd5OmLL/SCn3mnRsd2ciqrlQeyV3CLer0GH/3+PwPTKtGt eN+WWH/JqXaQiZGFKSVozEXhq2AAAX7Fx5PQHDQFjznYU5GHjYrj/e56nl9DH5xnGb29 Bf+dldHIOYllERHUMFeW1OOz2UBRzxUWCmWYew3Cmpjyu0vGHs3ywslrYif35ARYYLbk ePv+f+Y5AGfsNzV3CLDjYgTAdNuAz+PgFfhlXkz6+n/5HVxbSSHA10Zgyw3ePzmnmL6y VXBR3OA2GFT79WaZfjboYEHwiEft3r8/80udniC+t9Sh2RTAD6+2Ysivy0nOnUQ4SfhP fBiw==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=FzXsiAvL; arc=pass (i=1 spf=pass spfdomain=gmail.com dkim=pass dkdomain=gmail.com dmarc=pass fromdomain=gmail.com); spf=pass (google.com: domain of linux-kernel+bounces-85098-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-85098-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [2604:1380:4601:e00::3]) by mx.google.com with ESMTPS id y18-20020aa7ccd2000000b005661b5a14cesi1746082edt.151.2024.02.28.05.33.42 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Feb 2024 05:33:43 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-85098-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) client-ip=2604:1380:4601:e00::3; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=FzXsiAvL; arc=pass (i=1 spf=pass spfdomain=gmail.com dkim=pass dkdomain=gmail.com dmarc=pass fromdomain=gmail.com); spf=pass (google.com: domain of linux-kernel+bounces-85098-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-85098-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id 9BEFA1F28635 for ; Wed, 28 Feb 2024 13:33:42 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id D79A8153BD1; Wed, 28 Feb 2024 13:33:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="FzXsiAvL" Received: from mail-ej1-f53.google.com (mail-ej1-f53.google.com [209.85.218.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7508214F9E5; Wed, 28 Feb 2024 13:32:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1709127178; cv=none; b=MhipYdnG63972ha/1a3va6kyXHG/V2yq4rPVXdom0Gy+RQMmPkBlO0xAbzm7zy+vr/kFYjNSPjOWp+U/79wWRDjTMGRbR55FycyoJacVLNrGoZLM5cft/D6edhuh+xuXLad3IXOQKIlxHBFVFUCfcr5vAops+CU5RYJAy8rDkCs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1709127178; c=relaxed/simple; bh=BEB7qWDqpMw22mTCQUG5lw1gg9QbrSUF0oqtCMqWoC8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=MhK+9M9gLQceGBhDpwRL1LRMwCdLAD43LFbcxEtFW0fWIudV9DusL0Np/I8+ktl8UXFcoUH0M/Giq0PeV4kniw1+eE6ik4q6/kP4RuFuBUSUWW2qkm1jGlayfeGgPhGQHYxrgrf7Ty04zIbhCHfTgjN6KD1OYrn+pngp0FNGSyo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=FzXsiAvL; arc=none smtp.client-ip=209.85.218.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ej1-f53.google.com with SMTP id a640c23a62f3a-a4417fa396fso44671266b.1; Wed, 28 Feb 2024 05:32:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1709127175; x=1709731975; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=6Rqdfw7u5pplnc2e2TFtlnNGF+ckTKLmulF+IZmE6Uw=; b=FzXsiAvLMPLBcf/HhxaBj0DyMKh9rz9XKDVz0We0C7xwTNCi7ldPjlgbt4t+AKuzmm ggp11jZnlqsIZoJYZ63txkCXbHeOccpgaQg8tCRyyU8O4LNysFq+k7Wt7RMXWR6eCjBY 3tfQA1QhVvcRxtY0qTA2I/wFUoePCHL9vHE9gJdgBIqeldDPvz9f/ee5oxJZI13JeUls vAH3o+GWls9ZpYZZgnzhqGt+4rgBCK/w9kPU+YNLwKKitpGechp4Lm9801dAzoSv0F67 zuGoXIwEFOTTyCS+CjLYxMKMpOywmL6bmjVT/fgaMOSYTF+Alxi2GC+tuxgMqYG4B6gU YuKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1709127175; x=1709731975; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=6Rqdfw7u5pplnc2e2TFtlnNGF+ckTKLmulF+IZmE6Uw=; b=WdDXYFyHb3GQ7ChfU+3BPAe6cQuY2O3EHdZzcJi1ZoJLeb5H4IaXmDZ6MkV2AlVk0j 5YvSF5fFGNfEDCmDP1QDrTTAv/oRh8SJstJj2Gwn/xS66g8wsYmJjCvhENt31JtFC5M+ Nq0lRgnukwoF7A4RwkrnvoBxYCac3NJqOEScdvfgUpbRrS9WFr27CQt30E40ZZcwDVPA 35X9A7twepUPDgUCXUY7GAMu45lIpWGLy+t74zYoM6AumtMZDfoW/HLpS4PLn7G288+W N+YVvOLpTrzUFRI3hvflx+JnjWSA6dbqgt3tnlliXS8SfDWjctCATp6EFws8DZKC4H/D VNgg== X-Forwarded-Encrypted: i=1; AJvYcCXHcITswyI0bhobE1IzeIc0EPSkDZAS8RDChkQdBUp6XjXZFKGm+kGl4AjO+bebaPGLAN3ojVmFPRsE0QK/G+T3xa/oZr4Z3bib3Nr1MXQUNb29ioOc2QVVcfeiRSF5cjVgKU6N7AOF X-Gm-Message-State: AOJu0Yza1idgKL6FRLBsTJwhBVTgax3EogcC4zX7QkgUX2UehW328Ipi HdS32lGBdBBdhfK3Kw2eb+DRm8+7OI/dp2+6rHodmUn4n/NvGyWN7qpIgZJd X-Received: by 2002:a17:906:57c9:b0:a44:856:1368 with SMTP id u9-20020a17090657c900b00a4408561368mr987997ejr.12.1709127174675; Wed, 28 Feb 2024 05:32:54 -0800 (PST) Received: from debian.fritz.box ([93.184.186.109]) by smtp.gmail.com with ESMTPSA id vx5-20020a170907a78500b00a3f20a8d2f6sm1856952ejc.112.2024.02.28.05.32.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Feb 2024 05:32:52 -0800 (PST) From: Dimitri Fedrau To: Cc: Dimitri Fedrau , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , linux-kernel@vger.kernel.org, linux-pwm@vger.kernel.org Subject: [PATCH 2/3] pwm: add support for NXPs high-side switch MC33XS2410 Date: Wed, 28 Feb 2024 14:32:34 +0100 Message-Id: <20240228133236.748225-3-dima.fedrau@gmail.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240228133236.748225-1-dima.fedrau@gmail.com> References: <20240228133236.748225-1-dima.fedrau@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1792149747286183303 X-GMAIL-MSGID: 1792149786974653963 The MC33XS2410 is a four channel high-side switch. Featuring advanced monitoring and control function, the device is operational from 3.0 V to 60 V. The device is controlled by SPI port for configuration. Signed-off-by: Dimitri Fedrau --- drivers/pwm/Kconfig | 12 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-mc33xs2410.c | 324 +++++++++++++++++++++++++++++++++++ 3 files changed, 337 insertions(+) create mode 100644 drivers/pwm/pwm-mc33xs2410.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 4b956d661755..da7048899ea7 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -384,6 +384,18 @@ config PWM_LPSS_PLATFORM To compile this driver as a module, choose M here: the module will be called pwm-lpss-platform. +config PWM_MC33XS2410 + tristate "MC33XS2410 PWM support" + depends on OF + depends on SPI + help + NXP MC33XS2410 high-side switch driver. The MC33XS2410 is a four + channel high-side switch. The device is operational from 3.0 V + to 60 V. The device is controlled by SPI port for configuration. + + To compile this driver as a module, choose M here: the module + will be called pwm-mc33xs2410. + config PWM_MESON tristate "Amlogic Meson PWM driver" depends on ARCH_MESON || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index c5ec9e168ee7..6e7904e82c42 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o +obj-$(CONFIG_PWM_MC33XS2410) += pwm-mc33xs2410.o obj-$(CONFIG_PWM_MESON) += pwm-meson.o obj-$(CONFIG_PWM_MEDIATEK) += pwm-mediatek.o obj-$(CONFIG_PWM_MICROCHIP_CORE) += pwm-microchip-core.o diff --git a/drivers/pwm/pwm-mc33xs2410.c b/drivers/pwm/pwm-mc33xs2410.c new file mode 100644 index 000000000000..35753039da6b --- /dev/null +++ b/drivers/pwm/pwm-mc33xs2410.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Liebherr-Electronics and Drives GmbH + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define MC33XS2410_GLB_CTRL 0x00 +#define MC33XS2410_GLB_CTRL_MODE_MASK GENMASK(7, 6) +#define MC33XS2410_GLB_CTRL_NORMAL_MODE BIT(6) +#define MC33XS2410_GLB_CTRL_SAFE_MODE BIT(7) +#define MC33XS2410_OUT1_4_CTRL 0x02 +#define MC33XS2410_PWM_CTRL1 0x05 +#define MC33XS2410_PWM_CTRL1_POL_INV(x) BIT(x) +#define MC33XS2410_PWM_CTRL3 0x07 +#define MC33XS2410_PWM_CTRL3_EN(x) BIT(4 + (x)) +#define MC33XS2410_PWM_CTRL3_EN_MASK GENMASK(7, 4) +#define MC33XS2410_PWM_FREQ1 0x08 +#define MC33XS2410_PWM_FREQ(x) (MC33XS2410_PWM_FREQ1 + (x)) +#define MC33XS2410_PWM_FREQ_STEP_MASK GENMASK(7, 6) +#define MC33XS2410_PWM_FREQ_MASK GENMASK(5, 0) +#define MC33XS2410_PWM_DC1 0x0c +#define MC33XS2410_PWM_DC(x) (MC33XS2410_PWM_DC1 + (x)) +#define MC33XS2410_WDT 0x14 + +#define MC33XS2410_IN_OUT_STA 0x01 +#define MC33XS2410_IN_OUT_STA_OUT_EN(x) BIT(4 + (x)) + +#define MC33XS2410_WR_FLAG BIT(7) +#define MC33XS2410_RD_CTRL_FLAG BIT(7) +#define MC33XS2410_RD_DATA_MASK GENMASK(13, 0) + +#define MC33XS2410_PERIOD_MAX 0 +#define MC33XS2410_PERIOD_MIN 1 + +struct mc33xs2410_pwm { + struct pwm_chip chip; + struct spi_device *spi; + struct mutex lock; +}; + +enum mc33xs2410_freq_steps { + STEP_05HZ, + STEP_2HZ, + STEP_8HZ, + STEP_32HZ, +}; + +/* + * When outputs are controlled by SPI, the device supports four frequency ranges + * with following steps: + * - 0.5 Hz steps from 0.5 Hz to 32 Hz + * - 2 Hz steps from 2 Hz to 128 Hz + * - 8 Hz steps from 8 Hz to 512 Hz + * - 32 Hz steps from 32 Hz to 2048 Hz + * Below are the minimum and maximum frequencies converted to periods in ns for + * each of the four frequency ranges. + */ +static const u32 mc33xs2410_period[4][2] = { + [STEP_05HZ] = { 2000000000, 31250000 }, + [STEP_2HZ] = { 500000000, 7812500 }, + [STEP_8HZ] = { 125000000, 1953125 }, + [STEP_32HZ] = { 31250000, 488281 }, +}; + +static struct mc33xs2410_pwm *mc33xs2410_pwm_from_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct mc33xs2410_pwm, chip); +} + +static int mc33xs2410_write_reg(struct spi_device *spi, u8 reg, u8 val) +{ + u8 tx[2]; + + tx[0] = reg | MC33XS2410_WR_FLAG; + tx[1] = val; + + return spi_write(spi, tx, 2); +} + +static int mc33xs2410_read_reg(struct spi_device *spi, u8 reg, bool ctrl) +{ + u8 tx[2], rx[2]; + int ret; + + tx[0] = reg; + tx[1] = ctrl ? MC33XS2410_RD_CTRL_FLAG : 0; + + ret = spi_write(spi, tx, 2); + if (ret < 0) + return ret; + + ret = spi_read(spi, rx, 2); + if (ret < 0) + return ret; + + return FIELD_GET(MC33XS2410_RD_DATA_MASK, get_unaligned_be16(rx)); +} + +static int mc33xs2410_read_reg_ctrl(struct spi_device *spi, u8 reg) +{ + return mc33xs2410_read_reg(spi, reg, true); +} + +static int mc33xs2410_modify_reg(struct spi_device *spi, u8 reg, u8 mask, u8 val) +{ + int ret; + + ret = mc33xs2410_read_reg_ctrl(spi, reg); + if (ret < 0) + return ret; + + ret &= ~mask; + ret |= val & mask; + + return mc33xs2410_write_reg(spi, reg, ret); +} + +static int mc33xs2410_read_reg_diag(struct spi_device *spi, u8 reg) +{ + return mc33xs2410_read_reg(spi, reg, false); +} + +static u8 mc33xs2410_pwm_get_freq(const struct pwm_state *state) +{ + u32 period, freq, max, min; + int step; + u8 ret; + + period = state->period; + /* + * Check if period is within the limits of each of the four frequency + * ranges, starting with the highest frequency(lowest period). Higher + * frequencies are represented with better resolution by the device. + */ + for (step = STEP_32HZ; step >= STEP_05HZ; step--) { + min = mc33xs2410_period[step][MC33XS2410_PERIOD_MIN]; + max = mc33xs2410_period[step][MC33XS2410_PERIOD_MAX]; + if ((period <= max) && (period >= min)) + break; + } + + freq = DIV_ROUND_CLOSEST(max, period) - 1; + ret = FIELD_PREP(MC33XS2410_PWM_FREQ_MASK, freq); + return (ret | FIELD_PREP(MC33XS2410_PWM_FREQ_STEP_MASK, step)); +} + +static int mc33xs2410_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct mc33xs2410_pwm *mc33xs2410 = mc33xs2410_pwm_from_chip(chip); + struct spi_device *spi = mc33xs2410->spi; + u8 mask, val; + int ret; + + if (state->period > mc33xs2410_period[STEP_05HZ][MC33XS2410_PERIOD_MAX]) + return -EINVAL; + + if (state->period < mc33xs2410_period[STEP_32HZ][MC33XS2410_PERIOD_MIN]) + return -EINVAL; + + guard(mutex)(&mc33xs2410->lock); + mask = MC33XS2410_PWM_CTRL1_POL_INV(pwm->hwpwm); + val = (state->polarity == PWM_POLARITY_INVERSED) ? mask : 0; + ret = mc33xs2410_modify_reg(spi, MC33XS2410_PWM_CTRL1, mask, val); + if (ret < 0) + return ret; + + ret = mc33xs2410_write_reg(spi, MC33XS2410_PWM_FREQ(pwm->hwpwm), + mc33xs2410_pwm_get_freq(state)); + if (ret < 0) + return ret; + + ret = mc33xs2410_write_reg(spi, MC33XS2410_PWM_DC(pwm->hwpwm), + pwm_get_relative_duty_cycle(state, 255)); + if (ret < 0) + return ret; + + mask = MC33XS2410_PWM_CTRL3_EN(pwm->hwpwm); + val = (state->enabled) ? mask : 0; + return mc33xs2410_modify_reg(spi, MC33XS2410_PWM_CTRL3, mask, val); +} + +static int mc33xs2410_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) +{ + struct mc33xs2410_pwm *mc33xs2410 = mc33xs2410_pwm_from_chip(chip); + struct spi_device *spi = mc33xs2410->spi; + u32 freq, code, steps; + int ret; + + guard(mutex)(&mc33xs2410->lock); + ret = mc33xs2410_read_reg_ctrl(spi, MC33XS2410_PWM_CTRL1); + if (ret < 0) + return ret; + + state->polarity = (ret & MC33XS2410_PWM_CTRL1_POL_INV(pwm->hwpwm)) ? + PWM_POLARITY_INVERSED : PWM_POLARITY_NORMAL; + + ret = mc33xs2410_read_reg_ctrl(spi, MC33XS2410_PWM_FREQ(pwm->hwpwm)); + if (ret < 0) + return ret; + + /* Lowest frequency steps are starting with 0.5Hz, scale them by two. */ + steps = (FIELD_GET(MC33XS2410_PWM_FREQ_STEP_MASK, ret) * 2) << 1; + code = FIELD_GET(MC33XS2410_PWM_FREQ_MASK, ret); + /* Frequency = (code + 1) x steps */ + freq = (code + 1) * steps; + /* Convert frequency to period in ns, considering scaled steps value. */ + state->period = 2000000000ULL / (freq); + + ret = mc33xs2410_read_reg_ctrl(spi, MC33XS2410_PWM_DC(pwm->hwpwm)); + if (ret < 0) + return ret; + + ret = pwm_set_relative_duty_cycle(state, ret, 255); + if (ret) + return ret; + + ret = mc33xs2410_read_reg_diag(spi, MC33XS2410_IN_OUT_STA); + if (ret < 0) + return ret; + + state->enabled = !!(ret & MC33XS2410_IN_OUT_STA_OUT_EN(pwm->hwpwm)); + + return 0; +} + +static const struct pwm_ops mc33xs2410_pwm_ops = { + .apply = mc33xs2410_pwm_apply, + .get_state = mc33xs2410_pwm_get_state, +}; + +static int mc33xs2410_reset(struct device *dev) +{ + struct gpio_desc *reset_gpio; + + reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR_OR_NULL(reset_gpio)) + return PTR_ERR_OR_ZERO(reset_gpio); + + fsleep(1000); + gpiod_set_value_cansleep(reset_gpio, 0); + /* Wake-up time */ + fsleep(10000); + + return 0; +} + +static int mc33xs2410_probe(struct spi_device *spi) +{ + struct mc33xs2410_pwm *mc33xs2410; + struct device *dev = &spi->dev; + int ret; + + mc33xs2410 = devm_kzalloc(&spi->dev, sizeof(*mc33xs2410), GFP_KERNEL); + if (!mc33xs2410) + return -ENOMEM; + + mc33xs2410->chip.dev = dev; + mc33xs2410->chip.ops = &mc33xs2410_pwm_ops; + mc33xs2410->chip.npwm = 4; + mc33xs2410->spi = spi; + mutex_init(&mc33xs2410->lock); + + ret = mc33xs2410_reset(dev); + if (ret) + return ret; + + /* Disable watchdog */ + ret = mc33xs2410_write_reg(spi, MC33XS2410_WDT, 0x0); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to disable watchdog\n"); + + /* Transitition to normal mode */ + ret = mc33xs2410_modify_reg(spi, MC33XS2410_GLB_CTRL, + MC33XS2410_GLB_CTRL_MODE_MASK, + MC33XS2410_GLB_CTRL_NORMAL_MODE); + if (ret < 0) + return dev_err_probe(dev, ret, + "Failed to transition to normal mode\n"); + + ret = devm_pwmchip_add(dev, &mc33xs2410->chip); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to add pwm chip\n"); + + return 0; +} + +static const struct spi_device_id mc33xs2410_spi_id[] = { + { "mc33xs2410", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, mc33xs2410_spi_id); + +static const struct of_device_id mc33xs2410_of_match[] = { + { .compatible = "nxp,mc33xs2410" }, + { } +}; +MODULE_DEVICE_TABLE(of, mc33xs2410_of_match); + +static struct spi_driver mc33xs2410_driver = { + .driver = { + .name = "mc33xs2410-pwm", + .of_match_table = mc33xs2410_of_match, + }, + .probe = mc33xs2410_probe, + .id_table = mc33xs2410_spi_id, +}; +module_spi_driver(mc33xs2410_driver); + +MODULE_DESCRIPTION("NXP MC33XS2410 high-side switch driver"); +MODULE_AUTHOR("Dimitri Fedrau "); +MODULE_LICENSE("GPL"); From patchwork Wed Feb 28 13:32:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dimitri Fedrau X-Patchwork-Id: 207859 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:a81b:b0:108:e6aa:91d0 with SMTP id bq27csp3347341dyb; Wed, 28 Feb 2024 05:33:47 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCV0D/HthwUZmqG7cd23L0sCOhHZ2G0yrahBbtUS9BO/BRg7K1tsCUgSUUrhC79VHyTOAX7RVaziaNnpAHzASjBb2dGsoQ== X-Google-Smtp-Source: AGHT+IHHtWTmruubaW8718qMXE1YHHJmCWnCj02/A3jeXMXrzrBbSj6N0hwOnDuGOS5sEAmMR3Za X-Received: by 2002:a05:620a:a4c:b0:787:a7d0:25a5 with SMTP id j12-20020a05620a0a4c00b00787a7d025a5mr4580418qka.28.1709127227270; Wed, 28 Feb 2024 05:33:47 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1709127227; cv=pass; d=google.com; s=arc-20160816; b=vwzg2a17JoQODHa7FM/iGnDkYhamjfBrLVYIGBw4AyeoLr7+jnJpfr0ZGg5HapTgzv kHTllY82Ml5S1F+qxuc8PY9dPZXTGHR089pJg6X7mZPyDYVK+YoNGDQ9zpNPoTgh94ST nTWz317jN3BadMFnYko31JrF46baVjCboRAb4SfZGCIKPGlcBmk41HEtYhnjO22ds3WA xzRA0Jm4Po1O+5BTcsN+PuW5WQxBjMcZYIW/AkHW8R7HdSphEpsnewhf8X1Mz7qnj+y4 hU3fBXpALSv5aOd+f8SaIw2GO4+8G2H3jdQ6coRqQGFQe5AIOi1oYpoN1SJlEMkW7GyW JotQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=GPr5OT0hjAf7wDQpFiXt+umkADr7mP/nXjReYVXPj5M=; fh=I1zkcBp/SqvTHwweqndVldr8bOjR+T/QgFEgnCzuaFo=; b=EDnIRG43xWoYND59E83nqb2OedyDC2rm0jRTI5hGmLJZylEtvP8iwk/V4l1RqkA8iN De47WmzzEm87zE2pdlaqUnnfCv3fsgnjtOUXnaRWUO0rbGJgHSD6ebb1xEsNYAHYJ6VU D3Ni4TBHn/FnPYEsXEnH0H9fLAM44OTpeMrRk5OrB5GHPpJQOy0pZcjVd+XnYKtaJoUB NnnA5fhgKqOMQCBeALo5+O/dHbMAPfWVYJcL4/w2m/gucNYbDxIzk47K22c6rOrtHZhK F6HbQSJoScwnNw0DPCkb+A6P1LYe8B+VmUZwTK7IE34FXqzXPpDyU5Y7VhKSjetIOwXK NEHg==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=mj32giKO; arc=pass (i=1 spf=pass spfdomain=gmail.com dkim=pass dkdomain=gmail.com dmarc=pass fromdomain=gmail.com); spf=pass (google.com: domain of linux-kernel+bounces-85099-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-85099-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [147.75.199.223]) by mx.google.com with ESMTPS id wi4-20020a05620a570400b00786a450ec37si9634601qkn.296.2024.02.28.05.33.47 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Feb 2024 05:33:47 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-85099-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) client-ip=147.75.199.223; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=mj32giKO; arc=pass (i=1 spf=pass spfdomain=gmail.com dkim=pass dkdomain=gmail.com dmarc=pass fromdomain=gmail.com); spf=pass (google.com: domain of linux-kernel+bounces-85099-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-85099-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 05F991C230EA for ; Wed, 28 Feb 2024 13:33:47 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id AB61C154BF5; Wed, 28 Feb 2024 13:33:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="mj32giKO" Received: from mail-ed1-f46.google.com (mail-ed1-f46.google.com [209.85.208.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7149814C58C; Wed, 28 Feb 2024 13:32:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1709127180; cv=none; b=q+fzY7VLHGx4hvIc7pbQwB+SyLe6MHg99+ZlXv33TkOo/f9X2DGjNes5NfZiENRSnMiPK3RFr7RgCW6Sn8iprCp95utBSMzZkI6nCFtopRYnX/cIbOnH7tSq+3u4glGhksVr5YTAcebm+iqEay1rQwFgbrIiMMx0+VnP1X1dW1c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1709127180; c=relaxed/simple; bh=7IIXC1qsD1MFpjVOqYYi+BOf0Ko89zjnAhsRvckXXLA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=BTuR7OcJslOQ7x55Hx04BEGFbyScwK5wIQQaTC8/5wUuf7Dt/vRSXOfqfxXWX+j8oZ5oft8Xb5n80clVstUnJt0AvqBdBvOvaf2kirEAbm88p6zDZ1TsDC2o/D/Qx9eCGIIBrzGYf8Q6QL0dYECAdG60lYIG89qDyh64ttXglIw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=mj32giKO; arc=none smtp.client-ip=209.85.208.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ed1-f46.google.com with SMTP id 4fb4d7f45d1cf-55a179f5fa1so6978101a12.0; Wed, 28 Feb 2024 05:32:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1709127177; x=1709731977; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=GPr5OT0hjAf7wDQpFiXt+umkADr7mP/nXjReYVXPj5M=; b=mj32giKOlivVtkqrMS5OBEssUKko98m64EaFlhXQ445ynCpOWjmuG2gomATey9br9V QzpBUz1BK7a16BSI+EEmMvqt6DgeAQwpGk78ZbbFqOcRGLUnHbmVKBzMYEGf5Wa4VupF YmiF6H3pLEiILs0FxYN29D51CEL/Gx1/miXLMZ+QkEbx7NpeDOHLAhaQptWe31PklUjj DjDjxStGEfSA/jgrjUMIlOQJQu04Ju3qpgb9+89SN/feBQfDatq6jpadxWFDNM5vQCiF 0h7seBcbi8b+o0z1ujLtuloWnQB2jFQvtHXXp9cp1saVyIevy2nMIMraMMaKH+l7oipO 8YCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1709127177; x=1709731977; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=GPr5OT0hjAf7wDQpFiXt+umkADr7mP/nXjReYVXPj5M=; b=GiJNitNFXJuunGD/ENqTcLJkUFgwbcdaEheCPkHexM0XvorSdHgBWh9NBFSSQCrHM/ zojqYdL4rxqtC2E89RDgts61iqv5x03veYvgvi/rIF2IZv5nIp06SIUVsK8zJ2qu2h0u 8UYlnp4KwOSTLSFDxG0UN7MqJ/8w/3id0AfAg/bZvGhbvX+wO6KkPruquAIORMHo6JPB vlXk218DQtNqqd7bmuTzEeJumyQJT6dyJltCnqmP9G2+fZZhAeidGfJCQWdU00aMHhAa EWJmVbGNTZS8h0tkANKYoV+Y4UbdaP88rYW7rA7SVoU+4dUKDnRK/b4qrhpmV1RtebLZ Cz3A== X-Forwarded-Encrypted: i=1; AJvYcCUZ7bv7T5G9poZiEiREtARqyPd3kWenNZoII5fnLtGSPNswhA3LIxOmDhBOuM3L4NWB7smXu7mjpcWxJjU9v+VSSGU0NeEortKAkMQgLc46ibNazH0HwGs8wbjJ88/dCGWfSpoptzVI X-Gm-Message-State: AOJu0YwsGAdgnjJEVAkknvDEAm2lRl3uUO0423L6c9rH2DYxnX79hME6 VhazNtZ1Ve6FLWQwhgEnqejaQmm8GS/8qjPIFEr4WljXT8psGfsL X-Received: by 2002:a17:906:488c:b0:a44:fd7:3850 with SMTP id v12-20020a170906488c00b00a440fd73850mr808781ejq.66.1709127176741; Wed, 28 Feb 2024 05:32:56 -0800 (PST) Received: from debian.fritz.box ([93.184.186.109]) by smtp.gmail.com with ESMTPSA id vx5-20020a170907a78500b00a3f20a8d2f6sm1856952ejc.112.2024.02.28.05.32.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Feb 2024 05:32:56 -0800 (PST) From: Dimitri Fedrau To: Cc: Dimitri Fedrau , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , linux-kernel@vger.kernel.org, linux-pwm@vger.kernel.org Subject: [PATCH 3/3] pwm: mc33xs2410: add support for direct inputs Date: Wed, 28 Feb 2024 14:32:35 +0100 Message-Id: <20240228133236.748225-4-dima.fedrau@gmail.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240228133236.748225-1-dima.fedrau@gmail.com> References: <20240228133236.748225-1-dima.fedrau@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1792149791571885686 X-GMAIL-MSGID: 1792149791571885686 Add support for direct inputs, which are used to directly turn-on or turn-off the outputs. Direct inputs have the advantage over the SPI controlled outputs that they aren't limited to the frequency steps. Frequency resolution depends on the input signal, range is still from 0.5Hz to 2.048kHz. Signed-off-by: Dimitri Fedrau --- drivers/pwm/pwm-mc33xs2410.c | 116 +++++++++++++++++++++++++++++++---- 1 file changed, 105 insertions(+), 11 deletions(-) diff --git a/drivers/pwm/pwm-mc33xs2410.c b/drivers/pwm/pwm-mc33xs2410.c index 35753039da6b..828a67227185 100644 --- a/drivers/pwm/pwm-mc33xs2410.c +++ b/drivers/pwm/pwm-mc33xs2410.c @@ -18,7 +18,10 @@ #define MC33XS2410_GLB_CTRL_MODE_MASK GENMASK(7, 6) #define MC33XS2410_GLB_CTRL_NORMAL_MODE BIT(6) #define MC33XS2410_GLB_CTRL_SAFE_MODE BIT(7) +#define MC33XS2410_GLB_CTRL_CMOS_LEVEL BIT(0) #define MC33XS2410_OUT1_4_CTRL 0x02 +#define MC33XS2410_IN_CTRL1 0x03 +#define MC33XS2410_IN_CTRL1_IN_EN(x) BIT(x) #define MC33XS2410_PWM_CTRL1 0x05 #define MC33XS2410_PWM_CTRL1_POL_INV(x) BIT(x) #define MC33XS2410_PWM_CTRL3 0x07 @@ -45,6 +48,7 @@ struct mc33xs2410_pwm { struct pwm_chip chip; struct spi_device *spi; + struct pwm_device *di[4]; struct mutex lock; }; @@ -154,20 +158,15 @@ static u8 mc33xs2410_pwm_get_freq(const struct pwm_state *state) return (ret | FIELD_PREP(MC33XS2410_PWM_FREQ_STEP_MASK, step)); } -static int mc33xs2410_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - const struct pwm_state *state) +static int mc33xs2410_pwm_apply_spi(struct pwm_chip *chip, + struct pwm_device *pwm, + const struct pwm_state *state) { struct mc33xs2410_pwm *mc33xs2410 = mc33xs2410_pwm_from_chip(chip); struct spi_device *spi = mc33xs2410->spi; u8 mask, val; int ret; - if (state->period > mc33xs2410_period[STEP_05HZ][MC33XS2410_PERIOD_MAX]) - return -EINVAL; - - if (state->period < mc33xs2410_period[STEP_32HZ][MC33XS2410_PERIOD_MIN]) - return -EINVAL; - guard(mutex)(&mc33xs2410->lock); mask = MC33XS2410_PWM_CTRL1_POL_INV(pwm->hwpwm); val = (state->polarity == PWM_POLARITY_INVERSED) ? mask : 0; @@ -190,9 +189,38 @@ static int mc33xs2410_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return mc33xs2410_modify_reg(spi, MC33XS2410_PWM_CTRL3, mask, val); } -static int mc33xs2410_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) +static int mc33xs2410_pwm_apply_direct_inputs(struct pwm_chip *chip, + struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct mc33xs2410_pwm *mc33xs2410 = mc33xs2410_pwm_from_chip(chip); + struct pwm_device *di = mc33xs2410->di[pwm->hwpwm]; + + guard(mutex)(&mc33xs2410->lock); + + return pwm_apply_state(di, state); +} + +static int mc33xs2410_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct mc33xs2410_pwm *mc33xs2410 = mc33xs2410_pwm_from_chip(chip); + + if (state->period > mc33xs2410_period[STEP_05HZ][MC33XS2410_PERIOD_MAX]) + return -EINVAL; + + if (state->period < mc33xs2410_period[STEP_32HZ][MC33XS2410_PERIOD_MIN]) + return -EINVAL; + + if (mc33xs2410->di[pwm->hwpwm]) + return mc33xs2410_pwm_apply_direct_inputs(chip, pwm, state); + else + return mc33xs2410_pwm_apply_spi(chip, pwm, state); +} + +static int mc33xs2410_pwm_get_state_spi(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { struct mc33xs2410_pwm *mc33xs2410 = mc33xs2410_pwm_from_chip(chip); struct spi_device *spi = mc33xs2410->spi; @@ -236,6 +264,28 @@ static int mc33xs2410_pwm_get_state(struct pwm_chip *chip, return 0; } +static int mc33xs2410_pwm_get_state_direct_inputs(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) +{ + struct mc33xs2410_pwm *mc33xs2410 = mc33xs2410_pwm_from_chip(chip); + + pwm_get_state(mc33xs2410->di[pwm->hwpwm], state); + return 0; +} + +static int mc33xs2410_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) +{ + struct mc33xs2410_pwm *mc33xs2410 = mc33xs2410_pwm_from_chip(chip); + + if (mc33xs2410->di[pwm->hwpwm]) + return mc33xs2410_pwm_get_state_direct_inputs(chip, pwm, state); + else + return mc33xs2410_pwm_get_state_spi(chip, pwm, state); +} + static const struct pwm_ops mc33xs2410_pwm_ops = { .apply = mc33xs2410_pwm_apply, .get_state = mc33xs2410_pwm_get_state, @@ -257,6 +307,45 @@ static int mc33xs2410_reset(struct device *dev) return 0; } +static int mc33xs2410_direct_inputs_probe(struct mc33xs2410_pwm *mc33xs2410) +{ + struct device *dev = &mc33xs2410->spi->dev; + u16 di_en = 0; + char buf[4]; + int ret, ch; + + for (ch = 0; ch < 4; ch++) { + sprintf(buf, "di%d", ch); + mc33xs2410->di[ch] = devm_pwm_get(dev, buf); + ret = PTR_ERR_OR_ZERO(mc33xs2410->di[ch]); + switch (ret) { + case 0: + di_en |= MC33XS2410_IN_CTRL1_IN_EN(ch); + break; + case -ENODATA: + mc33xs2410->di[ch] = NULL; + break; + case -EPROBE_DEFER: + return ret; + default: + dev_err(dev, "Failed to request %s: %d\n", buf, ret); + return ret; + } + } + + if (!di_en) + return 0; + + /* CMOS input logic level */ + ret = mc33xs2410_modify_reg(mc33xs2410->spi, MC33XS2410_GLB_CTRL, + MC33XS2410_GLB_CTRL_CMOS_LEVEL, + MC33XS2410_GLB_CTRL_CMOS_LEVEL); + if (ret < 0) + return ret; + + return mc33xs2410_write_reg(mc33xs2410->spi, MC33XS2410_IN_CTRL1, di_en); +} + static int mc33xs2410_probe(struct spi_device *spi) { struct mc33xs2410_pwm *mc33xs2410; @@ -290,6 +379,11 @@ static int mc33xs2410_probe(struct spi_device *spi) return dev_err_probe(dev, ret, "Failed to transition to normal mode\n"); + /* Enable direct inputs */ + ret = mc33xs2410_direct_inputs_probe(mc33xs2410); + if (ret) + return ret; + ret = devm_pwmchip_add(dev, &mc33xs2410->chip); if (ret < 0) return dev_err_probe(dev, ret, "Failed to add pwm chip\n");