From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 19381C433E0 for ; Fri, 5 Jun 2020 08:49:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B53A5207D5 for ; Fri, 5 Jun 2020 08:49:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="JHKB7BPt" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726134AbgFEItU (ORCPT ); Fri, 5 Jun 2020 04:49:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53638 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726084AbgFEItU (ORCPT ); Fri, 5 Jun 2020 04:49:20 -0400 Received: from mail-wm1-x343.google.com (mail-wm1-x343.google.com [IPv6:2a00:1450:4864:20::343]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 05D40C08C5C6 for ; Fri, 5 Jun 2020 01:49:20 -0700 (PDT) Received: by mail-wm1-x343.google.com with SMTP id l26so7654167wme.3 for ; Fri, 05 Jun 2020 01:49:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:content-transfer-encoding:in-reply-to; bh=ShIPEKLtHJNI7EgByJ7TzTteP7weEEoEK5XnGUnAnDA=; b=JHKB7BPtiDQpdqRj4iwj2PaCKo2ZYMwCEXh3GY/NEwFYFSE47qjrQmxrSB7T0iodw6 RmMzOO/L8Msz58TpWxpu/ANCKEiUHGO9/amUCaByExYyC/UBu+ANQPXnWnataTsRLNix noronmmlyJ/akaNcxh7RNjTQtVPrDG5zYwQHZKYCxuIvGiMYbl2wO2WwNKj7bO+BZRDy VTU1uipZn/zZ7AeGaRUFx/ZnDlR4XWs6tXLm7o3NZNl0L9nq7dqN2eMCQ21F2xri8uAg nNF/9kpYLeZpM3I9M3QDpLL6TwDnOLzYVcNamQUkqcoCdclagZ4fvhx+DNoGufhzKrib 5y/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:content-transfer-encoding :in-reply-to; bh=ShIPEKLtHJNI7EgByJ7TzTteP7weEEoEK5XnGUnAnDA=; b=acet5G/z9b+/fXck772TBhON8SGcepvO/yvfaUTANQKGT/zErBhyyxsVlFPxWP25kv sNlmrncPouQMs5SB3olqPMMRRYykjnsFBBe9A/eQHcFnxk7BnxBmWNpDXGZ4XFCFOy7g qI5tIa4OCJ/mYpH6QUMDSuGD9BO9gYACn9bTzmAUX6F6jSHFcOWCB4he6d+zfVmD0Tzn yakgJxB9JbZx1uM3HAXGmBXBt+yn9a+CWxFqPEESkDgv2rYSP//1oufUxKsZxUvBPZPV lbfV3bQWvjCvaHFjXT9q0WaJNxpA0YYc3AFnbYL8qDsbwV2XgJ93RmGX6YS9Um3kU24D 2O7Q== X-Gm-Message-State: AOAM531bnwBj3kLanzMlbcv/LEfew8+IWTnDTL3/lnol+8OKMb+kpHt6 uv+jZ3dQZDxCJreljBVppCTLqw== X-Google-Smtp-Source: ABdhPJzFLO8h/vvGcmXwgNoyFftB5nfR424h9jxB25M8PSh39Yyc0S54n+rRnjr0KPF2rHImbfY5hg== X-Received: by 2002:a7b:cf02:: with SMTP id l2mr1609865wmg.136.1591346958101; Fri, 05 Jun 2020 01:49:18 -0700 (PDT) Received: from dell ([95.147.198.92]) by smtp.gmail.com with ESMTPSA id j5sm11113810wrq.39.2020.06.05.01.49.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Jun 2020 01:49:17 -0700 (PDT) Date: Fri, 5 Jun 2020 09:49:15 +0100 From: Lee Jones To: Michael Walle Cc: linux-gpio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, linux-pwm@vger.kernel.org, linux-watchdog@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Linus Walleij , Bartosz Golaszewski , Rob Herring , Jean Delvare , Guenter Roeck , Thierry Reding , Uwe =?iso-8859-1?Q?Kleine-K=F6nig?= , Wim Van Sebroeck , Shawn Guo , Li Yang , Thomas Gleixner , Jason Cooper , Marc Zyngier , Mark Brown , Greg Kroah-Hartman , Andy Shevchenko Subject: Re: [PATCH v4 05/11] pwm: add support for sl28cpld PWM controller Message-ID: <20200605084915.GE3714@dell> References: <20200604211039.12689-1-michael@walle.cc> <20200604211039.12689-6-michael@walle.cc> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <20200604211039.12689-6-michael@walle.cc> Sender: linux-gpio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org On Thu, 04 Jun 2020, Michael Walle wrote: > Add support for the PWM controller of the sl28cpld board management > controller. This is part of a multi-function device driver. > > The controller has one PWM channel and can just generate four distinct > frequencies. > > Signed-off-by: Michael Walle > --- > drivers/pwm/Kconfig | 10 ++ > drivers/pwm/Makefile | 1 + > drivers/pwm/pwm-sl28cpld.c | 201 +++++++++++++++++++++++++++++++++++++ > 3 files changed, 212 insertions(+) > create mode 100644 drivers/pwm/pwm-sl28cpld.c > > diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig > index cb8d739067d2..a39371c11ff6 100644 > --- a/drivers/pwm/Kconfig > +++ b/drivers/pwm/Kconfig > @@ -437,6 +437,16 @@ config PWM_SIFIVE > To compile this driver as a module, choose M here: the module > will be called pwm-sifive. > > +config PWM_SL28CPLD > + tristate "Kontron sl28 PWM support" > + depends on MFD_SL28CPLD > + help > + Generic PWM framework driver for board management controller > + found on the Kontron sl28 CPLD. > + > + To compile this driver as a module, choose M here: the module > + will be called pwm-sl28cpld. > + > config PWM_SPEAR > tristate "STMicroelectronics SPEAr PWM support" > depends on PLAT_SPEAR || COMPILE_TEST > diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile > index a59c710e98c7..c479623724e8 100644 > --- a/drivers/pwm/Makefile > +++ b/drivers/pwm/Makefile > @@ -41,6 +41,7 @@ obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o > obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o > obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o > obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o > +obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o > obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o > obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o > obj-$(CONFIG_PWM_STI) += pwm-sti.o > diff --git a/drivers/pwm/pwm-sl28cpld.c b/drivers/pwm/pwm-sl28cpld.c > new file mode 100644 > index 000000000000..d82303f509f5 > --- /dev/null > +++ b/drivers/pwm/pwm-sl28cpld.c > @@ -0,0 +1,201 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * sl28cpld PWM driver. > + * > + * Copyright 2019 Kontron Europe GmbH This is out of date. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +/* > + * PWM timer block registers. > + */ > +#define PWM_CTRL 0x00 > +#define PWM_ENABLE BIT(7) > +#define PWM_MODE_250HZ 0 > +#define PWM_MODE_500HZ 1 > +#define PWM_MODE_1KHZ 2 > +#define PWM_MODE_2KHZ 3 > +#define PWM_MODE_MASK GENMASK(1, 0) > +#define PWM_CYCLE 0x01 > +#define PWM_CYCLE_MAX 0x7f > + > +struct sl28cpld_pwm { > + struct pwm_chip pwm_chip; > + struct regmap *regmap; > + u32 offset; > +}; > + > +struct sl28cpld_pwm_periods { > + u8 ctrl; > + unsigned long duty_cycle; > +}; > + > +struct sl28cpld_pwm_config { > + unsigned long period_ns; > + u8 max_duty_cycle; > +}; Also, instead of hand rolling your own structure here, I think it would be prudent to re-use something that already exists. Seeing as this will be used to describe possible state, perhaps 'struct pwm_state' would be suitable - leaving polarity and enabled unpopulated of course. Ah wait (sorry, thinking allowed and on-the-fly here), what is max_duty_cycle here? I assume this does not have the same meaning/value-type as the one in 'struct pwm_state'. What does max_duty_cycle represent in your use-case? > +static struct sl28cpld_pwm_config sl28cpld_pwm_config[] = { > + [PWM_MODE_250HZ] = { .period_ns = 4000000, .max_duty_cycle = 0x80 }, > + [PWM_MODE_500HZ] = { .period_ns = 2000000, .max_duty_cycle = 0x40 }, > + [PWM_MODE_1KHZ] = { .period_ns = 1000000, .max_duty_cycle = 0x20 }, > + [PWM_MODE_2KHZ] = { .period_ns = 500000, .max_duty_cycle = 0x10 }, > +}; Tiny nit: If you lined these up from the '{'s it would be easier to see/compare the period_ns values at first glance, rather than having to count the ' 's and '0's. > +static inline struct sl28cpld_pwm *to_sl28cpld_pwm(struct pwm_chip *chip) > +{ > + return container_of(chip, struct sl28cpld_pwm, pwm_chip); > +} Why not save yourself the trouble and just: struct sl28cpld_pwm *pwm = dev_get_drvdata(chip->dev); > +static void sl28cpld_pwm_get_state(struct pwm_chip *chip, > + struct pwm_device *pwm, > + struct pwm_state *state) > +{ > + struct sl28cpld_pwm *spc = to_sl28cpld_pwm(chip); > + static struct sl28cpld_pwm_config *config; > + unsigned int reg; > + unsigned long cycle; Why is this 'long' here and 'long long' in *_apply()? > + unsigned int mode; > + > + regmap_read(spc->regmap, spc->offset + PWM_CTRL, ®); > + > + state->enabled = reg & PWM_ENABLE; > + > + mode = FIELD_GET(PWM_MODE_MASK, reg); > + config = &sl28cpld_pwm_config[mode]; > + state->period = config->period_ns; > + > + regmap_read(spc->regmap, spc->offset + PWM_CYCLE, ®); > + cycle = reg * config->period_ns; > + state->duty_cycle = DIV_ROUND_CLOSEST_ULL(cycle, > + config->max_duty_cycle); > +} > + > +static int sl28cpld_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, > + const struct pwm_state *state) > +{ > + struct sl28cpld_pwm *spc = to_sl28cpld_pwm(chip); > + struct sl28cpld_pwm_config *config; > + unsigned long long cycle; > + int ret; > + int mode; > + u8 ctrl; > + > + /* update config, first search best matching period */ Please use correct grammar (less full stops) in comments. > + for (mode = 0; mode < ARRAY_SIZE(sl28cpld_pwm_config); mode++) { > + config = &sl28cpld_pwm_config[mode]; > + if (state->period == config->period_ns) > + break; > + } > + > + if (mode == ARRAY_SIZE(sl28cpld_pwm_config)) > + return -EINVAL; > + > + ctrl = FIELD_PREP(PWM_MODE_MASK, mode); > + if (state->enabled) > + ctrl |= PWM_ENABLE; > + > + cycle = state->duty_cycle * config->max_duty_cycle; > + do_div(cycle, state->period); Forgive my ignorance (I'm new here!), but what are these 2 lines doing? Here we are multiplying the current duty_cycle with the maximum value, then dividing by the period. So in the case of PWM_MODE_1KHZ with a 50% duty cycle, you'd have: (500000 * 0x20[16]) / 1000000 = [0x10]16 Thus, the above gives as a proportional representation of the maximum valid value for placement into the cycle control register(s), right? Either way (whether I'm correct or not), I think it would be nice to mention this in a comment. Maybe even clarify with a simple example. > + /* > + * The hardware doesn't allow to set max_duty_cycle if the > + * 250Hz mode is enabled. But since this is "all-high" output > + * just use the 500Hz mode with the duty cycle to max value. > + */ > + if (cycle == config->max_duty_cycle) { > + ctrl &= ~PWM_MODE_MASK; > + ctrl |= FIELD_PREP(PWM_MODE_MASK, PWM_MODE_500HZ); > + cycle = PWM_CYCLE_MAX; > + } This is being executed even when 250Hz mode is not enabled. Is that by design? If so, it doesn't match the comment. > + ret = regmap_write(spc->regmap, spc->offset + PWM_CTRL, ctrl); > + if (ret) > + return ret; > + > + return regmap_write(spc->regmap, spc->offset + PWM_CYCLE, (u8)cycle); > +} > + > +static const struct pwm_ops sl28cpld_pwm_ops = { > + .apply = sl28cpld_pwm_apply, > + .get_state = sl28cpld_pwm_get_state, > + .owner = THIS_MODULE, > +}; > + > +static int sl28cpld_pwm_probe(struct platform_device *pdev) > +{ > + struct sl28cpld_pwm *pwm; This is super confusing. Here you call it 'pwm', but when you bring the data to the fore for consumption, you call it something different ('spc') for some reason. Is there logic behind this? > + struct pwm_chip *chip; > + int ret; > + > + if (!pdev->dev.parent) > + return -ENODEV; > + > + pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); > + if (!pwm) > + return -ENOMEM; > + > + pwm->regmap = dev_get_regmap(pdev->dev.parent, NULL); > + if (!pwm->regmap) > + return -ENODEV; > + > + ret = device_property_read_u32(&pdev->dev, "reg", &pwm->offset); Really? Can you use the 'reg' property in this way? Side question: Do any of your child address spaces actually overlap/intersect? > + if (ret) > + return -EINVAL; > + > + /* initialize struct pwm_chip */ Proper grammar please. > + chip = &pwm->pwm_chip; > + chip->dev = &pdev->dev; > + chip->ops = &sl28cpld_pwm_ops; > + chip->base = -1; > + chip->npwm = 1; > + > + ret = pwmchip_add(&pwm->pwm_chip); > + if (ret < 0) Is '> 0' even valid? Suggest "!ret" here, as you have done above. > + return ret; > + > + platform_set_drvdata(pdev, pwm); > + > + return 0; > +} > + > +static int sl28cpld_pwm_remove(struct platform_device *pdev) > +{ > + struct sl28cpld_pwm *pwm = platform_get_drvdata(pdev); > + > + return pwmchip_remove(&pwm->pwm_chip); > +} > + > +static const struct of_device_id sl28cpld_pwm_of_match[] = { > + { .compatible = "kontron,sl28cpld-pwm" }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, sl28cpld_pwm_of_match); > + > +static const struct platform_device_id sl28cpld_pwm_id_table[] = { > + {"sl28cpld-pwm"}, Spaces either side of the "'s please. > + {}, > +}; > +MODULE_DEVICE_TABLE(platform, sl28cpld_pwm_id_table); What are you using this for? > +static struct platform_driver sl28cpld_pwm_driver = { > + .probe = sl28cpld_pwm_probe, > + .remove = sl28cpld_pwm_remove, > + .id_table = sl28cpld_pwm_id_table, > + .driver = { > + .name = KBUILD_MODNAME, Please just use the quoted name in full. > + .of_match_table = sl28cpld_pwm_of_match, > + }, > +}; > +module_platform_driver(sl28cpld_pwm_driver); > + > +MODULE_DESCRIPTION("sl28cpld PWM Driver"); "SL28CPLD" ? > +MODULE_AUTHOR("Michael Walle "); > +MODULE_LICENSE("GPL"); -- Lee Jones [李琼斯] Linaro Services Technical Lead Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog From mboxrd@z Thu Jan 1 00:00:00 1970 From: Lee Jones Subject: Re: [PATCH v4 05/11] pwm: add support for sl28cpld PWM controller Date: Fri, 5 Jun 2020 09:49:15 +0100 Message-ID: <20200605084915.GE3714@dell> References: <20200604211039.12689-1-michael@walle.cc> <20200604211039.12689-6-michael@walle.cc> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Return-path: Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53632 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726115AbgFEItU (ORCPT ); Fri, 5 Jun 2020 04:49:20 -0400 Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B3E48C08C5C3 for ; Fri, 5 Jun 2020 01:49:19 -0700 (PDT) Received: by mail-wm1-x344.google.com with SMTP id u13so7683292wml.1 for ; Fri, 05 Jun 2020 01:49:19 -0700 (PDT) Content-Disposition: inline In-Reply-To: <20200604211039.12689-6-michael@walle.cc> Sender: linux-pwm-owner@vger.kernel.org List-Id: linux-pwm@vger.kernel.org To: Michael Walle Cc: linux-gpio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, linux-pwm@vger.kernel.org, linux-watchdog@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Linus Walleij , Bartosz Golaszewski , Rob Herring , Jean Delvare , Guenter Roeck , Thierry Reding , Uwe =?iso-8859-1?Q?Kleine-K=F6nig?= , Wim Van Sebroeck , Shawn Guo , Li Yang , Thomas Gleixner , Jason Cooper , Marc Zyngier , Mark Brown On Thu, 04 Jun 2020, Michael Walle wrote: > Add support for the PWM controller of the sl28cpld board management > controller. This is part of a multi-function device driver. > > The controller has one PWM channel and can just generate four distinct > frequencies. > > Signed-off-by: Michael Walle > --- > drivers/pwm/Kconfig | 10 ++ > drivers/pwm/Makefile | 1 + > drivers/pwm/pwm-sl28cpld.c | 201 +++++++++++++++++++++++++++++++++++++ > 3 files changed, 212 insertions(+) > create mode 100644 drivers/pwm/pwm-sl28cpld.c > > diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig > index cb8d739067d2..a39371c11ff6 100644 > --- a/drivers/pwm/Kconfig > +++ b/drivers/pwm/Kconfig > @@ -437,6 +437,16 @@ config PWM_SIFIVE > To compile this driver as a module, choose M here: the module > will be called pwm-sifive. > > +config PWM_SL28CPLD > + tristate "Kontron sl28 PWM support" > + depends on MFD_SL28CPLD > + help > + Generic PWM framework driver for board management controller > + found on the Kontron sl28 CPLD. > + > + To compile this driver as a module, choose M here: the module > + will be called pwm-sl28cpld. > + > config PWM_SPEAR > tristate "STMicroelectronics SPEAr PWM support" > depends on PLAT_SPEAR || COMPILE_TEST > diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile > index a59c710e98c7..c479623724e8 100644 > --- a/drivers/pwm/Makefile > +++ b/drivers/pwm/Makefile > @@ -41,6 +41,7 @@ obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o > obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o > obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o > obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o > +obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o > obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o > obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o > obj-$(CONFIG_PWM_STI) += pwm-sti.o > diff --git a/drivers/pwm/pwm-sl28cpld.c b/drivers/pwm/pwm-sl28cpld.c > new file mode 100644 > index 000000000000..d82303f509f5 > --- /dev/null > +++ b/drivers/pwm/pwm-sl28cpld.c > @@ -0,0 +1,201 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * sl28cpld PWM driver. > + * > + * Copyright 2019 Kontron Europe GmbH This is out of date. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +/* > + * PWM timer block registers. > + */ > +#define PWM_CTRL 0x00 > +#define PWM_ENABLE BIT(7) > +#define PWM_MODE_250HZ 0 > +#define PWM_MODE_500HZ 1 > +#define PWM_MODE_1KHZ 2 > +#define PWM_MODE_2KHZ 3 > +#define PWM_MODE_MASK GENMASK(1, 0) > +#define PWM_CYCLE 0x01 > +#define PWM_CYCLE_MAX 0x7f > + > +struct sl28cpld_pwm { > + struct pwm_chip pwm_chip; > + struct regmap *regmap; > + u32 offset; > +}; > + > +struct sl28cpld_pwm_periods { > + u8 ctrl; > + unsigned long duty_cycle; > +}; > + > +struct sl28cpld_pwm_config { > + unsigned long period_ns; > + u8 max_duty_cycle; > +}; Also, instead of hand rolling your own structure here, I think it would be prudent to re-use something that already exists. Seeing as this will be used to describe possible state, perhaps 'struct pwm_state' would be suitable - leaving polarity and enabled unpopulated of course. Ah wait (sorry, thinking allowed and on-the-fly here), what is max_duty_cycle here? I assume this does not have the same meaning/value-type as the one in 'struct pwm_state'. What does max_duty_cycle represent in your use-case? > +static struct sl28cpld_pwm_config sl28cpld_pwm_config[] = { > + [PWM_MODE_250HZ] = { .period_ns = 4000000, .max_duty_cycle = 0x80 }, > + [PWM_MODE_500HZ] = { .period_ns = 2000000, .max_duty_cycle = 0x40 }, > + [PWM_MODE_1KHZ] = { .period_ns = 1000000, .max_duty_cycle = 0x20 }, > + [PWM_MODE_2KHZ] = { .period_ns = 500000, .max_duty_cycle = 0x10 }, > +}; Tiny nit: If you lined these up from the '{'s it would be easier to see/compare the period_ns values at first glance, rather than having to count the ' 's and '0's. > +static inline struct sl28cpld_pwm *to_sl28cpld_pwm(struct pwm_chip *chip) > +{ > + return container_of(chip, struct sl28cpld_pwm, pwm_chip); > +} Why not save yourself the trouble and just: struct sl28cpld_pwm *pwm = dev_get_drvdata(chip->dev); > +static void sl28cpld_pwm_get_state(struct pwm_chip *chip, > + struct pwm_device *pwm, > + struct pwm_state *state) > +{ > + struct sl28cpld_pwm *spc = to_sl28cpld_pwm(chip); > + static struct sl28cpld_pwm_config *config; > + unsigned int reg; > + unsigned long cycle; Why is this 'long' here and 'long long' in *_apply()? > + unsigned int mode; > + > + regmap_read(spc->regmap, spc->offset + PWM_CTRL, ®); > + > + state->enabled = reg & PWM_ENABLE; > + > + mode = FIELD_GET(PWM_MODE_MASK, reg); > + config = &sl28cpld_pwm_config[mode]; > + state->period = config->period_ns; > + > + regmap_read(spc->regmap, spc->offset + PWM_CYCLE, ®); > + cycle = reg * config->period_ns; > + state->duty_cycle = DIV_ROUND_CLOSEST_ULL(cycle, > + config->max_duty_cycle); > +} > + > +static int sl28cpld_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, > + const struct pwm_state *state) > +{ > + struct sl28cpld_pwm *spc = to_sl28cpld_pwm(chip); > + struct sl28cpld_pwm_config *config; > + unsigned long long cycle; > + int ret; > + int mode; > + u8 ctrl; > + > + /* update config, first search best matching period */ Please use correct grammar (less full stops) in comments. > + for (mode = 0; mode < ARRAY_SIZE(sl28cpld_pwm_config); mode++) { > + config = &sl28cpld_pwm_config[mode]; > + if (state->period == config->period_ns) > + break; > + } > + > + if (mode == ARRAY_SIZE(sl28cpld_pwm_config)) > + return -EINVAL; > + > + ctrl = FIELD_PREP(PWM_MODE_MASK, mode); > + if (state->enabled) > + ctrl |= PWM_ENABLE; > + > + cycle = state->duty_cycle * config->max_duty_cycle; > + do_div(cycle, state->period); Forgive my ignorance (I'm new here!), but what are these 2 lines doing? Here we are multiplying the current duty_cycle with the maximum value, then dividing by the period. So in the case of PWM_MODE_1KHZ with a 50% duty cycle, you'd have: (500000 * 0x20[16]) / 1000000 = [0x10]16 Thus, the above gives as a proportional representation of the maximum valid value for placement into the cycle control register(s), right? Either way (whether I'm correct or not), I think it would be nice to mention this in a comment. Maybe even clarify with a simple example. > + /* > + * The hardware doesn't allow to set max_duty_cycle if the > + * 250Hz mode is enabled. But since this is "all-high" output > + * just use the 500Hz mode with the duty cycle to max value. > + */ > + if (cycle == config->max_duty_cycle) { > + ctrl &= ~PWM_MODE_MASK; > + ctrl |= FIELD_PREP(PWM_MODE_MASK, PWM_MODE_500HZ); > + cycle = PWM_CYCLE_MAX; > + } This is being executed even when 250Hz mode is not enabled. Is that by design? If so, it doesn't match the comment. > + ret = regmap_write(spc->regmap, spc->offset + PWM_CTRL, ctrl); > + if (ret) > + return ret; > + > + return regmap_write(spc->regmap, spc->offset + PWM_CYCLE, (u8)cycle); > +} > + > +static const struct pwm_ops sl28cpld_pwm_ops = { > + .apply = sl28cpld_pwm_apply, > + .get_state = sl28cpld_pwm_get_state, > + .owner = THIS_MODULE, > +}; > + > +static int sl28cpld_pwm_probe(struct platform_device *pdev) > +{ > + struct sl28cpld_pwm *pwm; This is super confusing. Here you call it 'pwm', but when you bring the data to the fore for consumption, you call it something different ('spc') for some reason. Is there logic behind this? > + struct pwm_chip *chip; > + int ret; > + > + if (!pdev->dev.parent) > + return -ENODEV; > + > + pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); > + if (!pwm) > + return -ENOMEM; > + > + pwm->regmap = dev_get_regmap(pdev->dev.parent, NULL); > + if (!pwm->regmap) > + return -ENODEV; > + > + ret = device_property_read_u32(&pdev->dev, "reg", &pwm->offset); Really? Can you use the 'reg' property in this way? Side question: Do any of your child address spaces actually overlap/intersect? > + if (ret) > + return -EINVAL; > + > + /* initialize struct pwm_chip */ Proper grammar please. > + chip = &pwm->pwm_chip; > + chip->dev = &pdev->dev; > + chip->ops = &sl28cpld_pwm_ops; > + chip->base = -1; > + chip->npwm = 1; > + > + ret = pwmchip_add(&pwm->pwm_chip); > + if (ret < 0) Is '> 0' even valid? Suggest "!ret" here, as you have done above. > + return ret; > + > + platform_set_drvdata(pdev, pwm); > + > + return 0; > +} > + > +static int sl28cpld_pwm_remove(struct platform_device *pdev) > +{ > + struct sl28cpld_pwm *pwm = platform_get_drvdata(pdev); > + > + return pwmchip_remove(&pwm->pwm_chip); > +} > + > +static const struct of_device_id sl28cpld_pwm_of_match[] = { > + { .compatible = "kontron,sl28cpld-pwm" }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, sl28cpld_pwm_of_match); > + > +static const struct platform_device_id sl28cpld_pwm_id_table[] = { > + {"sl28cpld-pwm"}, Spaces either side of the "'s please. > + {}, > +}; > +MODULE_DEVICE_TABLE(platform, sl28cpld_pwm_id_table); What are you using this for? > +static struct platform_driver sl28cpld_pwm_driver = { > + .probe = sl28cpld_pwm_probe, > + .remove = sl28cpld_pwm_remove, > + .id_table = sl28cpld_pwm_id_table, > + .driver = { > + .name = KBUILD_MODNAME, Please just use the quoted name in full. > + .of_match_table = sl28cpld_pwm_of_match, > + }, > +}; > +module_platform_driver(sl28cpld_pwm_driver); > + > +MODULE_DESCRIPTION("sl28cpld PWM Driver"); "SL28CPLD" ? > +MODULE_AUTHOR("Michael Walle "); > +MODULE_LICENSE("GPL"); -- Lee Jones [李琼斯] Linaro Services Technical Lead Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 72F9DC433E0 for ; Fri, 5 Jun 2020 08:49:25 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 42EBF20772 for ; Fri, 5 Jun 2020 08:49:25 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="W7tD+w9x"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="JHKB7BPt" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 42EBF20772 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+infradead-linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:In-Reply-To:MIME-Version:References: Message-ID:Subject:To:From:Date:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=LRU367t9oJ5DvmQCXjDQHNwIzODxv4I/w/O+wxYEad0=; b=W7tD+w9xr/J/CQ cW4IPzCkfj/LgZBBdDIS3+KLueiFPlBARJGBRiOaMw9WHFtwQaeRDfCC8EkXeDtwrfNU/O+jUBS7A Kh8nUepeNZ/dfGhW2dG88Ekr+oMUdnpVG5KT0lXrJDNmsO6xR+mDNuLFXp+dbkFthqV3/vAt72cka kExDX/JsURS3XgMaoGla3Ut3/CDT8VVzHjiREWvs9ZaCFzR3nebhYBTL3QvCzgaeWBs/V5NIY29+i qwN2+O+L/KPY6v6QocQoHYZ+YXGxggy6WI8jNuIAcsqn2yMw7DZeZTRfghMyC2iTICuVwCRFuvu7N y8AmUSZ/elvyZoq5U7Hw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jh82W-0006db-VD; Fri, 05 Jun 2020 08:49:24 +0000 Received: from mail-wm1-x341.google.com ([2a00:1450:4864:20::341]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jh82R-0006d5-SF for linux-arm-kernel@lists.infradead.org; Fri, 05 Jun 2020 08:49:23 +0000 Received: by mail-wm1-x341.google.com with SMTP id l26so7654169wme.3 for ; Fri, 05 Jun 2020 01:49:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:content-transfer-encoding:in-reply-to; bh=ShIPEKLtHJNI7EgByJ7TzTteP7weEEoEK5XnGUnAnDA=; b=JHKB7BPtiDQpdqRj4iwj2PaCKo2ZYMwCEXh3GY/NEwFYFSE47qjrQmxrSB7T0iodw6 RmMzOO/L8Msz58TpWxpu/ANCKEiUHGO9/amUCaByExYyC/UBu+ANQPXnWnataTsRLNix noronmmlyJ/akaNcxh7RNjTQtVPrDG5zYwQHZKYCxuIvGiMYbl2wO2WwNKj7bO+BZRDy VTU1uipZn/zZ7AeGaRUFx/ZnDlR4XWs6tXLm7o3NZNl0L9nq7dqN2eMCQ21F2xri8uAg nNF/9kpYLeZpM3I9M3QDpLL6TwDnOLzYVcNamQUkqcoCdclagZ4fvhx+DNoGufhzKrib 5y/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:content-transfer-encoding :in-reply-to; bh=ShIPEKLtHJNI7EgByJ7TzTteP7weEEoEK5XnGUnAnDA=; b=umlJ5uZxcrxHMdQXZ447pAE3GGjXefRDWYQr77spPKcQumQlYu6p7NSStwM/CBTLkA eM6jPPFQ9a6Rqj3IHZJYcCh5HUHTLUbxHDhfiTeoL/vUJcZjIubaV54qiHqW9tygJgoZ fsiKEDY0AhxtUGVLkFe92Fe4xapsPCe+fKl0qUhRyHZuRCqPTLCXYIq/H1aYP3LTyYhH nc6BgQadGBQFglfh8kjDvtdiM6+S17cmsZtuiBzIVkNkTtezRB1MH8tbZ+Ile3KwdnTU FxInMVeE5UOW/3+cT3fYdrCn/tgNXSKg+N0SNHfoLGWHEgpBPmGlLCjIVKJVAz3Z25sO rJzw== X-Gm-Message-State: AOAM5316/ikuue0F6wSgaYDIrsk1CFYSCtsuRTbXy+1OCIDqQPg37Fjt fqD9V4mleGR3wgMgmRpqB4MaiQ== X-Google-Smtp-Source: ABdhPJzFLO8h/vvGcmXwgNoyFftB5nfR424h9jxB25M8PSh39Yyc0S54n+rRnjr0KPF2rHImbfY5hg== X-Received: by 2002:a7b:cf02:: with SMTP id l2mr1609865wmg.136.1591346958101; Fri, 05 Jun 2020 01:49:18 -0700 (PDT) Received: from dell ([95.147.198.92]) by smtp.gmail.com with ESMTPSA id j5sm11113810wrq.39.2020.06.05.01.49.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Jun 2020 01:49:17 -0700 (PDT) Date: Fri, 5 Jun 2020 09:49:15 +0100 From: Lee Jones To: Michael Walle Subject: Re: [PATCH v4 05/11] pwm: add support for sl28cpld PWM controller Message-ID: <20200605084915.GE3714@dell> References: <20200604211039.12689-1-michael@walle.cc> <20200604211039.12689-6-michael@walle.cc> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20200604211039.12689-6-michael@walle.cc> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200605_014919_951675_58871CF1 X-CRM114-Status: GOOD ( 32.20 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, Linus Walleij , Thierry Reding , Jason Cooper , Andy Shevchenko , Marc Zyngier , Bartosz Golaszewski , Uwe =?iso-8859-1?Q?Kleine-K=F6nig?= , Guenter Roeck , linux-pwm@vger.kernel.org, Jean Delvare , linux-watchdog@vger.kernel.org, linux-gpio@vger.kernel.org, Mark Brown , Thomas Gleixner , Wim Van Sebroeck , linux-arm-kernel@lists.infradead.org, linux-hwmon@vger.kernel.org, Greg Kroah-Hartman , linux-kernel@vger.kernel.org, Li Yang , Rob Herring , Shawn Guo Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+infradead-linux-arm-kernel=archiver.kernel.org@lists.infradead.org T24gVGh1LCAwNCBKdW4gMjAyMCwgTWljaGFlbCBXYWxsZSB3cm90ZToKCj4gQWRkIHN1cHBvcnQg Zm9yIHRoZSBQV00gY29udHJvbGxlciBvZiB0aGUgc2wyOGNwbGQgYm9hcmQgbWFuYWdlbWVudAo+ IGNvbnRyb2xsZXIuIFRoaXMgaXMgcGFydCBvZiBhIG11bHRpLWZ1bmN0aW9uIGRldmljZSBkcml2 ZXIuCj4gCj4gVGhlIGNvbnRyb2xsZXIgaGFzIG9uZSBQV00gY2hhbm5lbCBhbmQgY2FuIGp1c3Qg Z2VuZXJhdGUgZm91ciBkaXN0aW5jdAo+IGZyZXF1ZW5jaWVzLgo+IAo+IFNpZ25lZC1vZmYtYnk6 IE1pY2hhZWwgV2FsbGUgPG1pY2hhZWxAd2FsbGUuY2M+Cj4gLS0tCj4gIGRyaXZlcnMvcHdtL0tj b25maWcgICAgICAgIHwgIDEwICsrCj4gIGRyaXZlcnMvcHdtL01ha2VmaWxlICAgICAgIHwgICAx ICsKPiAgZHJpdmVycy9wd20vcHdtLXNsMjhjcGxkLmMgfCAyMDEgKysrKysrKysrKysrKysrKysr KysrKysrKysrKysrKysrKysrKwo+ICAzIGZpbGVzIGNoYW5nZWQsIDIxMiBpbnNlcnRpb25zKCsp Cj4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL3B3bS9wd20tc2wyOGNwbGQuYwo+IAo+IGRp ZmYgLS1naXQgYS9kcml2ZXJzL3B3bS9LY29uZmlnIGIvZHJpdmVycy9wd20vS2NvbmZpZwo+IGlu ZGV4IGNiOGQ3MzkwNjdkMi4uYTM5MzcxYzExZmY2IDEwMDY0NAo+IC0tLSBhL2RyaXZlcnMvcHdt L0tjb25maWcKPiArKysgYi9kcml2ZXJzL3B3bS9LY29uZmlnCj4gQEAgLTQzNyw2ICs0MzcsMTYg QEAgY29uZmlnIFBXTV9TSUZJVkUKPiAgCSAgVG8gY29tcGlsZSB0aGlzIGRyaXZlciBhcyBhIG1v ZHVsZSwgY2hvb3NlIE0gaGVyZTogdGhlIG1vZHVsZQo+ICAJICB3aWxsIGJlIGNhbGxlZCBwd20t c2lmaXZlLgo+ICAKPiArY29uZmlnIFBXTV9TTDI4Q1BMRAo+ICsJdHJpc3RhdGUgIktvbnRyb24g c2wyOCBQV00gc3VwcG9ydCIKPiArCWRlcGVuZHMgb24gTUZEX1NMMjhDUExECj4gKwloZWxwCj4g KwkgIEdlbmVyaWMgUFdNIGZyYW1ld29yayBkcml2ZXIgZm9yIGJvYXJkIG1hbmFnZW1lbnQgY29u dHJvbGxlcgo+ICsJICBmb3VuZCBvbiB0aGUgS29udHJvbiBzbDI4IENQTEQuCj4gKwo+ICsJICBU byBjb21waWxlIHRoaXMgZHJpdmVyIGFzIGEgbW9kdWxlLCBjaG9vc2UgTSBoZXJlOiB0aGUgbW9k dWxlCj4gKwkgIHdpbGwgYmUgY2FsbGVkIHB3bS1zbDI4Y3BsZC4KPiArCj4gIGNvbmZpZyBQV01f U1BFQVIKPiAgCXRyaXN0YXRlICJTVE1pY3JvZWxlY3Ryb25pY3MgU1BFQXIgUFdNIHN1cHBvcnQi Cj4gIAlkZXBlbmRzIG9uIFBMQVRfU1BFQVIgfHwgQ09NUElMRV9URVNUCj4gZGlmZiAtLWdpdCBh L2RyaXZlcnMvcHdtL01ha2VmaWxlIGIvZHJpdmVycy9wd20vTWFrZWZpbGUKPiBpbmRleCBhNTlj NzEwZTk4YzcuLmM0Nzk2MjM3MjRlOCAxMDA2NDQKPiAtLS0gYS9kcml2ZXJzL3B3bS9NYWtlZmls ZQo+ICsrKyBiL2RyaXZlcnMvcHdtL01ha2VmaWxlCj4gQEAgLTQxLDYgKzQxLDcgQEAgb2JqLSQo Q09ORklHX1BXTV9SRU5FU0FTX1RQVSkJKz0gcHdtLXJlbmVzYXMtdHB1Lm8KPiAgb2JqLSQoQ09O RklHX1BXTV9ST0NLQ0hJUCkJKz0gcHdtLXJvY2tjaGlwLm8KPiAgb2JqLSQoQ09ORklHX1BXTV9T QU1TVU5HKQkrPSBwd20tc2Ftc3VuZy5vCj4gIG9iai0kKENPTkZJR19QV01fU0lGSVZFKQkrPSBw d20tc2lmaXZlLm8KPiArb2JqLSQoQ09ORklHX1BXTV9TTDI4Q1BMRCkJKz0gcHdtLXNsMjhjcGxk Lm8KPiAgb2JqLSQoQ09ORklHX1BXTV9TUEVBUikJCSs9IHB3bS1zcGVhci5vCj4gIG9iai0kKENP TkZJR19QV01fU1BSRCkJCSs9IHB3bS1zcHJkLm8KPiAgb2JqLSQoQ09ORklHX1BXTV9TVEkpCQkr PSBwd20tc3RpLm8KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9wd20vcHdtLXNsMjhjcGxkLmMgYi9k cml2ZXJzL3B3bS9wd20tc2wyOGNwbGQuYwo+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4gaW5kZXgg MDAwMDAwMDAwMDAwLi5kODIzMDNmNTA5ZjUKPiAtLS0gL2Rldi9udWxsCj4gKysrIGIvZHJpdmVy cy9wd20vcHdtLXNsMjhjcGxkLmMKPiBAQCAtMCwwICsxLDIwMSBAQAo+ICsvLyBTUERYLUxpY2Vu c2UtSWRlbnRpZmllcjogR1BMLTIuMC1vbmx5Cj4gKy8qCj4gKyAqIHNsMjhjcGxkIFBXTSBkcml2 ZXIuCj4gKyAqCj4gKyAqIENvcHlyaWdodCAyMDE5IEtvbnRyb24gRXVyb3BlIEdtYkgKClRoaXMg aXMgb3V0IG9mIGRhdGUuCgo+ICsgKi8KPiArCj4gKyNpbmNsdWRlIDxsaW51eC9iaXRmaWVsZC5o Pgo+ICsjaW5jbHVkZSA8bGludXgva2VybmVsLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9tb2R1bGUu aD4KPiArI2luY2x1ZGUgPGxpbnV4L29mX2RldmljZS5oPgo+ICsjaW5jbHVkZSA8bGludXgvcGxh dGZvcm1fZGV2aWNlLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9wd20uaD4KPiArI2luY2x1ZGUgPGxp bnV4L3JlZ21hcC5oPgo+ICsKPiArLyoKPiArICogUFdNIHRpbWVyIGJsb2NrIHJlZ2lzdGVycy4K PiArICovCj4gKyNkZWZpbmUgUFdNX0NUUkwJCTB4MDAKPiArI2RlZmluZSAgIFBXTV9FTkFCTEUJ CUJJVCg3KQo+ICsjZGVmaW5lICAgUFdNX01PREVfMjUwSFoJMAo+ICsjZGVmaW5lICAgUFdNX01P REVfNTAwSFoJMQo+ICsjZGVmaW5lICAgUFdNX01PREVfMUtIWgkJMgo+ICsjZGVmaW5lICAgUFdN X01PREVfMktIWgkJMwo+ICsjZGVmaW5lICAgUFdNX01PREVfTUFTSwkJR0VOTUFTSygxLCAwKQo+ ICsjZGVmaW5lIFBXTV9DWUNMRQkJMHgwMQo+ICsjZGVmaW5lICAgUFdNX0NZQ0xFX01BWAkJMHg3 Zgo+ICsKPiArc3RydWN0IHNsMjhjcGxkX3B3bSB7Cj4gKwlzdHJ1Y3QgcHdtX2NoaXAgcHdtX2No aXA7Cj4gKwlzdHJ1Y3QgcmVnbWFwICpyZWdtYXA7Cj4gKwl1MzIgb2Zmc2V0Owo+ICt9Owo+ICsK PiArc3RydWN0IHNsMjhjcGxkX3B3bV9wZXJpb2RzIHsKPiArCXU4IGN0cmw7Cj4gKwl1bnNpZ25l ZCBsb25nIGR1dHlfY3ljbGU7Cj4gK307Cj4gKwo+ICtzdHJ1Y3Qgc2wyOGNwbGRfcHdtX2NvbmZp ZyB7Cj4gKwl1bnNpZ25lZCBsb25nIHBlcmlvZF9uczsKPiArCXU4IG1heF9kdXR5X2N5Y2xlOwo+ ICt9OwoKQWxzbywgaW5zdGVhZCBvZiBoYW5kIHJvbGxpbmcgeW91ciBvd24gc3RydWN0dXJlIGhl cmUsIEkgdGhpbmsgaXQKd291bGQgYmUgcHJ1ZGVudCB0byByZS11c2Ugc29tZXRoaW5nIHRoYXQg YWxyZWFkeSBleGlzdHMuICBTZWVpbmcgYXMKdGhpcyB3aWxsIGJlIHVzZWQgdG8gZGVzY3JpYmUg cG9zc2libGUgc3RhdGUsIHBlcmhhcHMgJ3N0cnVjdApwd21fc3RhdGUnIHdvdWxkIGJlIHN1aXRh YmxlIC0gbGVhdmluZyBwb2xhcml0eSBhbmQgZW5hYmxlZAp1bnBvcHVsYXRlZCBvZiBjb3Vyc2Uu CgpBaCB3YWl0IChzb3JyeSwgdGhpbmtpbmcgYWxsb3dlZCBhbmQgb24tdGhlLWZseSBoZXJlKSwg d2hhdCBpcwptYXhfZHV0eV9jeWNsZSBoZXJlPyAgSSBhc3N1bWUgdGhpcyBkb2VzIG5vdCBoYXZl IHRoZSBzYW1lCm1lYW5pbmcvdmFsdWUtdHlwZSBhcyB0aGUgb25lIGluICdzdHJ1Y3QgcHdtX3N0 YXRlJy4gIFdoYXQgZG9lcwptYXhfZHV0eV9jeWNsZSByZXByZXNlbnQgaW4geW91ciB1c2UtY2Fz ZT8KCj4gK3N0YXRpYyBzdHJ1Y3Qgc2wyOGNwbGRfcHdtX2NvbmZpZyBzbDI4Y3BsZF9wd21fY29u ZmlnW10gPSB7Cj4gKwlbUFdNX01PREVfMjUwSFpdID0geyAucGVyaW9kX25zID0gNDAwMDAwMCwg Lm1heF9kdXR5X2N5Y2xlID0gMHg4MCB9LAo+ICsJW1BXTV9NT0RFXzUwMEhaXSA9IHsgLnBlcmlv ZF9ucyA9IDIwMDAwMDAsIC5tYXhfZHV0eV9jeWNsZSA9IDB4NDAgfSwKPiArCVtQV01fTU9ERV8x S0haXSA9IHsgLnBlcmlvZF9ucyA9IDEwMDAwMDAsIC5tYXhfZHV0eV9jeWNsZSA9IDB4MjAgfSwK PiArCVtQV01fTU9ERV8yS0haXSA9IHsgLnBlcmlvZF9ucyA9ICA1MDAwMDAsIC5tYXhfZHV0eV9j eWNsZSA9IDB4MTAgfSwKPiArfTsKClRpbnkgbml0OiBJZiB5b3UgbGluZWQgdGhlc2UgdXAgZnJv bSB0aGUgJ3sncyBpdCB3b3VsZCBiZSBlYXNpZXIgdG8Kc2VlL2NvbXBhcmUgdGhlIHBlcmlvZF9u cyB2YWx1ZXMgYXQgZmlyc3QgZ2xhbmNlLCByYXRoZXIgdGhhbiBoYXZpbmcKdG8gY291bnQgdGhl ICcgJ3MgYW5kICcwJ3MuCgo+ICtzdGF0aWMgaW5saW5lIHN0cnVjdCBzbDI4Y3BsZF9wd20gKnRv X3NsMjhjcGxkX3B3bShzdHJ1Y3QgcHdtX2NoaXAgKmNoaXApCj4gK3sKPiArCXJldHVybiBjb250 YWluZXJfb2YoY2hpcCwgc3RydWN0IHNsMjhjcGxkX3B3bSwgcHdtX2NoaXApOwo+ICt9CgpXaHkg bm90IHNhdmUgeW91cnNlbGYgdGhlIHRyb3VibGUgYW5kIGp1c3Q6CgogIHN0cnVjdCBzbDI4Y3Bs ZF9wd20gKnB3bSA9IGRldl9nZXRfZHJ2ZGF0YShjaGlwLT5kZXYpOwoKPiArc3RhdGljIHZvaWQg c2wyOGNwbGRfcHdtX2dldF9zdGF0ZShzdHJ1Y3QgcHdtX2NoaXAgKmNoaXAsCj4gKwkJCQkgICBz dHJ1Y3QgcHdtX2RldmljZSAqcHdtLAo+ICsJCQkJICAgc3RydWN0IHB3bV9zdGF0ZSAqc3RhdGUp Cj4gK3sKPiArCXN0cnVjdCBzbDI4Y3BsZF9wd20gKnNwYyA9IHRvX3NsMjhjcGxkX3B3bShjaGlw KTsKPiArCXN0YXRpYyBzdHJ1Y3Qgc2wyOGNwbGRfcHdtX2NvbmZpZyAqY29uZmlnOwo+ICsJdW5z aWduZWQgaW50IHJlZzsKPiArCXVuc2lnbmVkIGxvbmcgY3ljbGU7CgpXaHkgaXMgdGhpcyAnbG9u ZycgaGVyZSBhbmQgJ2xvbmcgbG9uZycgaW4gKl9hcHBseSgpPwoKPiArCXVuc2lnbmVkIGludCBt b2RlOwo+ICsKPiArCXJlZ21hcF9yZWFkKHNwYy0+cmVnbWFwLCBzcGMtPm9mZnNldCArIFBXTV9D VFJMLCAmcmVnKTsKPiArCj4gKwlzdGF0ZS0+ZW5hYmxlZCA9IHJlZyAmIFBXTV9FTkFCTEU7Cj4g Kwo+ICsJbW9kZSA9IEZJRUxEX0dFVChQV01fTU9ERV9NQVNLLCByZWcpOwo+ICsJY29uZmlnID0g JnNsMjhjcGxkX3B3bV9jb25maWdbbW9kZV07Cj4gKwlzdGF0ZS0+cGVyaW9kID0gY29uZmlnLT5w ZXJpb2RfbnM7Cj4gKwo+ICsJcmVnbWFwX3JlYWQoc3BjLT5yZWdtYXAsIHNwYy0+b2Zmc2V0ICsg UFdNX0NZQ0xFLCAmcmVnKTsKPiArCWN5Y2xlID0gcmVnICogY29uZmlnLT5wZXJpb2RfbnM7Cj4g KwlzdGF0ZS0+ZHV0eV9jeWNsZSA9IERJVl9ST1VORF9DTE9TRVNUX1VMTChjeWNsZSwKPiArCQkJ CQkJICBjb25maWctPm1heF9kdXR5X2N5Y2xlKTsKPiArfQo+ICsKPiArc3RhdGljIGludCBzbDI4 Y3BsZF9wd21fYXBwbHkoc3RydWN0IHB3bV9jaGlwICpjaGlwLCBzdHJ1Y3QgcHdtX2RldmljZSAq cHdtLAo+ICsJCQkgICAgICBjb25zdCBzdHJ1Y3QgcHdtX3N0YXRlICpzdGF0ZSkKPiArewo+ICsJ c3RydWN0IHNsMjhjcGxkX3B3bSAqc3BjID0gdG9fc2wyOGNwbGRfcHdtKGNoaXApOwo+ICsJc3Ry dWN0IHNsMjhjcGxkX3B3bV9jb25maWcgKmNvbmZpZzsKPiArCXVuc2lnbmVkIGxvbmcgbG9uZyBj eWNsZTsKPiArCWludCByZXQ7Cj4gKwlpbnQgbW9kZTsKPiArCXU4IGN0cmw7Cj4gKwo+ICsJLyog dXBkYXRlIGNvbmZpZywgZmlyc3Qgc2VhcmNoIGJlc3QgbWF0Y2hpbmcgcGVyaW9kICovCgpQbGVh c2UgdXNlIGNvcnJlY3QgZ3JhbW1hciAobGVzcyBmdWxsIHN0b3BzKSBpbiBjb21tZW50cy4KCj4g Kwlmb3IgKG1vZGUgPSAwOyBtb2RlIDwgQVJSQVlfU0laRShzbDI4Y3BsZF9wd21fY29uZmlnKTsg bW9kZSsrKSB7Cj4gKwkJY29uZmlnID0gJnNsMjhjcGxkX3B3bV9jb25maWdbbW9kZV07Cj4gKwkJ aWYgKHN0YXRlLT5wZXJpb2QgPT0gY29uZmlnLT5wZXJpb2RfbnMpCj4gKwkJCWJyZWFrOwo+ICsJ fQo+ICsKPiArCWlmIChtb2RlID09IEFSUkFZX1NJWkUoc2wyOGNwbGRfcHdtX2NvbmZpZykpCj4g KwkJcmV0dXJuIC1FSU5WQUw7Cj4gKwo+ICsJY3RybCA9IEZJRUxEX1BSRVAoUFdNX01PREVfTUFT SywgbW9kZSk7Cj4gKwlpZiAoc3RhdGUtPmVuYWJsZWQpCj4gKwkJY3RybCB8PSBQV01fRU5BQkxF Owo+ICsKPiArCWN5Y2xlID0gc3RhdGUtPmR1dHlfY3ljbGUgKiBjb25maWctPm1heF9kdXR5X2N5 Y2xlOwo+ICsJZG9fZGl2KGN5Y2xlLCBzdGF0ZS0+cGVyaW9kKTsKCkZvcmdpdmUgbXkgaWdub3Jh bmNlIChJJ20gbmV3IGhlcmUhKSwgYnV0IHdoYXQgYXJlIHRoZXNlIDIgbGluZXMKZG9pbmc/ICBI ZXJlIHdlIGFyZSBtdWx0aXBseWluZyB0aGUgY3VycmVudCBkdXR5X2N5Y2xlIHdpdGggdGhlCm1h eGltdW0gdmFsdWUsIHRoZW4gZGl2aWRpbmcgYnkgdGhlIHBlcmlvZC4KClNvIGluIHRoZSBjYXNl IG9mIFBXTV9NT0RFXzFLSFogd2l0aCBhIDUwJSBkdXR5IGN5Y2xlLCB5b3UnZCBoYXZlOgoKICAg KDUwMDAwMCAqIDB4MjBbMTZdKSAvIDEwMDAwMDAgPSBbMHgxMF0xNgoKVGh1cywgdGhlIGFib3Zl IGdpdmVzIGFzIGEgcHJvcG9ydGlvbmFsIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBtYXhpbXVtCnZh bGlkIHZhbHVlIGZvciBwbGFjZW1lbnQgaW50byB0aGUgY3ljbGUgY29udHJvbCByZWdpc3Rlcihz KSwgcmlnaHQ/CgpFaXRoZXIgd2F5ICh3aGV0aGVyIEknbSBjb3JyZWN0IG9yIG5vdCksIEkgdGhp bmsgaXQgd291bGQgYmUgbmljZSB0bwptZW50aW9uIHRoaXMgaW4gYSBjb21tZW50LiAgTWF5YmUg ZXZlbiBjbGFyaWZ5IHdpdGggYSBzaW1wbGUgZXhhbXBsZS4KCj4gKwkvKgo+ICsJICogVGhlIGhh cmR3YXJlIGRvZXNuJ3QgYWxsb3cgdG8gc2V0IG1heF9kdXR5X2N5Y2xlIGlmIHRoZQo+ICsJICog MjUwSHogbW9kZSBpcyBlbmFibGVkLiBCdXQgc2luY2UgdGhpcyBpcyAiYWxsLWhpZ2giIG91dHB1 dAo+ICsJICoganVzdCB1c2UgdGhlIDUwMEh6IG1vZGUgd2l0aCB0aGUgZHV0eSBjeWNsZSB0byBt YXggdmFsdWUuCj4gKwkgKi8KPiArCWlmIChjeWNsZSA9PSBjb25maWctPm1heF9kdXR5X2N5Y2xl KSB7Cj4gKwkJY3RybCAmPSB+UFdNX01PREVfTUFTSzsKPiArCQljdHJsIHw9IEZJRUxEX1BSRVAo UFdNX01PREVfTUFTSywgUFdNX01PREVfNTAwSFopOwo+ICsJCWN5Y2xlID0gUFdNX0NZQ0xFX01B WDsKPiArCX0KClRoaXMgaXMgYmVpbmcgZXhlY3V0ZWQgZXZlbiB3aGVuIDI1MEh6IG1vZGUgaXMg bm90IGVuYWJsZWQuCgpJcyB0aGF0IGJ5IGRlc2lnbj8gIElmIHNvLCBpdCBkb2Vzbid0IG1hdGNo IHRoZSBjb21tZW50LgoKPiArCXJldCA9IHJlZ21hcF93cml0ZShzcGMtPnJlZ21hcCwgc3BjLT5v ZmZzZXQgKyBQV01fQ1RSTCwgY3RybCk7Cj4gKwlpZiAocmV0KQo+ICsJCXJldHVybiByZXQ7Cj4g Kwo+ICsJcmV0dXJuIHJlZ21hcF93cml0ZShzcGMtPnJlZ21hcCwgc3BjLT5vZmZzZXQgKyBQV01f Q1lDTEUsICh1OCljeWNsZSk7Cj4gK30KPiArCj4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgcHdtX29w cyBzbDI4Y3BsZF9wd21fb3BzID0gewo+ICsJLmFwcGx5ID0gc2wyOGNwbGRfcHdtX2FwcGx5LAo+ ICsJLmdldF9zdGF0ZSA9IHNsMjhjcGxkX3B3bV9nZXRfc3RhdGUsCj4gKwkub3duZXIgPSBUSElT X01PRFVMRSwKPiArfTsKPiArCj4gK3N0YXRpYyBpbnQgc2wyOGNwbGRfcHdtX3Byb2JlKHN0cnVj dCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpCj4gK3sKPiArCXN0cnVjdCBzbDI4Y3BsZF9wd20gKnB3 bTsKClRoaXMgaXMgc3VwZXIgY29uZnVzaW5nLiAgSGVyZSB5b3UgY2FsbCBpdCAncHdtJywgYnV0 IHdoZW4geW91IGJyaW5nCnRoZSBkYXRhIHRvIHRoZSBmb3JlIGZvciBjb25zdW1wdGlvbiwgeW91 IGNhbGwgaXQgc29tZXRoaW5nIGRpZmZlcmVudAooJ3NwYycpIGZvciBzb21lIHJlYXNvbi4KCklz IHRoZXJlIGxvZ2ljIGJlaGluZCB0aGlzPwoKPiArCXN0cnVjdCBwd21fY2hpcCAqY2hpcDsKPiAr CWludCByZXQ7Cj4gKwo+ICsJaWYgKCFwZGV2LT5kZXYucGFyZW50KQo+ICsJCXJldHVybiAtRU5P REVWOwo+ICsKPiArCXB3bSA9IGRldm1fa3phbGxvYygmcGRldi0+ZGV2LCBzaXplb2YoKnB3bSks IEdGUF9LRVJORUwpOwo+ICsJaWYgKCFwd20pCj4gKwkJcmV0dXJuIC1FTk9NRU07Cj4gKwo+ICsJ cHdtLT5yZWdtYXAgPSBkZXZfZ2V0X3JlZ21hcChwZGV2LT5kZXYucGFyZW50LCBOVUxMKTsKPiAr CWlmICghcHdtLT5yZWdtYXApCj4gKwkJcmV0dXJuIC1FTk9ERVY7Cj4gKwo+ICsJcmV0ID0gZGV2 aWNlX3Byb3BlcnR5X3JlYWRfdTMyKCZwZGV2LT5kZXYsICJyZWciLCAmcHdtLT5vZmZzZXQpOwoK UmVhbGx5PyAgQ2FuIHlvdSB1c2UgdGhlICdyZWcnIHByb3BlcnR5IGluIHRoaXMgd2F5PwoKU2lk ZSBxdWVzdGlvbjoKICBEbyBhbnkgb2YgeW91ciBjaGlsZCBhZGRyZXNzIHNwYWNlcyBhY3R1YWxs eSBvdmVybGFwL2ludGVyc2VjdD8KCj4gKwlpZiAocmV0KQo+ICsJCXJldHVybiAtRUlOVkFMOwo+ ICsKPiArCS8qIGluaXRpYWxpemUgc3RydWN0IHB3bV9jaGlwICovCgpQcm9wZXIgZ3JhbW1hciBw bGVhc2UuCgo+ICsJY2hpcCA9ICZwd20tPnB3bV9jaGlwOwo+ICsJY2hpcC0+ZGV2ID0gJnBkZXYt PmRldjsKPiArCWNoaXAtPm9wcyA9ICZzbDI4Y3BsZF9wd21fb3BzOwo+ICsJY2hpcC0+YmFzZSA9 IC0xOwo+ICsJY2hpcC0+bnB3bSA9IDE7Cj4gKwo+ICsJcmV0ID0gcHdtY2hpcF9hZGQoJnB3bS0+ cHdtX2NoaXApOwo+ICsJaWYgKHJldCA8IDApCgpJcyAnPiAwJyBldmVuIHZhbGlkPwoKU3VnZ2Vz dCAiIXJldCIgaGVyZSwgYXMgeW91IGhhdmUgZG9uZSBhYm92ZS4KCj4gKwkJcmV0dXJuIHJldDsK PiArCj4gKwlwbGF0Zm9ybV9zZXRfZHJ2ZGF0YShwZGV2LCBwd20pOwo+ICsKPiArCXJldHVybiAw Owo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHNsMjhjcGxkX3B3bV9yZW1vdmUoc3RydWN0IHBsYXRm b3JtX2RldmljZSAqcGRldikKPiArewo+ICsJc3RydWN0IHNsMjhjcGxkX3B3bSAqcHdtID0gcGxh dGZvcm1fZ2V0X2RydmRhdGEocGRldik7Cj4gKwo+ICsJcmV0dXJuIHB3bWNoaXBfcmVtb3ZlKCZw d20tPnB3bV9jaGlwKTsKPiArfQo+ICsKPiArc3RhdGljIGNvbnN0IHN0cnVjdCBvZl9kZXZpY2Vf aWQgc2wyOGNwbGRfcHdtX29mX21hdGNoW10gPSB7Cj4gKwl7IC5jb21wYXRpYmxlID0gImtvbnRy b24sc2wyOGNwbGQtcHdtIiB9LAo+ICsJe30sCj4gK307Cj4gK01PRFVMRV9ERVZJQ0VfVEFCTEUo b2YsIHNsMjhjcGxkX3B3bV9vZl9tYXRjaCk7Cj4gKwo+ICtzdGF0aWMgY29uc3Qgc3RydWN0IHBs YXRmb3JtX2RldmljZV9pZCBzbDI4Y3BsZF9wd21faWRfdGFibGVbXSA9IHsKPiArCXsic2wyOGNw bGQtcHdtIn0sCgpTcGFjZXMgZWl0aGVyIHNpZGUgb2YgdGhlICIncyBwbGVhc2UuCgo+ICsJe30s Cj4gK307Cj4gK01PRFVMRV9ERVZJQ0VfVEFCTEUocGxhdGZvcm0sIHNsMjhjcGxkX3B3bV9pZF90 YWJsZSk7CgpXaGF0IGFyZSB5b3UgdXNpbmcgdGhpcyBmb3I/Cgo+ICtzdGF0aWMgc3RydWN0IHBs YXRmb3JtX2RyaXZlciBzbDI4Y3BsZF9wd21fZHJpdmVyID0gewo+ICsJLnByb2JlID0gc2wyOGNw bGRfcHdtX3Byb2JlLAo+ICsJLnJlbW92ZQk9IHNsMjhjcGxkX3B3bV9yZW1vdmUsCj4gKwkuaWRf dGFibGUgPSBzbDI4Y3BsZF9wd21faWRfdGFibGUsCj4gKwkuZHJpdmVyID0gewo+ICsJCS5uYW1l ID0gS0JVSUxEX01PRE5BTUUsCgpQbGVhc2UganVzdCB1c2UgdGhlIHF1b3RlZCBuYW1lIGluIGZ1 bGwuCgo+ICsJCS5vZl9tYXRjaF90YWJsZSA9IHNsMjhjcGxkX3B3bV9vZl9tYXRjaCwKPiArCX0s Cj4gK307Cj4gK21vZHVsZV9wbGF0Zm9ybV9kcml2ZXIoc2wyOGNwbGRfcHdtX2RyaXZlcik7Cj4g Kwo+ICtNT0RVTEVfREVTQ1JJUFRJT04oInNsMjhjcGxkIFBXTSBEcml2ZXIiKTsKCiJTTDI4Q1BM RCIgPwoKPiArTU9EVUxFX0FVVEhPUigiTWljaGFlbCBXYWxsZSA8bWljaGFlbEB3YWxsZS5jYz4i KTsKPiArTU9EVUxFX0xJQ0VOU0UoIkdQTCIpOwoKLS0gCkxlZSBKb25lcyBb5p2O55C85pavXQpM aW5hcm8gU2VydmljZXMgVGVjaG5pY2FsIExlYWQKTGluYXJvLm9yZyDilIIgT3BlbiBzb3VyY2Ug c29mdHdhcmUgZm9yIEFSTSBTb0NzCkZvbGxvdyBMaW5hcm86IEZhY2Vib29rIHwgVHdpdHRlciB8 IEJsb2cKCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fCmxp bnV4LWFybS1rZXJuZWwgbWFpbGluZyBsaXN0CmxpbnV4LWFybS1rZXJuZWxAbGlzdHMuaW5mcmFk ZWFkLm9yZwpodHRwOi8vbGlzdHMuaW5mcmFkZWFkLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2xpbnV4 LWFybS1rZXJuZWwK