@@ -118,6 +118,87 @@ static const struct mfd_cell cells[] = {
118118 "flipper,one-typec" ),
119119};
120120
121+ static int fomcu_set_cpustate (struct fomcu_device * ddata ,
122+ enum fomcu_cpu_states state )
123+ {
124+ int ret ;
125+
126+ ret = regmap_write (ddata -> regmap , FOMCU_REG_CPUSTATE , state );
127+ if (ret )
128+ return ret ;
129+
130+ ddata -> cpustate = state ;
131+ return 0 ;
132+ }
133+
134+ static const char * const fomcu_state_names [FOMCU_CPUSTATE_NUM_STATES ] = {
135+ [FOMCU_CPUSTATE_UNKNOWN ] = "unknown" ,
136+ [FOMCU_CPUSTATE_BOOTLOADER ] = "bootloader" ,
137+ [FOMCU_CPUSTATE_KERNEL_INIT ] = "kernel-init" ,
138+ [FOMCU_CPUSTATE_ONLINE ] = "online" ,
139+ [FOMCU_CPUSTATE_SUSPEND_REQ ] = "suspend-request" ,
140+ [FOMCU_CPUSTATE_SUSPEND ] = "suspend" ,
141+ [FOMCU_CPUSTATE_REBOOT_REQ ] = "reboot-request" ,
142+ [FOMCU_CPUSTATE_POWEROFF_REQ ] = "poweroff-request" ,
143+ [FOMCU_CPUSTATE_SHUTTING_DOWN ] = "shutting-down" ,
144+ [FOMCU_CPUSTATE_POWERED_OFF ] = "powered-off" ,
145+ };
146+
147+ /* States userspace is permitted to report through the cpustate sysfs file. */
148+ static const enum fomcu_cpu_states fomcu_user_writable_states [] = {
149+ FOMCU_CPUSTATE_ONLINE ,
150+ FOMCU_CPUSTATE_SUSPEND_REQ ,
151+ FOMCU_CPUSTATE_REBOOT_REQ ,
152+ FOMCU_CPUSTATE_POWEROFF_REQ ,
153+ };
154+
155+ static ssize_t cpustate_show (struct device * dev ,
156+ struct device_attribute * attr , char * buf )
157+ {
158+ struct fomcu_device * ddata = dev_get_drvdata (dev );
159+
160+ return sysfs_emit (buf , "%s\n" , fomcu_state_names [ddata -> cpustate ]);
161+ }
162+
163+ static ssize_t cpustate_store (struct device * dev ,
164+ struct device_attribute * attr ,
165+ const char * buf , size_t count )
166+ {
167+ struct fomcu_device * ddata = dev_get_drvdata (dev );
168+ enum fomcu_cpu_states state ;
169+ int i , ret ;
170+
171+ for (i = 0 ; i < ARRAY_SIZE (fomcu_user_writable_states ); i ++ ) {
172+ state = fomcu_user_writable_states [i ];
173+ if (sysfs_streq (buf , fomcu_state_names [state ]))
174+ break ;
175+ }
176+
177+ if (i == ARRAY_SIZE (fomcu_user_writable_states ))
178+ return - EINVAL ;
179+
180+ /*
181+ * Only ONLINE is a sticky state that resume should restore. The
182+ * *-request states are transient announcements of an imminent
183+ * transition, so they must not become the resume restore-point
184+ * (otherwise a suspend-request/suspend/resume cycle would come back
185+ * as "suspend-request" instead of "online").
186+ */
187+ if (state == FOMCU_CPUSTATE_ONLINE )
188+ ret = fomcu_set_cpustate (ddata , state );
189+ else
190+ ret = regmap_write (ddata -> regmap , FOMCU_REG_CPUSTATE , state );
191+
192+ return ret ? : count ;
193+ }
194+ static DEVICE_ATTR_RW (cpustate );
195+
196+ static struct attribute * fomcu_attrs [] = {
197+ & dev_attr_cpustate .attr ,
198+ NULL ,
199+ };
200+ ATTRIBUTE_GROUPS (fomcu );
201+
121202static int fomcu_reboot_notify (struct notifier_block * nb ,
122203 unsigned long action , void * data )
123204{
@@ -198,8 +279,7 @@ static int fomcu_probe(struct i2c_client *client)
198279 * Signal that early kernel init has reached this driver. Userspace is
199280 * expected to move the MCU to FOMCU_CPUSTATE_ONLINE once boot completes.
200281 */
201- ddata -> cpustate = FOMCU_CPUSTATE_KERNEL_INIT ;
202- return regmap_write (ddata -> regmap , FOMCU_REG_CPUSTATE , ddata -> cpustate );
282+ return fomcu_set_cpustate (ddata , FOMCU_CPUSTATE_KERNEL_INIT );
203283}
204284
205285static int fomcu_suspend (struct device * dev )
@@ -240,6 +320,7 @@ static struct i2c_driver fomcu_driver = {
240320 .name = "flipper-one-mcu" ,
241321 .of_match_table = fomcu_of_match ,
242322 .pm = pm_sleep_ptr (& fomcu_pm_ops ),
323+ .dev_groups = fomcu_groups ,
243324 },
244325 .probe = fomcu_probe ,
245326 .id_table = fomcu_i2c_ids ,
0 commit comments