From: Alexandre Belloni <alexandre.belloni@bootlin.com>
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, Andy Shevchenko <andy@kernel.org>,
Linus Walleij <linus.walleij@linaro.org>,
Alessandro Zummo <a.zummo@towertech.it>,
Bartosz Golaszewski <brgl@bgdev.pl>,
linux-rtc@vger.kernel.org
Subject: Re: [PATCH v4 4/7] platform: cznic: turris-omnia-mcu: Add support for poweroff and wakeup
Date: Fri, 3 Nov 2023 20:23:16 +0100 [thread overview]
Message-ID: <202311031923161422b866@mail.local> (raw)
In-Reply-To: <20231026161803.16750-5-kabel@kernel.org>
On 26/10/2023 18:18:00+0200, Marek Behún wrote:
> +static int omnia_get_uptime_wakeup(const struct i2c_client *client, u32 *uptime,
> + u32 *wakeup)
> +{
> + __le32 reply[2];
> + int err;
> +
> + err = omnia_cmd_read(client, CMD_GET_UPTIME_AND_WAKEUP, reply,
> + sizeof(reply));
> + if (err)
> + return err;
> +
> + if (uptime)
> + *uptime = le32_to_cpu(reply[0]);
> +
> + if (wakeup)
> + *wakeup = le32_to_cpu(reply[1]);
> +
> + return 0;
> +}
> +
> +static int omnia_read_time(struct device *dev, struct rtc_time *tm)
> +{
> + u32 uptime;
> + int err;
> +
> + err = omnia_get_uptime_wakeup(to_i2c_client(dev), &uptime, NULL);
> + if (err)
> + return err;
Does this get the real time or the board uptime?
> +
> + rtc_time64_to_tm(uptime, tm);
> +
> + return 0;
> +}
> +
> +static int omnia_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> + struct i2c_client *client = to_i2c_client(dev);
> + struct omnia_mcu *mcu = i2c_get_clientdata(client);
> + u32 wakeup;
> + int err;
> +
> + err = omnia_get_uptime_wakeup(client, NULL, &wakeup);
> + if (err)
> + return err;
> +
> + alrm->enabled = !!wakeup;
> + rtc_time64_to_tm(wakeup ?: mcu->rtc_alarm, &alrm->time);
I don't think this works properly as on boot, mcu->rtc_alarm will not be
set whereas wakeup could be.
Also, is wakeup actually an absolute time? I'm not sure I get how the
MCU works then.
> +
> + return 0;
> +}
> +
> +static int omnia_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> + struct i2c_client *client = to_i2c_client(dev);
> + struct omnia_mcu *mcu = i2c_get_clientdata(client);
> +
> + mcu->rtc_alarm = rtc_tm_to_time64(&alrm->time);
> +
> + if (alrm->enabled)
> + return omnia_cmd_write_u32(client, CMD_SET_WAKEUP,
> + mcu->rtc_alarm);
> +
> + return 0;
> +}
> +
> +static int omnia_alarm_irq_enable(struct device *dev, unsigned int enabled)
> +{
> + struct i2c_client *client = to_i2c_client(dev);
> + struct omnia_mcu *mcu = i2c_get_clientdata(client);
> +
> + return omnia_cmd_write_u32(client, CMD_SET_WAKEUP,
> + enabled ? mcu->rtc_alarm : 0);
> +}
> +
> +static const struct rtc_class_ops omnia_rtc_ops = {
> + .read_time = omnia_read_time,
> + .read_alarm = omnia_read_alarm,
> + .set_alarm = omnia_set_alarm,
> + .alarm_irq_enable = omnia_alarm_irq_enable,
> +};
> +
> +static int omnia_power_off(struct sys_off_data *data)
> +{
> + struct omnia_mcu *mcu = data->cb_data;
> + __be32 tmp;
> + u8 cmd[9];
> + u16 arg;
> + int err;
> +
> + if (mcu->front_button_poweron)
> + arg = CMD_POWER_OFF_POWERON_BUTTON;
> + else
> + arg = 0;
> +
> + cmd[0] = CMD_POWER_OFF;
> + put_unaligned_le16(CMD_POWER_OFF_MAGIC, &cmd[1]);
> + put_unaligned_le16(arg, &cmd[3]);
> +
> + /*
> + * Although all values from and to MCU are passed in little-endian, the
> + * MCU's CRC unit uses big-endian CRC32 polynomial (0x04c11db7), so we
> + * need to use crc32_be() here.
> + */
> + tmp = cpu_to_be32(get_unaligned_le32(&cmd[1]));
> + put_unaligned_le32(crc32_be(0xffffffff, (void *)&tmp, sizeof(tmp)),
> + &cmd[5]);
> +
> + err = omnia_cmd_write(mcu->client, cmd, sizeof(cmd));
> + if (err)
> + dev_err(&mcu->client->dev,
> + "Unable to send the poweroff command: %d\n", err);
> +
> + return NOTIFY_DONE;
> +}
> +
> +static int omnia_restart(struct sys_off_data *data)
> +{
> + struct omnia_mcu *mcu = data->cb_data;
> + u8 cmd[3];
> + int err;
> +
> + cmd[0] = CMD_GENERAL_CONTROL;
> +
> + if (reboot_mode == REBOOT_HARD)
> + cmd[1] = cmd[2] = CTL_HARD_RST;
> + else
> + cmd[1] = cmd[2] = CTL_LIGHT_RST;
> +
> + err = omnia_cmd_write(mcu->client, cmd, sizeof(cmd));
> + if (err)
> + dev_err(&mcu->client->dev,
> + "Unable to send the restart command: %d\n", err);
> +
> + /*
> + * MCU needs a little bit to process the I2C command, otherwise it will
> + * do a light reset based on SOC SYSRES_OUT pin.
> + */
> + mdelay(1);
> +
> + return NOTIFY_DONE;
> +}
> +
> +static ssize_t front_button_poweron_show(struct device *dev,
> + struct device_attribute *a, char *buf)
> +{
> + struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));
> +
> + return sysfs_emit(buf, "%d\n", mcu->front_button_poweron);
> +}
> +
> +static ssize_t front_button_poweron_store(struct device *dev,
> + struct device_attribute *a,
> + const char *buf, size_t count)
> +{
> + struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));
> + bool val;
> + int err;
> +
> + err = kstrtobool(buf, &val);
> + if (err)
> + return err;
> +
> + mcu->front_button_poweron = val;
> +
> + return count;
> +}
> +static DEVICE_ATTR_RW(front_button_poweron);
> +
> +static struct attribute *omnia_mcu_poweroff_attrs[] = {
> + &dev_attr_front_button_poweron.attr,
> + NULL
> +};
> +
> +static umode_t poweroff_attrs_visible(struct kobject *kobj, struct attribute *a,
> + int n)
> +{
> + struct device *dev = kobj_to_dev(kobj);
> + struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));
> +
> + if (mcu->features & FEAT_POWEROFF_WAKEUP)
> + return a->mode;
> +
> + return 0;
> +}
> +
> +const struct attribute_group omnia_mcu_poweroff_group = {
> + .attrs = omnia_mcu_poweroff_attrs,
> + .is_visible = poweroff_attrs_visible,
> +};
> +
> +int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu)
> +{
> + struct device *dev = &mcu->client->dev;
> + int err;
> +
> + /* MCU restart is always available */
> + err = devm_register_sys_off_handler(dev, SYS_OFF_MODE_RESTART,
> + SYS_OFF_PRIO_FIRMWARE,
> + omnia_restart, mcu);
> + if (err)
> + return dev_err_probe(dev, err,
> + "Cannot register system restart handler\n");
> +
> + /*
> + * Poweroff and wakeup are available only if POWEROFF_WAKEUP feature is
> + * present.
> + */
> + if (!(mcu->features & FEAT_POWEROFF_WAKEUP))
> + return 0;
> +
> + err = devm_register_sys_off_handler(dev, SYS_OFF_MODE_POWER_OFF,
> + SYS_OFF_PRIO_FIRMWARE,
> + omnia_power_off, mcu);
> + if (err)
> + return dev_err_probe(dev, err,
> + "Cannot register system power off handler\n");
> +
> + mcu->rtcdev = devm_rtc_allocate_device(dev);
> + if (IS_ERR(mcu->rtcdev))
> + return dev_err_probe(dev, PTR_ERR(mcu->rtcdev),
> + "Cannot allocate RTC device\n");
> +
> + mcu->rtcdev->ops = &omnia_rtc_ops;
> + mcu->rtcdev->range_max = U32_MAX;
You probably need to add:
set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, mcu->rtcdev->features);
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
next prev parent reply other threads:[~2023-11-03 19:23 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-10-26 16:17 [PATCH v4 0/7] Turris Omnia MCU driver Marek Behún
2023-10-26 16:17 ` [PATCH v4 1/7] dt-bindings: arm: add cznic,turris-omnia-mcu binding Marek Behún
2023-10-27 8:43 ` Marek Behún
2023-10-26 16:17 ` [PATCH v4 2/7] platform: cznic: Add preliminary support for Turris Omnia MCU Marek Behún
2023-10-26 16:17 ` [PATCH v4 3/7] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs Marek Behún
2023-11-01 11:38 ` Marek Behún
2023-12-08 14:26 ` Gregory CLEMENT
2023-12-08 15:27 ` Marek Behún
2023-10-26 16:18 ` [PATCH v4 4/7] platform: cznic: turris-omnia-mcu: Add support for poweroff and wakeup Marek Behún
2023-11-03 19:23 ` Alexandre Belloni [this message]
2023-12-08 15:46 ` Marek Behún
2023-10-26 16:18 ` [PATCH v4 5/7] platform: cznic: turris-omnia-mcu: Add support for MCU watchdog Marek Behún
2023-10-26 16:18 ` [PATCH v4 6/7] ARM: dts: turris-omnia: Add MCU system-controller node Marek Behún
2023-10-26 16:18 ` [PATCH v4 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=202311031923161422b866@mail.local \
--to=alexandre.belloni@bootlin.com \
--cc=a.zummo@towertech.it \
--cc=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-rtc@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.