Skip to content

Commit 437bf37

Browse files
committed
fixup! drm/tiny: Add driver for the Flipper One display
1 parent d1b6c66 commit 437bf37

3 files changed

Lines changed: 94 additions & 5 deletions

File tree

MAINTAINERS

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7982,10 +7982,6 @@ F: include/linux/aperture.h
79827982
F: include/linux/sysfb.h
79837983
F: include/video/nomodeset.h
79847984

7985-
DRM DRIVER FOR THE FLIPPER ONE DISPLAY
7986-
M: Alexey Charkov <alchark@flipper.net>
7987-
F: drivers/gpu/drm/tiny/flipper-one-display.c
7988-
79897985
DRM DRIVER FOR GENERIC EDP PANELS
79907986
R: Douglas Anderson <dianders@chromium.org>
79917987
F: Documentation/devicetree/bindings/display/panel/panel-edp.yaml

drivers/mfd/flipper-one-mcu.c

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@
1010
#include <linux/mfd/core.h>
1111
#include <linux/mfd/flipper-one-mcu.h>
1212
#include <linux/module.h>
13+
#include <linux/pm.h>
14+
#include <linux/reboot.h>
1315
#include <linux/regmap.h>
1416

1517
static const struct regmap_range fomcu_writeable_reg_ranges[] = {
18+
regmap_reg_range(FOMCU_REG_CPUSTATE, FOMCU_REG_CPUSTATE),
1619
regmap_reg_range(FOMCU_REG_INTMSK_INPUT,
1720
FOMCU_REG_INPUT_BTNS - 1),
1821
regmap_reg_range(FOMCU_REG_LEDS_BR_LINK,
@@ -115,6 +118,34 @@ static const struct mfd_cell cells[] = {
115118
"flipper,one-typec"),
116119
};
117120

121+
static int fomcu_reboot_notify(struct notifier_block *nb,
122+
unsigned long action, void *data)
123+
{
124+
struct fomcu_device *ddata =
125+
container_of(nb, struct fomcu_device, reboot_nb);
126+
127+
/* Runs before device_shutdown() for both reboot and power-off */
128+
regmap_write(ddata->regmap, FOMCU_REG_CPUSTATE,
129+
FOMCU_CPUSTATE_SHUTTING_DOWN);
130+
131+
return NOTIFY_DONE;
132+
}
133+
134+
static int fomcu_power_off(struct sys_off_data *data)
135+
{
136+
struct fomcu_device *ddata = data->cb_data;
137+
138+
/*
139+
* Runs after device_shutdown(), just before the machine is actually
140+
* powered off. Only reached on power-off, not on reboot, so this is
141+
* where we tell the MCU it may cut power to the PMIC.
142+
*/
143+
regmap_write(ddata->regmap, FOMCU_REG_CPUSTATE,
144+
FOMCU_CPUSTATE_POWERED_OFF);
145+
146+
return NOTIFY_DONE;
147+
}
148+
118149
static int fomcu_probe(struct i2c_client *client)
119150
{
120151
struct regmap_irq_chip_data *irq_data;
@@ -149,9 +180,49 @@ static int fomcu_probe(struct i2c_client *client)
149180
return dev_err_probe(&client->dev, ret,
150181
"Failed to register child devices\n");
151182

152-
return ret;
183+
ddata->reboot_nb.notifier_call = fomcu_reboot_notify;
184+
ret = devm_register_reboot_notifier(&client->dev, &ddata->reboot_nb);
185+
if (ret)
186+
return dev_err_probe(&client->dev, ret,
187+
"Failed to register reboot notifier\n");
188+
189+
ret = devm_register_sys_off_handler(&client->dev,
190+
SYS_OFF_MODE_POWER_OFF_PREPARE,
191+
SYS_OFF_PRIO_DEFAULT,
192+
fomcu_power_off, ddata);
193+
if (ret)
194+
return dev_err_probe(&client->dev, ret,
195+
"Failed to register power-off handler\n");
196+
197+
/*
198+
* Signal that early kernel init has reached this driver. Userspace is
199+
* expected to move the MCU to FOMCU_CPUSTATE_ONLINE once boot completes.
200+
*/
201+
ddata->cpustate = FOMCU_CPUSTATE_KERNEL_INIT;
202+
return regmap_write(ddata->regmap, FOMCU_REG_CPUSTATE, ddata->cpustate);
203+
}
204+
205+
static int fomcu_suspend(struct device *dev)
206+
{
207+
struct fomcu_device *ddata = dev_get_drvdata(dev);
208+
209+
/*
210+
* Leave ddata->cpustate untouched so that resume can restore whatever
211+
* state we were in before suspending (KERNEL_INIT if userspace had not
212+
* come up yet, ONLINE otherwise).
213+
*/
214+
return regmap_write(ddata->regmap, FOMCU_REG_CPUSTATE, FOMCU_CPUSTATE_SUSPEND);
153215
}
154216

217+
static int fomcu_resume(struct device *dev)
218+
{
219+
struct fomcu_device *ddata = dev_get_drvdata(dev);
220+
221+
return regmap_write(ddata->regmap, FOMCU_REG_CPUSTATE, ddata->cpustate);
222+
}
223+
224+
static DEFINE_SIMPLE_DEV_PM_OPS(fomcu_pm_ops, fomcu_suspend, fomcu_resume);
225+
155226
static const struct i2c_device_id fomcu_i2c_ids[] = {
156227
{ "flipper-one-mcu" },
157228
{}
@@ -168,6 +239,7 @@ static struct i2c_driver fomcu_driver = {
168239
.driver = {
169240
.name = "flipper-one-mcu",
170241
.of_match_table = fomcu_of_match,
242+
.pm = pm_sleep_ptr(&fomcu_pm_ops),
171243
},
172244
.probe = fomcu_probe,
173245
.id_table = fomcu_i2c_ids,

include/linux/mfd/flipper-one-mcu.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#define __LINUX_MFD_FLIPPER_ONE_MCU_H
99

1010
#include <linux/i2c.h>
11+
#include <linux/notifier.h>
1112
#include <linux/regmap.h>
1213

1314
enum fomcu_interrupts {
@@ -19,6 +20,23 @@ enum fomcu_interrupts {
1920

2021
#define FOMCU_REG_INTSTS 0x0000
2122

23+
#define FOMCU_REG_CPUSTATE 0x0040
24+
25+
/*
26+
* These values are part of the wire protocol shared with the MCU firmware;
27+
* keep them stable and in sync with the MCU side when adding new states.
28+
*/
29+
enum fomcu_cpu_states {
30+
FOMCU_CPUSTATE_UNKNOWN = 0,
31+
FOMCU_CPUSTATE_BOOTLOADER, /* set by the MCU/bootloader itself */
32+
FOMCU_CPUSTATE_KERNEL_INIT, /* this driver has probed */
33+
FOMCU_CPUSTATE_ONLINE, /* userspace up / resumed from suspend */
34+
FOMCU_CPUSTATE_SUSPEND, /* about to suspend */
35+
FOMCU_CPUSTATE_SHUTTING_DOWN, /* reboot or power-off in progress */
36+
FOMCU_CPUSTATE_POWERED_OFF, /* safe to cut power to the PMIC */
37+
FOMCU_CPUSTATE_NUM_STATES
38+
};
39+
2240
#define FOMCU_REG_VERSION 0x0080
2341

2442
#define FOMCU_REG_INTSTS_INPUT 0x0100
@@ -69,6 +87,9 @@ enum fomcu_interrupts {
6987
struct fomcu_device {
7088
struct i2c_client *client;
7189
struct regmap *regmap;
90+
struct notifier_block reboot_nb;
91+
/* Last non-transient CPU state, restored on resume. */
92+
enum fomcu_cpu_states cpustate;
7293
};
7394

7495
#endif /* __LINUX_MFD_FLIPPER_ONE_MCU_H */

0 commit comments

Comments
 (0)