From: Andy Shevchenko <andy@kernel.org>
To: "Marek Behún" <kabel@kernel.org>
Cc: Gregory CLEMENT <gregory.clement@bootlin.com>,
Arnd Bergmann <arnd@arndb.de>,
soc@kernel.org, arm@kernel.org,
Linus Walleij <linus.walleij@linaro.org>,
Bartosz Golaszewski <brgl@bgdev.pl>,
linux-gpio@vger.kernel.org
Subject: Re: [PATCH v2 3/7] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs
Date: Tue, 19 Sep 2023 16:00:39 +0300 [thread overview]
Message-ID: <ZQmbd211FzPjA97r@smile.fi.intel.com> (raw)
In-Reply-To: <20230919103815.16818-4-kabel@kernel.org>
On Tue, Sep 19, 2023 at 12:38:11PM +0200, Marek Behún wrote:
> Add support for GPIOs connected to the MCU on the Turris Omnia board.
>
> This include:
includes
> - front button pin
> - enable pins for USB regulators
> - MiniPCIe / mSATA card presence pins in MiniPCIe port 0
> - LED output pins from WAN ethernet PHY, LAN switch and MiniPCIe ports
> - on board revisions 32+ also various peripheral resets and another
> voltage regulator enable pin
Can the main driver provide a regmap and all other use it?
...
> +Date: August 2023
> +KernelVersion: 6.6
Same as per previous patch review.
...
> + ret = omnia_mcu_register_gpiochip(mcu);
> + if (ret)
> + return ret;
> +
> return 0;
return ..._gpiochip(...);
?
...
> + switch (cmd) {
> + case CMD_GENERAL_CONTROL:
> + buf[1] = val;
> + buf[2] = mask;
> + len = 3;
> + break;
> +
> + case CMD_EXT_CONTROL:
> + put_unaligned_le16(val, &buf[1]);
> + put_unaligned_le16(mask, &buf[3]);
> + len = 5;
> + break;
> +
> + default:
> + unreachable();
You meant BUG_ON()?
> + }
...
> +static int omnia_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
> +{
> + struct omnia_mcu *mcu = gpiochip_get_data(gc);
> +
> + if (offset == OMNIA_GPIO_PHY_SFP_OFFSET) {
> + int val;
> +
> + mutex_lock(&mcu->lock);
> + val = omnia_cmd_read_bit(mcu->client,
> + CMD_GET_EXT_CONTROL_STATUS,
> + EXT_CTL_PHY_SFP_AUTO);
> + mutex_unlock(&mcu->lock);
> +
> + if (val < 0)
> + return val;
> +
> + if (val)
> + return GPIO_LINE_DIRECTION_IN;
> + else
Redundant 'else'.
> + return GPIO_LINE_DIRECTION_OUT;
> + }
> +
> + if (omnia_gpios[offset].ctl_cmd)
> + return GPIO_LINE_DIRECTION_OUT;
> + else
Ditto.
> + return GPIO_LINE_DIRECTION_IN;
> +}
...
> + if (offset == OMNIA_GPIO_PHY_SFP_OFFSET)
> + return omnia_ctl_cmd(mcu, CMD_EXT_CONTROL, EXT_CTL_PHY_SFP_AUTO,
> + EXT_CTL_PHY_SFP_AUTO);
> +
> + if (gpio->ctl_cmd)
> + return -EOPNOTSUPP;
I believe internally we use ENOTSUPP.
Ditto for all cases like this.
...
> + uint16_t val, mask;
So, why uintXX_t out of a sudden?
...
> + if (gpio->ctl_cmd)
> + return omnia_ctl_cmd(mcu, gpio->ctl_cmd, val, mask);
> + else
Redundant 'else'.
> + return -EOPNOTSUPP;
> +}
...
> +static void omnia_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
> +{
> + const struct omnia_gpio *gpio = &omnia_gpios[offset];
> + struct omnia_mcu *mcu = gpiochip_get_data(gc);
> + u16 val, mask;
> + int err = 0;
Redundant assignment.
> + if (!gpio->ctl_cmd)
> + return;
> +
> + mask = gpio->ctl_bit;
> + val = value ? mask : 0;
> +
> + err = omnia_ctl_cmd(mcu, gpio->ctl_cmd, val, mask);
> + if (err)
> + dev_err(&mcu->client->dev, "Cannot set GPIO %u: %d\n",
> + offset, err);
> +}
...
> + mutex_lock(&mcu->lock);
> +
> + if (ctl_mask)
> + err = omnia_ctl_cmd_unlocked(mcu, CMD_GENERAL_CONTROL, ctl,
> + ctl_mask);
> + if (!err && ext_ctl_mask)
> + err = omnia_ctl_cmd_unlocked(mcu, CMD_EXT_CONTROL, ext_ctl,
> + ext_ctl_mask);
Can it be
if (err)
goto out_unlock;
if (_mask)
...
?
> + mutex_unlock(&mcu->lock);
> + if (err)
> + dev_err(&mcu->client->dev, "Cannot set GPIOs: %d\n", err);
How is useful this one?
...
> +static bool omnia_gpio_available(struct omnia_mcu *mcu,
> + const struct omnia_gpio *gpio)
> +{
> + if (gpio->feat_mask)
> + return (mcu->features & gpio->feat_mask) == gpio->feat;
> + else if (gpio->feat)
> + return mcu->features & gpio->feat;
> + else
Redundant 'else':s.
> + return true;
> +}
...
> +static int omnia_gpio_init_valid_mask(struct gpio_chip *gc,
> + unsigned long *valid_mask,
> + unsigned int ngpios)
> +{
> + struct omnia_mcu *mcu = gpiochip_get_data(gc);
> + bitmap_zero(valid_mask, ngpios);
No need.
Also do you have bitops.h included?
> + for (int i = 0; i < ngpios; ++i) {
> + const struct omnia_gpio *gpio = &omnia_gpios[i];
> +
> + if (!gpio->cmd && !gpio->int_bit)
> + continue;
Use clear_bit() here...
> + if (omnia_gpio_available(mcu, gpio))
> + set_bit(i, valid_mask);
...and assign_bit() here.
> + }
> +
> + return 0;
> +}
...
> + dev_dbg(&mcu->client->dev,
> + "set int mask %02x %02x %02x %02x %02x %02x %02x %02x\n",
> + cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8]);
%8ph
...
> + /*
> + * Remember which GPIOs have both rising and falling interrupts enabled.
> + * For those we will cache their value so that .get() method is faster.
> + * We also need to forget cached values of GPIOs that aren't cached
> + * anymore.
> + */
> + if (!err) {
if (err)
goto out_unlock;
> + mcu->both = rising & falling;
> + mcu->is_cached &= mcu->both;
> + }
> +
> + mutex_unlock(&mcu->lock);
...
> +static void omnia_irq_init_valid_mask(struct gpio_chip *gc,
> + unsigned long *valid_mask,
> + unsigned int ngpios)
> +{
> + struct omnia_mcu *mcu = gpiochip_get_data(gc);
> + bitmap_zero(valid_mask, ngpios);
No need (see above how).
> + for (int i = 0; i < ngpios; ++i) {
> + const struct omnia_gpio *gpio = &omnia_gpios[i];
> +
> + if (!gpio->int_bit)
> + continue;
> +
> + if (omnia_gpio_available(mcu, gpio))
> + set_bit(i, valid_mask);
> + }
> +}
...
> + u8 cmd[9] = {};
Magic number in a few places. Please, use self-explanatory pre-defined constant
instead.
...
> + dev_err(&mcu->client->dev, "Cannot read pending IRQs: %d\n",
> + err);
In all functions with help of
struct device *dev = &mcu->client->dev;
you can make code shorter.
...
> + rising = reply[0] | (reply[2] << 8) | (reply[4] << 16) |
> + (reply[6] << 24);
> + falling = reply[1] | (reply[3] << 8) | (reply[5] << 16) |
> + (reply[7] << 24);
With a help of two masks, you can access to the both edges as to 64-bit value
and simplify the code.
...
> + int ret = omnia_cmd_read_u16(mcu->client, CMD_GET_STATUS_WORD);
Please, split this for better maintenance.
> + if (ret < 0)
> + return ret;
...
> +static irqreturn_t omnia_irq_thread_handler(int irq, void *dev_id)
> +{
> + struct omnia_mcu *mcu = dev_id;
> + irqreturn_t res = IRQ_NONE;
> + unsigned long pending;
> + int i;
> +
> + if (!omnia_irq_read_pending(mcu, &pending))
> + return IRQ_NONE;
> +
> + for_each_set_bit(i, &pending, 32) {
> + unsigned int nested_irq =
> + irq_find_mapping(mcu->gc.irq.domain,
> + omnia_int_to_gpio_idx[i]);
It's much better to read in a form
unsigned int nested_irq;
domain = ...
nested_irq = irq_find_mapping(domain, omnia_int_to_gpio_idx[i]);
(exactly 80 characters, btw).
> + handle_nested_irq(nested_irq);
> + res = IRQ_HANDLED;
No need.
> + }
> + return res;
return IRQ_RETVAL(pending);
> +}
...
> +static ssize_t front_button_mode_show(struct device *dev,
> + struct device_attribute *a, char *buf)
> +{
> + struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));
> + int val;
> +
> + if (mcu->features & FEAT_NEW_INT_API)
> + val = omnia_cmd_read_bit(mcu->client, CMD_GET_STATUS_WORD,
> + STS_BUTTON_MODE);
> + else
> + val = !!(mcu->last_status & STS_BUTTON_MODE);
> + if (val < 0)
Can be true only in one case, why to check for the second oner?/
> + return val;
> + return sysfs_emit(buf, "%s\n", val ? "cpu" : "mcu");
With a static const array of string literals...
> +}
...
> + if (sysfs_streq(buf, "mcu"))
> + val = 0;
> + else if (sysfs_streq(buf, "cpu"))
> + val = mask;
> + else
> + return -EINVAL;
...and help of sysfs_match_string() you can simplify the code.
...
> +static struct attribute *omnia_mcu_gpio_attrs[] = {
> + &dev_attr_front_button_mode.attr,
> + NULL,
> +};
> +
> +static const struct attribute_group omnia_mcu_gpio_group = {
> + .attrs = omnia_mcu_gpio_attrs,
> +};
ATTRIBUTE_GROUPS() ?
...
> + err = devm_gpiochip_add_data(dev, &mcu->gc, mcu);
> + if (err) {
> + dev_err(dev, "Cannot add GPIO chip: %d\n", err);
> + return err;
return dev_err_probe(...);
Ditto for other places like this in the probe stage.
> + }
...
> + err = devm_device_add_group(dev, &omnia_mcu_gpio_group);
No way, no-one should use the API scheduled for removal.
What's wrong with .dev_groups ?
...
> +void omnia_mcu_unregister_gpiochip(struct omnia_mcu *mcu)
> +{
> + if (!(mcu->features & FEAT_NEW_INT_API))
> + cancel_delayed_work_sync(&mcu->button_release_emul_work);
> +
> + mutex_destroy(&mcu->lock);
Wrong order?
> +}
...
> struct omnia_mcu {
> struct i2c_client *client;
> const char *type;
> u16 features;
> +
> + /* GPIO chip */
> + struct gpio_chip gc;
Making this a first member may lead to the better code. Check with bloat-o-meter.
> + struct mutex lock;
> + u32 mask, rising, falling, both, cached, is_cached;
> + /* Old MCU firmware handling needs the following */
> + u16 last_status;
> + struct delayed_work button_release_emul_work;
Swapping these two may free a few bytes. Check with pahole tool.
> + bool button_pressed_emul;
> };
...
> + if (!bits) {
> + *reply = 0;
> + return 0;
> + }
> +
> + ret = omnia_cmd_read(client, cmd, reply, (ilog2(bits) >> 3) + 1);
> +
Redundant blank line.
> + if (ret >= 0)
> + *reply = le32_to_cpu(*reply) & bits;
Huh?! Please, check your code with sparse like
make W=1 C=1 CF=-D__CHECK_ENDIAN__ ...
> + return ret < 0 ? ret : 0;
--
With Best Regards,
Andy Shevchenko
next prev parent reply other threads:[~2023-09-19 13:00 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-19 10:38 [PATCH v2 0/7] Turris Omnia MCU driver Marek Behún
2023-09-19 10:38 ` [PATCH v2 1/7] dt-bindings: arm: add cznic,turris-omnia-mcu binding Marek Behún
2023-09-20 12:37 ` Krzysztof Kozlowski
2023-09-19 10:38 ` [PATCH v2 2/7] platform: cznic: Add preliminary support for Turris Omnia MCU Marek Behún
2023-09-19 12:29 ` Andy Shevchenko
2023-09-19 15:16 ` Marek Behún
2023-09-19 18:27 ` Andy Shevchenko
2023-09-20 14:19 ` Marek Behún
2023-09-20 14:47 ` Andy Shevchenko
2023-09-19 10:38 ` [PATCH v2 3/7] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs Marek Behún
2023-09-19 13:00 ` Andy Shevchenko [this message]
2023-09-20 17:08 ` Marek Behún
2023-09-21 9:55 ` Andy Shevchenko
2023-09-21 20:25 ` Marek Behún
2023-09-22 14:18 ` Andy Shevchenko
2023-09-25 10:03 ` Marek Behún
2023-09-25 10:29 ` Andy Shevchenko
2023-09-21 18:42 ` Marek Behún
2023-09-22 14:14 ` Andy Shevchenko
2023-09-20 11:58 ` Linus Walleij
2023-09-20 13:36 ` Andy Shevchenko
2023-09-21 19:45 ` Marek Behún
2023-09-21 20:14 ` Marek Behún
2023-09-22 14:21 ` Andy Shevchenko
2023-09-19 10:38 ` [PATCH v2 4/7] platform: cznic: turris-omnia-mcu: Add support for poweroff and wakeup Marek Behún
2023-09-19 10:38 ` [PATCH v2 5/7] platform: cznic: turris-omnia-mcu: Add support for MCU watchdog Marek Behún
2023-09-19 13:50 ` Guenter Roeck
2023-09-22 11:46 ` Marek Behún
2023-09-19 10:38 ` [PATCH v2 6/7] ARM: dts: turris-omnia: Add MCU system-controller node Marek Behún
2023-09-19 10:38 ` [PATCH v2 7/7] ARM: dts: turris-omnia: Add GPIO key node for front button Marek Behún
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZQmbd211FzPjA97r@smile.fi.intel.com \
--to=andy@kernel.org \
--cc=arm@kernel.org \
--cc=arnd@arndb.de \
--cc=brgl@bgdev.pl \
--cc=gregory.clement@bootlin.com \
--cc=kabel@kernel.org \
--cc=linus.walleij@linaro.org \
--cc=linux-gpio@vger.kernel.org \
--cc=soc@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox