1919#include <linux/cleanup.h>
2020#include <linux/device.h>
2121#include <linux/export.h>
22+ #include <linux/kref.h>
23+ #include <linux/list.h>
2224#include <linux/mutex.h>
25+ #include <linux/of.h>
26+ #include <linux/property.h>
2327#include <linux/spi/offload/consumer.h>
2428#include <linux/spi/offload/provider.h>
2529#include <linux/spi/offload/types.h>
@@ -31,6 +35,23 @@ struct spi_controller_and_offload {
3135 struct spi_offload * offload ;
3236};
3337
38+ struct spi_offload_trigger {
39+ struct list_head list ;
40+ struct kref ref ;
41+ struct fwnode_handle * fwnode ;
42+ /* synchronizes calling ops and driver registration */
43+ struct mutex lock ;
44+ /*
45+ * If the provider goes away while the consumer still has a reference,
46+ * ops and priv will be set to NULL and all calls will fail with -ENODEV.
47+ */
48+ const struct spi_offload_trigger_ops * ops ;
49+ void * priv ;
50+ };
51+
52+ static LIST_HEAD (spi_offload_triggers );
53+ static DEFINE_MUTEX (spi_offload_triggers_lock );
54+
3455/**
3556 * devm_spi_offload_alloc() - Allocate offload instance
3657 * @dev: Device for devm purposes and assigned to &struct spi_offload.provider_dev
@@ -112,3 +133,263 @@ struct spi_offload *devm_spi_offload_get(struct device *dev,
112133 return resource -> offload ;
113134}
114135EXPORT_SYMBOL_GPL (devm_spi_offload_get );
136+
137+ static void spi_offload_trigger_free (struct kref * ref )
138+ {
139+ struct spi_offload_trigger * trigger =
140+ container_of (ref , struct spi_offload_trigger , ref );
141+
142+ mutex_destroy (& trigger -> lock );
143+ fwnode_handle_put (trigger -> fwnode );
144+ kfree (trigger );
145+ }
146+
147+ static void spi_offload_trigger_put (void * data )
148+ {
149+ struct spi_offload_trigger * trigger = data ;
150+
151+ scoped_guard (mutex , & trigger -> lock )
152+ if (trigger -> ops && trigger -> ops -> release )
153+ trigger -> ops -> release (trigger );
154+
155+ kref_put (& trigger -> ref , spi_offload_trigger_free );
156+ }
157+
158+ static struct spi_offload_trigger
159+ * spi_offload_trigger_get (enum spi_offload_trigger_type type ,
160+ struct fwnode_reference_args * args )
161+ {
162+ struct spi_offload_trigger * trigger ;
163+ bool match = false;
164+ int ret ;
165+
166+ guard (mutex )(& spi_offload_triggers_lock );
167+
168+ list_for_each_entry (trigger , & spi_offload_triggers , list ) {
169+ if (trigger -> fwnode != args -> fwnode )
170+ continue ;
171+
172+ match = trigger -> ops -> match (trigger , type , args -> args , args -> nargs );
173+ if (match )
174+ break ;
175+ }
176+
177+ if (!match )
178+ return ERR_PTR (- EPROBE_DEFER );
179+
180+ guard (mutex )(& trigger -> lock );
181+
182+ if (!trigger -> ops )
183+ return ERR_PTR (- ENODEV );
184+
185+ if (trigger -> ops -> request ) {
186+ ret = trigger -> ops -> request (trigger , type , args -> args , args -> nargs );
187+ if (ret )
188+ return ERR_PTR (ret );
189+ }
190+
191+ kref_get (& trigger -> ref );
192+
193+ return trigger ;
194+ }
195+
196+ /**
197+ * devm_spi_offload_trigger_get() - Get an offload trigger instance
198+ * @dev: Device for devm purposes.
199+ * @offload: Offload instance connected to a trigger.
200+ * @type: Trigger type to get.
201+ *
202+ * Return: Offload trigger instance or error on failure.
203+ */
204+ struct spi_offload_trigger
205+ * devm_spi_offload_trigger_get (struct device * dev ,
206+ struct spi_offload * offload ,
207+ enum spi_offload_trigger_type type )
208+ {
209+ struct spi_offload_trigger * trigger ;
210+ struct fwnode_reference_args args ;
211+ int ret ;
212+
213+ ret = fwnode_property_get_reference_args (dev_fwnode (offload -> provider_dev ),
214+ "trigger-sources" ,
215+ "#trigger-source-cells" , 0 , 0 ,
216+ & args );
217+ if (ret )
218+ return ERR_PTR (ret );
219+
220+ trigger = spi_offload_trigger_get (type , & args );
221+ fwnode_handle_put (args .fwnode );
222+ if (IS_ERR (trigger ))
223+ return trigger ;
224+
225+ ret = devm_add_action_or_reset (dev , spi_offload_trigger_put , trigger );
226+ if (ret )
227+ return ERR_PTR (ret );
228+
229+ return trigger ;
230+ }
231+ EXPORT_SYMBOL_GPL (devm_spi_offload_trigger_get );
232+
233+ /**
234+ * spi_offload_trigger_validate - Validate the requested trigger
235+ * @trigger: Offload trigger instance
236+ * @config: Trigger config to validate
237+ *
238+ * On success, @config may be modifed to reflect what the hardware can do.
239+ * For example, the frequency of a periodic trigger may be adjusted to the
240+ * nearest supported value.
241+ *
242+ * Callers will likely need to do additional validation of the modified trigger
243+ * parameters.
244+ *
245+ * Return: 0 on success, negative error code on failure.
246+ */
247+ int spi_offload_trigger_validate (struct spi_offload_trigger * trigger ,
248+ struct spi_offload_trigger_config * config )
249+ {
250+ guard (mutex )(& trigger -> lock );
251+
252+ if (!trigger -> ops )
253+ return - ENODEV ;
254+
255+ if (!trigger -> ops -> validate )
256+ return - EOPNOTSUPP ;
257+
258+ return trigger -> ops -> validate (trigger , config );
259+ }
260+ EXPORT_SYMBOL_GPL (spi_offload_trigger_validate );
261+
262+ /**
263+ * spi_offload_trigger_enable - enables trigger for offload
264+ * @offload: Offload instance
265+ * @trigger: Offload trigger instance
266+ * @config: Trigger config to validate
267+ *
268+ * There must be a prepared offload instance with the specified ID (i.e.
269+ * spi_optimize_message() was called with the same offload assigned to the
270+ * message). This will also reserve the bus for exclusive use by the offload
271+ * instance until the trigger is disabled. Any other attempts to send a
272+ * transfer or lock the bus will fail with -EBUSY during this time.
273+ *
274+ * Calls must be balanced with spi_offload_trigger_disable().
275+ *
276+ * Context: can sleep
277+ * Return: 0 on success, else a negative error code.
278+ */
279+ int spi_offload_trigger_enable (struct spi_offload * offload ,
280+ struct spi_offload_trigger * trigger ,
281+ struct spi_offload_trigger_config * config )
282+ {
283+ int ret ;
284+
285+ guard (mutex )(& trigger -> lock );
286+
287+ if (!trigger -> ops )
288+ return - ENODEV ;
289+
290+ if (offload -> ops && offload -> ops -> trigger_enable ) {
291+ ret = offload -> ops -> trigger_enable (offload );
292+ if (ret )
293+ return ret ;
294+ }
295+
296+ if (trigger -> ops -> enable ) {
297+ ret = trigger -> ops -> enable (trigger , config );
298+ if (ret ) {
299+ if (offload -> ops -> trigger_disable )
300+ offload -> ops -> trigger_disable (offload );
301+ return ret ;
302+ }
303+ }
304+
305+ return 0 ;
306+ }
307+ EXPORT_SYMBOL_GPL (spi_offload_trigger_enable );
308+
309+ /**
310+ * spi_offload_trigger_disable - disables hardware trigger for offload
311+ * @offload: Offload instance
312+ * @trigger: Offload trigger instance
313+ *
314+ * Disables the hardware trigger for the offload instance with the specified ID
315+ * and releases the bus for use by other clients.
316+ *
317+ * Context: can sleep
318+ */
319+ void spi_offload_trigger_disable (struct spi_offload * offload ,
320+ struct spi_offload_trigger * trigger )
321+ {
322+ if (offload -> ops && offload -> ops -> trigger_disable )
323+ offload -> ops -> trigger_disable (offload );
324+
325+ guard (mutex )(& trigger -> lock );
326+
327+ if (!trigger -> ops )
328+ return ;
329+
330+ if (trigger -> ops -> disable )
331+ trigger -> ops -> disable (trigger );
332+ }
333+ EXPORT_SYMBOL_GPL (spi_offload_trigger_disable );
334+
335+ /* Triggers providers */
336+
337+ static void spi_offload_trigger_unregister (void * data )
338+ {
339+ struct spi_offload_trigger * trigger = data ;
340+
341+ scoped_guard (mutex , & spi_offload_triggers_lock )
342+ list_del (& trigger -> list );
343+
344+ scoped_guard (mutex , & trigger -> lock ) {
345+ trigger -> priv = NULL ;
346+ trigger -> ops = NULL ;
347+ }
348+
349+ kref_put (& trigger -> ref , spi_offload_trigger_free );
350+ }
351+
352+ /**
353+ * devm_spi_offload_trigger_register() - Allocate and register an offload trigger
354+ * @dev: Device for devm purposes.
355+ * @info: Provider-specific trigger info.
356+ *
357+ * Return: 0 on success, else a negative error code.
358+ */
359+ int devm_spi_offload_trigger_register (struct device * dev ,
360+ struct spi_offload_trigger_info * info )
361+ {
362+ struct spi_offload_trigger * trigger ;
363+
364+ if (!info -> fwnode || !info -> ops )
365+ return - EINVAL ;
366+
367+ trigger = kzalloc (sizeof (* trigger ), GFP_KERNEL );
368+ if (!trigger )
369+ return - ENOMEM ;
370+
371+ kref_init (& trigger -> ref );
372+ mutex_init (& trigger -> lock );
373+ trigger -> fwnode = fwnode_handle_get (info -> fwnode );
374+ trigger -> ops = info -> ops ;
375+ trigger -> priv = info -> priv ;
376+
377+ scoped_guard (mutex , & spi_offload_triggers_lock )
378+ list_add_tail (& trigger -> list , & spi_offload_triggers );
379+
380+ return devm_add_action_or_reset (dev , spi_offload_trigger_unregister , trigger );
381+ }
382+ EXPORT_SYMBOL_GPL (devm_spi_offload_trigger_register );
383+
384+ /**
385+ * spi_offload_trigger_get_priv() - Get the private data for the trigger
386+ *
387+ * @trigger: Offload trigger instance.
388+ *
389+ * Return: Private data for the trigger.
390+ */
391+ void * spi_offload_trigger_get_priv (struct spi_offload_trigger * trigger )
392+ {
393+ return trigger -> priv ;
394+ }
395+ EXPORT_SYMBOL_GPL (spi_offload_trigger_get_priv );
0 commit comments