···11+// SPDX-License-Identifier: GPL-2.0-only22+/*33+ * Copyright (C) 2024 Analog Devices Inc.44+ * Copyright (C) 2024 BayLibre, SAS55+ *66+ * Generic PWM trigger for SPI offload.77+ */88+99+#include <linux/platform_device.h>1010+#include <linux/pwm.h>1111+#include <linux/mod_devicetable.h>1212+#include <linux/spi/offload/provider.h>1313+#include <linux/types.h>1414+1515+struct spi_offload_trigger_pwm_state {1616+ struct device *dev;1717+ struct pwm_device *pwm;1818+};1919+2020+static bool spi_offload_trigger_pwm_match(struct spi_offload_trigger *trigger,2121+ enum spi_offload_trigger_type type,2222+ u64 *args, u32 nargs)2323+{2424+ if (nargs)2525+ return false;2626+2727+ return type == SPI_OFFLOAD_TRIGGER_PERIODIC;2828+}2929+3030+static int spi_offload_trigger_pwm_validate(struct spi_offload_trigger *trigger,3131+ struct spi_offload_trigger_config *config)3232+{3333+ struct spi_offload_trigger_pwm_state *st = spi_offload_trigger_get_priv(trigger);3434+ struct spi_offload_trigger_periodic *periodic = &config->periodic;3535+ struct pwm_waveform wf = { };3636+ int ret;3737+3838+ if (config->type != SPI_OFFLOAD_TRIGGER_PERIODIC)3939+ return -EINVAL;4040+4141+ if (!periodic->frequency_hz)4242+ return -EINVAL;4343+4444+ wf.period_length_ns = DIV_ROUND_UP_ULL(NSEC_PER_SEC, periodic->frequency_hz);4545+ /* REVISIT: 50% duty-cycle for now - may add config parameter later */4646+ wf.duty_length_ns = wf.period_length_ns / 2;4747+4848+ ret = pwm_round_waveform_might_sleep(st->pwm, &wf);4949+ if (ret < 0)5050+ return ret;5151+5252+ periodic->frequency_hz = DIV_ROUND_UP_ULL(NSEC_PER_SEC, wf.period_length_ns);5353+5454+ return 0;5555+}5656+5757+static int spi_offload_trigger_pwm_enable(struct spi_offload_trigger *trigger,5858+ struct spi_offload_trigger_config *config)5959+{6060+ struct spi_offload_trigger_pwm_state *st = spi_offload_trigger_get_priv(trigger);6161+ struct spi_offload_trigger_periodic *periodic = &config->periodic;6262+ struct pwm_waveform wf = { };6363+6464+ if (config->type != SPI_OFFLOAD_TRIGGER_PERIODIC)6565+ return -EINVAL;6666+6767+ if (!periodic->frequency_hz)6868+ return -EINVAL;6969+7070+ wf.period_length_ns = DIV_ROUND_UP_ULL(NSEC_PER_SEC, periodic->frequency_hz);7171+ /* REVISIT: 50% duty-cycle for now - may add config parameter later */7272+ wf.duty_length_ns = wf.period_length_ns / 2;7373+7474+ return pwm_set_waveform_might_sleep(st->pwm, &wf, false);7575+}7676+7777+static void spi_offload_trigger_pwm_disable(struct spi_offload_trigger *trigger)7878+{7979+ struct spi_offload_trigger_pwm_state *st = spi_offload_trigger_get_priv(trigger);8080+ struct pwm_waveform wf;8181+ int ret;8282+8383+ ret = pwm_get_waveform_might_sleep(st->pwm, &wf);8484+ if (ret < 0) {8585+ dev_err(st->dev, "failed to get waveform: %d\n", ret);8686+ return;8787+ }8888+8989+ wf.duty_length_ns = 0;9090+9191+ ret = pwm_set_waveform_might_sleep(st->pwm, &wf, false);9292+ if (ret < 0)9393+ dev_err(st->dev, "failed to disable PWM: %d\n", ret);9494+}9595+9696+static const struct spi_offload_trigger_ops spi_offload_trigger_pwm_ops = {9797+ .match = spi_offload_trigger_pwm_match,9898+ .validate = spi_offload_trigger_pwm_validate,9999+ .enable = spi_offload_trigger_pwm_enable,100100+ .disable = spi_offload_trigger_pwm_disable,101101+};102102+103103+static void spi_offload_trigger_pwm_release(void *data)104104+{105105+ pwm_disable(data);106106+}107107+108108+static int spi_offload_trigger_pwm_probe(struct platform_device *pdev)109109+{110110+ struct device *dev = &pdev->dev;111111+ struct spi_offload_trigger_info info = {112112+ .fwnode = dev_fwnode(dev),113113+ .ops = &spi_offload_trigger_pwm_ops,114114+ };115115+ struct spi_offload_trigger_pwm_state *st;116116+ struct pwm_state state;117117+ int ret;118118+119119+ st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);120120+ if (!st)121121+ return -ENOMEM;122122+123123+ info.priv = st;124124+ st->dev = dev;125125+126126+ st->pwm = devm_pwm_get(dev, NULL);127127+ if (IS_ERR(st->pwm))128128+ return dev_err_probe(dev, PTR_ERR(st->pwm), "failed to get PWM\n");129129+130130+ /* init with duty_cycle = 0, output enabled to ensure trigger off */131131+ pwm_init_state(st->pwm, &state);132132+ state.enabled = true;133133+134134+ ret = pwm_apply_might_sleep(st->pwm, &state);135135+ if (ret < 0)136136+ return dev_err_probe(dev, ret, "failed to apply PWM state\n");137137+138138+ ret = devm_add_action_or_reset(dev, spi_offload_trigger_pwm_release, st->pwm);139139+ if (ret)140140+ return ret;141141+142142+ return devm_spi_offload_trigger_register(dev, &info);143143+}144144+145145+static const struct of_device_id spi_offload_trigger_pwm_of_match_table[] = {146146+ { .compatible = "pwm-trigger" },147147+ { }148148+};149149+MODULE_DEVICE_TABLE(of, spi_offload_trigger_pwm_of_match_table);150150+151151+static struct platform_driver spi_offload_trigger_pwm_driver = {152152+ .driver = {153153+ .name = "pwm-trigger",154154+ .of_match_table = spi_offload_trigger_pwm_of_match_table,155155+ },156156+ .probe = spi_offload_trigger_pwm_probe,157157+};158158+module_platform_driver(spi_offload_trigger_pwm_driver);159159+160160+MODULE_AUTHOR("David Lechner <dlechner@baylibre.com>");161161+MODULE_DESCRIPTION("Generic PWM trigger");162162+MODULE_LICENSE("GPL");
+465
drivers/spi/spi-offload.c
···11+// SPDX-License-Identifier: GPL-2.0-only22+/*33+ * Copyright (C) 2024 Analog Devices Inc.44+ * Copyright (C) 2024 BayLibre, SAS55+ */66+77+/*88+ * SPI Offloading support.99+ *1010+ * Some SPI controllers support offloading of SPI transfers. Essentially, this1111+ * is the ability for a SPI controller to perform SPI transfers with minimal1212+ * or even no CPU intervention, e.g. via a specialized SPI controller with a1313+ * hardware trigger or via a conventional SPI controller using a non-Linux MCU1414+ * processor core to offload the work.1515+ */1616+1717+#define DEFAULT_SYMBOL_NAMESPACE "SPI_OFFLOAD"1818+1919+#include <linux/cleanup.h>2020+#include <linux/device.h>2121+#include <linux/dmaengine.h>2222+#include <linux/export.h>2323+#include <linux/kref.h>2424+#include <linux/list.h>2525+#include <linux/mutex.h>2626+#include <linux/of.h>2727+#include <linux/property.h>2828+#include <linux/spi/offload/consumer.h>2929+#include <linux/spi/offload/provider.h>3030+#include <linux/spi/offload/types.h>3131+#include <linux/spi/spi.h>3232+#include <linux/types.h>3333+3434+struct spi_controller_and_offload {3535+ struct spi_controller *controller;3636+ struct spi_offload *offload;3737+};3838+3939+struct spi_offload_trigger {4040+ struct list_head list;4141+ struct kref ref;4242+ struct fwnode_handle *fwnode;4343+ /* synchronizes calling ops and driver registration */4444+ struct mutex lock;4545+ /*4646+ * If the provider goes away while the consumer still has a reference,4747+ * ops and priv will be set to NULL and all calls will fail with -ENODEV.4848+ */4949+ const struct spi_offload_trigger_ops *ops;5050+ void *priv;5151+};5252+5353+static LIST_HEAD(spi_offload_triggers);5454+static DEFINE_MUTEX(spi_offload_triggers_lock);5555+5656+/**5757+ * devm_spi_offload_alloc() - Allocate offload instance5858+ * @dev: Device for devm purposes and assigned to &struct spi_offload.provider_dev5959+ * @priv_size: Size of private data to allocate6060+ *6161+ * Offload providers should use this to allocate offload instances.6262+ *6363+ * Return: Pointer to new offload instance or error on failure.6464+ */6565+struct spi_offload *devm_spi_offload_alloc(struct device *dev,6666+ size_t priv_size)6767+{6868+ struct spi_offload *offload;6969+ void *priv;7070+7171+ offload = devm_kzalloc(dev, sizeof(*offload), GFP_KERNEL);7272+ if (!offload)7373+ return ERR_PTR(-ENOMEM);7474+7575+ priv = devm_kzalloc(dev, priv_size, GFP_KERNEL);7676+ if (!priv)7777+ return ERR_PTR(-ENOMEM);7878+7979+ offload->provider_dev = dev;8080+ offload->priv = priv;8181+8282+ return offload;8383+}8484+EXPORT_SYMBOL_GPL(devm_spi_offload_alloc);8585+8686+static void spi_offload_put(void *data)8787+{8888+ struct spi_controller_and_offload *resource = data;8989+9090+ resource->controller->put_offload(resource->offload);9191+ kfree(resource);9292+}9393+9494+/**9595+ * devm_spi_offload_get() - Get an offload instance9696+ * @dev: Device for devm purposes9797+ * @spi: SPI device to use for the transfers9898+ * @config: Offload configuration9999+ *100100+ * Peripheral drivers call this function to get an offload instance that meets101101+ * the requirements specified in @config. If no suitable offload instance is102102+ * available, -ENODEV is returned.103103+ *104104+ * Return: Offload instance or error on failure.105105+ */106106+struct spi_offload *devm_spi_offload_get(struct device *dev,107107+ struct spi_device *spi,108108+ const struct spi_offload_config *config)109109+{110110+ struct spi_controller_and_offload *resource;111111+ int ret;112112+113113+ if (!spi || !config)114114+ return ERR_PTR(-EINVAL);115115+116116+ if (!spi->controller->get_offload)117117+ return ERR_PTR(-ENODEV);118118+119119+ resource = kzalloc(sizeof(*resource), GFP_KERNEL);120120+ if (!resource)121121+ return ERR_PTR(-ENOMEM);122122+123123+ resource->controller = spi->controller;124124+ resource->offload = spi->controller->get_offload(spi, config);125125+ if (IS_ERR(resource->offload)) {126126+ kfree(resource);127127+ return resource->offload;128128+ }129129+130130+ ret = devm_add_action_or_reset(dev, spi_offload_put, resource);131131+ if (ret)132132+ return ERR_PTR(ret);133133+134134+ return resource->offload;135135+}136136+EXPORT_SYMBOL_GPL(devm_spi_offload_get);137137+138138+static void spi_offload_trigger_free(struct kref *ref)139139+{140140+ struct spi_offload_trigger *trigger =141141+ container_of(ref, struct spi_offload_trigger, ref);142142+143143+ mutex_destroy(&trigger->lock);144144+ fwnode_handle_put(trigger->fwnode);145145+ kfree(trigger);146146+}147147+148148+static void spi_offload_trigger_put(void *data)149149+{150150+ struct spi_offload_trigger *trigger = data;151151+152152+ scoped_guard(mutex, &trigger->lock)153153+ if (trigger->ops && trigger->ops->release)154154+ trigger->ops->release(trigger);155155+156156+ kref_put(&trigger->ref, spi_offload_trigger_free);157157+}158158+159159+static struct spi_offload_trigger160160+*spi_offload_trigger_get(enum spi_offload_trigger_type type,161161+ struct fwnode_reference_args *args)162162+{163163+ struct spi_offload_trigger *trigger;164164+ bool match = false;165165+ int ret;166166+167167+ guard(mutex)(&spi_offload_triggers_lock);168168+169169+ list_for_each_entry(trigger, &spi_offload_triggers, list) {170170+ if (trigger->fwnode != args->fwnode)171171+ continue;172172+173173+ match = trigger->ops->match(trigger, type, args->args, args->nargs);174174+ if (match)175175+ break;176176+ }177177+178178+ if (!match)179179+ return ERR_PTR(-EPROBE_DEFER);180180+181181+ guard(mutex)(&trigger->lock);182182+183183+ if (!trigger->ops)184184+ return ERR_PTR(-ENODEV);185185+186186+ if (trigger->ops->request) {187187+ ret = trigger->ops->request(trigger, type, args->args, args->nargs);188188+ if (ret)189189+ return ERR_PTR(ret);190190+ }191191+192192+ kref_get(&trigger->ref);193193+194194+ return trigger;195195+}196196+197197+/**198198+ * devm_spi_offload_trigger_get() - Get an offload trigger instance199199+ * @dev: Device for devm purposes.200200+ * @offload: Offload instance connected to a trigger.201201+ * @type: Trigger type to get.202202+ *203203+ * Return: Offload trigger instance or error on failure.204204+ */205205+struct spi_offload_trigger206206+*devm_spi_offload_trigger_get(struct device *dev,207207+ struct spi_offload *offload,208208+ enum spi_offload_trigger_type type)209209+{210210+ struct spi_offload_trigger *trigger;211211+ struct fwnode_reference_args args;212212+ int ret;213213+214214+ ret = fwnode_property_get_reference_args(dev_fwnode(offload->provider_dev),215215+ "trigger-sources",216216+ "#trigger-source-cells", 0, 0,217217+ &args);218218+ if (ret)219219+ return ERR_PTR(ret);220220+221221+ trigger = spi_offload_trigger_get(type, &args);222222+ fwnode_handle_put(args.fwnode);223223+ if (IS_ERR(trigger))224224+ return trigger;225225+226226+ ret = devm_add_action_or_reset(dev, spi_offload_trigger_put, trigger);227227+ if (ret)228228+ return ERR_PTR(ret);229229+230230+ return trigger;231231+}232232+EXPORT_SYMBOL_GPL(devm_spi_offload_trigger_get);233233+234234+/**235235+ * spi_offload_trigger_validate - Validate the requested trigger236236+ * @trigger: Offload trigger instance237237+ * @config: Trigger config to validate238238+ *239239+ * On success, @config may be modifed to reflect what the hardware can do.240240+ * For example, the frequency of a periodic trigger may be adjusted to the241241+ * nearest supported value.242242+ *243243+ * Callers will likely need to do additional validation of the modified trigger244244+ * parameters.245245+ *246246+ * Return: 0 on success, negative error code on failure.247247+ */248248+int spi_offload_trigger_validate(struct spi_offload_trigger *trigger,249249+ struct spi_offload_trigger_config *config)250250+{251251+ guard(mutex)(&trigger->lock);252252+253253+ if (!trigger->ops)254254+ return -ENODEV;255255+256256+ if (!trigger->ops->validate)257257+ return -EOPNOTSUPP;258258+259259+ return trigger->ops->validate(trigger, config);260260+}261261+EXPORT_SYMBOL_GPL(spi_offload_trigger_validate);262262+263263+/**264264+ * spi_offload_trigger_enable - enables trigger for offload265265+ * @offload: Offload instance266266+ * @trigger: Offload trigger instance267267+ * @config: Trigger config to validate268268+ *269269+ * There must be a prepared offload instance with the specified ID (i.e.270270+ * spi_optimize_message() was called with the same offload assigned to the271271+ * message). This will also reserve the bus for exclusive use by the offload272272+ * instance until the trigger is disabled. Any other attempts to send a273273+ * transfer or lock the bus will fail with -EBUSY during this time.274274+ *275275+ * Calls must be balanced with spi_offload_trigger_disable().276276+ *277277+ * Context: can sleep278278+ * Return: 0 on success, else a negative error code.279279+ */280280+int spi_offload_trigger_enable(struct spi_offload *offload,281281+ struct spi_offload_trigger *trigger,282282+ struct spi_offload_trigger_config *config)283283+{284284+ int ret;285285+286286+ guard(mutex)(&trigger->lock);287287+288288+ if (!trigger->ops)289289+ return -ENODEV;290290+291291+ if (offload->ops && offload->ops->trigger_enable) {292292+ ret = offload->ops->trigger_enable(offload);293293+ if (ret)294294+ return ret;295295+ }296296+297297+ if (trigger->ops->enable) {298298+ ret = trigger->ops->enable(trigger, config);299299+ if (ret) {300300+ if (offload->ops->trigger_disable)301301+ offload->ops->trigger_disable(offload);302302+ return ret;303303+ }304304+ }305305+306306+ return 0;307307+}308308+EXPORT_SYMBOL_GPL(spi_offload_trigger_enable);309309+310310+/**311311+ * spi_offload_trigger_disable - disables hardware trigger for offload312312+ * @offload: Offload instance313313+ * @trigger: Offload trigger instance314314+ *315315+ * Disables the hardware trigger for the offload instance with the specified ID316316+ * and releases the bus for use by other clients.317317+ *318318+ * Context: can sleep319319+ */320320+void spi_offload_trigger_disable(struct spi_offload *offload,321321+ struct spi_offload_trigger *trigger)322322+{323323+ if (offload->ops && offload->ops->trigger_disable)324324+ offload->ops->trigger_disable(offload);325325+326326+ guard(mutex)(&trigger->lock);327327+328328+ if (!trigger->ops)329329+ return;330330+331331+ if (trigger->ops->disable)332332+ trigger->ops->disable(trigger);333333+}334334+EXPORT_SYMBOL_GPL(spi_offload_trigger_disable);335335+336336+static void spi_offload_release_dma_chan(void *chan)337337+{338338+ dma_release_channel(chan);339339+}340340+341341+/**342342+ * devm_spi_offload_tx_stream_request_dma_chan - Get the DMA channel info for the TX stream343343+ * @dev: Device for devm purposes.344344+ * @offload: Offload instance345345+ *346346+ * This is the DMA channel that will provide data to transfers that use the347347+ * %SPI_OFFLOAD_XFER_TX_STREAM offload flag.348348+ *349349+ * Return: Pointer to DMA channel info, or negative error code350350+ */351351+struct dma_chan352352+*devm_spi_offload_tx_stream_request_dma_chan(struct device *dev,353353+ struct spi_offload *offload)354354+{355355+ struct dma_chan *chan;356356+ int ret;357357+358358+ if (!offload->ops || !offload->ops->tx_stream_request_dma_chan)359359+ return ERR_PTR(-EOPNOTSUPP);360360+361361+ chan = offload->ops->tx_stream_request_dma_chan(offload);362362+ if (IS_ERR(chan))363363+ return chan;364364+365365+ ret = devm_add_action_or_reset(dev, spi_offload_release_dma_chan, chan);366366+ if (ret)367367+ return ERR_PTR(ret);368368+369369+ return chan;370370+}371371+EXPORT_SYMBOL_GPL(devm_spi_offload_tx_stream_request_dma_chan);372372+373373+/**374374+ * devm_spi_offload_rx_stream_request_dma_chan - Get the DMA channel info for the RX stream375375+ * @dev: Device for devm purposes.376376+ * @offload: Offload instance377377+ *378378+ * This is the DMA channel that will receive data from transfers that use the379379+ * %SPI_OFFLOAD_XFER_RX_STREAM offload flag.380380+ *381381+ * Return: Pointer to DMA channel info, or negative error code382382+ */383383+struct dma_chan384384+*devm_spi_offload_rx_stream_request_dma_chan(struct device *dev,385385+ struct spi_offload *offload)386386+{387387+ struct dma_chan *chan;388388+ int ret;389389+390390+ if (!offload->ops || !offload->ops->rx_stream_request_dma_chan)391391+ return ERR_PTR(-EOPNOTSUPP);392392+393393+ chan = offload->ops->rx_stream_request_dma_chan(offload);394394+ if (IS_ERR(chan))395395+ return chan;396396+397397+ ret = devm_add_action_or_reset(dev, spi_offload_release_dma_chan, chan);398398+ if (ret)399399+ return ERR_PTR(ret);400400+401401+ return chan;402402+}403403+EXPORT_SYMBOL_GPL(devm_spi_offload_rx_stream_request_dma_chan);404404+405405+/* Triggers providers */406406+407407+static void spi_offload_trigger_unregister(void *data)408408+{409409+ struct spi_offload_trigger *trigger = data;410410+411411+ scoped_guard(mutex, &spi_offload_triggers_lock)412412+ list_del(&trigger->list);413413+414414+ scoped_guard(mutex, &trigger->lock) {415415+ trigger->priv = NULL;416416+ trigger->ops = NULL;417417+ }418418+419419+ kref_put(&trigger->ref, spi_offload_trigger_free);420420+}421421+422422+/**423423+ * devm_spi_offload_trigger_register() - Allocate and register an offload trigger424424+ * @dev: Device for devm purposes.425425+ * @info: Provider-specific trigger info.426426+ *427427+ * Return: 0 on success, else a negative error code.428428+ */429429+int devm_spi_offload_trigger_register(struct device *dev,430430+ struct spi_offload_trigger_info *info)431431+{432432+ struct spi_offload_trigger *trigger;433433+434434+ if (!info->fwnode || !info->ops)435435+ return -EINVAL;436436+437437+ trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);438438+ if (!trigger)439439+ return -ENOMEM;440440+441441+ kref_init(&trigger->ref);442442+ mutex_init(&trigger->lock);443443+ trigger->fwnode = fwnode_handle_get(info->fwnode);444444+ trigger->ops = info->ops;445445+ trigger->priv = info->priv;446446+447447+ scoped_guard(mutex, &spi_offload_triggers_lock)448448+ list_add_tail(&trigger->list, &spi_offload_triggers);449449+450450+ return devm_add_action_or_reset(dev, spi_offload_trigger_unregister, trigger);451451+}452452+EXPORT_SYMBOL_GPL(devm_spi_offload_trigger_register);453453+454454+/**455455+ * spi_offload_trigger_get_priv() - Get the private data for the trigger456456+ *457457+ * @trigger: Offload trigger instance.458458+ *459459+ * Return: Private data for the trigger.460460+ */461461+void *spi_offload_trigger_get_priv(struct spi_offload_trigger *trigger)462462+{463463+ return trigger->priv;464464+}465465+EXPORT_SYMBOL_GPL(spi_offload_trigger_get_priv);
+10
drivers/spi/spi.c
···3131#include <linux/ptp_clock_kernel.h>3232#include <linux/sched/rt.h>3333#include <linux/slab.h>3434+#include <linux/spi/offload/types.h>3435#include <linux/spi/spi.h>3536#include <linux/spi/spi-mem.h>3637#include <uapi/linux/sched/types.h>···4159415841604159 if (_spi_xfer_word_delay_update(xfer, spi))41614160 return -EINVAL;41614161+41624162+ /* Make sure controller supports required offload features. */41634163+ if (xfer->offload_flags) {41644164+ if (!message->offload)41654165+ return -EINVAL;41664166+41674167+ if (xfer->offload_flags & ~message->offload->xfer_flags)41684168+ return -EINVAL;41694169+ }41624170 }4163417141644172 message->status = -EINPROGRESS;
···11+/* SPDX-License-Identifier: GPL-2.0-only */22+/*33+ * Copyright (C) 2024 Analog Devices Inc.44+ * Copyright (C) 2024 BayLibre, SAS55+ */66+77+#ifndef __LINUX_SPI_OFFLOAD_PROVIDER_H88+#define __LINUX_SPI_OFFLOAD_PROVIDER_H99+1010+#include <linux/module.h>1111+#include <linux/spi/offload/types.h>1212+#include <linux/types.h>1313+1414+MODULE_IMPORT_NS("SPI_OFFLOAD");1515+1616+struct device;1717+struct spi_offload_trigger;1818+1919+struct spi_offload *devm_spi_offload_alloc(struct device *dev, size_t priv_size);2020+2121+struct spi_offload_trigger_ops {2222+ bool (*match)(struct spi_offload_trigger *trigger,2323+ enum spi_offload_trigger_type type, u64 *args, u32 nargs);2424+ int (*request)(struct spi_offload_trigger *trigger,2525+ enum spi_offload_trigger_type type, u64 *args, u32 nargs);2626+ void (*release)(struct spi_offload_trigger *trigger);2727+ int (*validate)(struct spi_offload_trigger *trigger,2828+ struct spi_offload_trigger_config *config);2929+ int (*enable)(struct spi_offload_trigger *trigger,3030+ struct spi_offload_trigger_config *config);3131+ void (*disable)(struct spi_offload_trigger *trigger);3232+};3333+3434+struct spi_offload_trigger_info {3535+ /** @fwnode: Provider fwnode, used to match to consumer. */3636+ struct fwnode_handle *fwnode;3737+ /** @ops: Provider-specific callbacks. */3838+ const struct spi_offload_trigger_ops *ops;3939+ /** Provider-specific state to be used in callbacks. */4040+ void *priv;4141+};4242+4343+int devm_spi_offload_trigger_register(struct device *dev,4444+ struct spi_offload_trigger_info *info);4545+void *spi_offload_trigger_get_priv(struct spi_offload_trigger *trigger);4646+4747+#endif /* __LINUX_SPI_OFFLOAD_PROVIDER_H */
+99
include/linux/spi/offload/types.h
···11+/* SPDX-License-Identifier: GPL-2.0-only */22+/*33+ * Copyright (C) 2024 Analog Devices Inc.44+ * Copyright (C) 2024 BayLibre, SAS55+ */66+77+#ifndef __LINUX_SPI_OFFLOAD_TYPES_H88+#define __LINUX_SPI_OFFLOAD_TYPES_H99+1010+#include <linux/types.h>1111+1212+struct device;1313+1414+/* This is write xfer but TX uses external data stream rather than tx_buf. */1515+#define SPI_OFFLOAD_XFER_TX_STREAM BIT(0)1616+/* This is read xfer but RX uses external data stream rather than rx_buf. */1717+#define SPI_OFFLOAD_XFER_RX_STREAM BIT(1)1818+1919+/* Offload can be triggered by external hardware event. */2020+#define SPI_OFFLOAD_CAP_TRIGGER BIT(0)2121+/* Offload can record and then play back TX data when triggered. */2222+#define SPI_OFFLOAD_CAP_TX_STATIC_DATA BIT(1)2323+/* Offload can get TX data from an external stream source. */2424+#define SPI_OFFLOAD_CAP_TX_STREAM_DMA BIT(2)2525+/* Offload can send RX data to an external stream sink. */2626+#define SPI_OFFLOAD_CAP_RX_STREAM_DMA BIT(3)2727+2828+/**2929+ * struct spi_offload_config - offload configuration3030+ *3131+ * This is used to request an offload with specific configuration.3232+ */3333+struct spi_offload_config {3434+ /** @capability_flags: required capabilities. See %SPI_OFFLOAD_CAP_* */3535+ u32 capability_flags;3636+};3737+3838+/**3939+ * struct spi_offload - offload instance4040+ */4141+struct spi_offload {4242+ /** @provider_dev: for get/put reference counting */4343+ struct device *provider_dev;4444+ /** @priv: provider driver private data */4545+ void *priv;4646+ /** @ops: callbacks for offload support */4747+ const struct spi_offload_ops *ops;4848+ /** @xfer_flags: %SPI_OFFLOAD_XFER_* flags supported by provider */4949+ u32 xfer_flags;5050+};5151+5252+enum spi_offload_trigger_type {5353+ /* Indication from SPI peripheral that data is read to read. */5454+ SPI_OFFLOAD_TRIGGER_DATA_READY,5555+ /* Trigger comes from a periodic source such as a clock. */5656+ SPI_OFFLOAD_TRIGGER_PERIODIC,5757+};5858+5959+struct spi_offload_trigger_periodic {6060+ u64 frequency_hz;6161+};6262+6363+struct spi_offload_trigger_config {6464+ /** @type: type discriminator for union */6565+ enum spi_offload_trigger_type type;6666+ union {6767+ struct spi_offload_trigger_periodic periodic;6868+ };6969+};7070+7171+/**7272+ * struct spi_offload_ops - callbacks implemented by offload providers7373+ */7474+struct spi_offload_ops {7575+ /**7676+ * @trigger_enable: Optional callback to enable the trigger for the7777+ * given offload instance.7878+ */7979+ int (*trigger_enable)(struct spi_offload *offload);8080+ /**8181+ * @trigger_disable: Optional callback to disable the trigger for the8282+ * given offload instance.8383+ */8484+ void (*trigger_disable)(struct spi_offload *offload);8585+ /**8686+ * @tx_stream_request_dma_chan: Optional callback for controllers that8787+ * have an offload where the TX data stream is connected directly to a8888+ * DMA channel.8989+ */9090+ struct dma_chan *(*tx_stream_request_dma_chan)(struct spi_offload *offload);9191+ /**9292+ * @rx_stream_request_dma_chan: Optional callback for controllers that9393+ * have an offload where the RX data stream is connected directly to a9494+ * DMA channel.9595+ */9696+ struct dma_chan *(*rx_stream_request_dma_chan)(struct spi_offload *offload);9797+};9898+9999+#endif /* __LINUX_SPI_OFFLOAD_TYPES_H */
+20
include/linux/spi/spi.h
···3131struct spi_controller_mem_ops;3232struct spi_controller_mem_caps;3333struct spi_message;3434+struct spi_offload;3535+struct spi_offload_config;34363537/*3638 * INTERFACES between SPI master-side drivers and SPI slave protocol handlers,···498496 * @mem_ops: optimized/dedicated operations for interactions with SPI memory.499497 * This field is optional and should only be implemented if the500498 * controller has native support for memory like operations.499499+ * @get_offload: callback for controllers with offload support to get matching500500+ * offload instance. Implementations should return -ENODEV if no match is501501+ * found.502502+ * @put_offload: release the offload instance acquired by @get_offload.501503 * @mem_caps: controller capabilities for the handling of memory operations.502504 * @unprepare_message: undo any work done by prepare_message().503505 * @target_abort: abort the ongoing transfer request on an SPI target controller···745739 /* Optimized handlers for SPI memory-like operations. */746740 const struct spi_controller_mem_ops *mem_ops;747741 const struct spi_controller_mem_caps *mem_caps;742742+743743+ struct spi_offload *(*get_offload)(struct spi_device *spi,744744+ const struct spi_offload_config *config);745745+ void (*put_offload)(struct spi_offload *offload);748746749747 /* GPIO chip select */750748 struct gpio_desc **cs_gpiods;···1093108310941084 u32 effective_speed_hz;1095108510861086+ /* Use %SPI_OFFLOAD_XFER_* from spi-offload.h */10871087+ unsigned int offload_flags;10881088+10961089 unsigned int ptp_sts_word_pre;10971090 unsigned int ptp_sts_word_post;10981091···11211108 * @state: for use by whichever driver currently owns the message11221109 * @opt_state: for use by whichever driver currently owns the message11231110 * @resources: for resource management when the SPI message is processed11111111+ * @offload: (optional) offload instance used by this message11241112 *11251113 * A @spi_message is used to execute an atomic sequence of data transfers,11261114 * each represented by a struct spi_transfer. The sequence is "atomic"···11811167 * __spi_optimize_message() and __spi_unoptimize_message().11821168 */11831169 void *opt_state;11701170+11711171+ /*11721172+ * Optional offload instance used by this message. This must be set11731173+ * by the peripheral driver before calling spi_optimize_message().11741174+ */11751175+ struct spi_offload *offload;1184117611851177 /* List of spi_res resources when the SPI message is processed */11861178 struct list_head resources;