1*8e02d188SDavid Lechner // SPDX-License-Identifier: GPL-2.0-only 2*8e02d188SDavid Lechner /* 3*8e02d188SDavid Lechner * Copyright (C) 2024 Analog Devices Inc. 4*8e02d188SDavid Lechner * Copyright (C) 2024 BayLibre, SAS 5*8e02d188SDavid Lechner */ 6*8e02d188SDavid Lechner 7*8e02d188SDavid Lechner /* 8*8e02d188SDavid Lechner * SPI Offloading support. 9*8e02d188SDavid Lechner * 10*8e02d188SDavid Lechner * Some SPI controllers support offloading of SPI transfers. Essentially, this 11*8e02d188SDavid Lechner * is the ability for a SPI controller to perform SPI transfers with minimal 12*8e02d188SDavid Lechner * or even no CPU intervention, e.g. via a specialized SPI controller with a 13*8e02d188SDavid Lechner * hardware trigger or via a conventional SPI controller using a non-Linux MCU 14*8e02d188SDavid Lechner * processor core to offload the work. 15*8e02d188SDavid Lechner */ 16*8e02d188SDavid Lechner 17*8e02d188SDavid Lechner #define DEFAULT_SYMBOL_NAMESPACE "SPI_OFFLOAD" 18*8e02d188SDavid Lechner 19*8e02d188SDavid Lechner #include <linux/cleanup.h> 20*8e02d188SDavid Lechner #include <linux/device.h> 21*8e02d188SDavid Lechner #include <linux/export.h> 22*8e02d188SDavid Lechner #include <linux/mutex.h> 23*8e02d188SDavid Lechner #include <linux/spi/offload/consumer.h> 24*8e02d188SDavid Lechner #include <linux/spi/offload/provider.h> 25*8e02d188SDavid Lechner #include <linux/spi/offload/types.h> 26*8e02d188SDavid Lechner #include <linux/spi/spi.h> 27*8e02d188SDavid Lechner #include <linux/types.h> 28*8e02d188SDavid Lechner 29*8e02d188SDavid Lechner struct spi_controller_and_offload { 30*8e02d188SDavid Lechner struct spi_controller *controller; 31*8e02d188SDavid Lechner struct spi_offload *offload; 32*8e02d188SDavid Lechner }; 33*8e02d188SDavid Lechner 34*8e02d188SDavid Lechner /** 35*8e02d188SDavid Lechner * devm_spi_offload_alloc() - Allocate offload instance 36*8e02d188SDavid Lechner * @dev: Device for devm purposes and assigned to &struct spi_offload.provider_dev 37*8e02d188SDavid Lechner * @priv_size: Size of private data to allocate 38*8e02d188SDavid Lechner * 39*8e02d188SDavid Lechner * Offload providers should use this to allocate offload instances. 40*8e02d188SDavid Lechner * 41*8e02d188SDavid Lechner * Return: Pointer to new offload instance or error on failure. 42*8e02d188SDavid Lechner */ 43*8e02d188SDavid Lechner struct spi_offload *devm_spi_offload_alloc(struct device *dev, 44*8e02d188SDavid Lechner size_t priv_size) 45*8e02d188SDavid Lechner { 46*8e02d188SDavid Lechner struct spi_offload *offload; 47*8e02d188SDavid Lechner void *priv; 48*8e02d188SDavid Lechner 49*8e02d188SDavid Lechner offload = devm_kzalloc(dev, sizeof(*offload), GFP_KERNEL); 50*8e02d188SDavid Lechner if (!offload) 51*8e02d188SDavid Lechner return ERR_PTR(-ENOMEM); 52*8e02d188SDavid Lechner 53*8e02d188SDavid Lechner priv = devm_kzalloc(dev, priv_size, GFP_KERNEL); 54*8e02d188SDavid Lechner if (!priv) 55*8e02d188SDavid Lechner return ERR_PTR(-ENOMEM); 56*8e02d188SDavid Lechner 57*8e02d188SDavid Lechner offload->provider_dev = dev; 58*8e02d188SDavid Lechner offload->priv = priv; 59*8e02d188SDavid Lechner 60*8e02d188SDavid Lechner return offload; 61*8e02d188SDavid Lechner } 62*8e02d188SDavid Lechner EXPORT_SYMBOL_GPL(devm_spi_offload_alloc); 63*8e02d188SDavid Lechner 64*8e02d188SDavid Lechner static void spi_offload_put(void *data) 65*8e02d188SDavid Lechner { 66*8e02d188SDavid Lechner struct spi_controller_and_offload *resource = data; 67*8e02d188SDavid Lechner 68*8e02d188SDavid Lechner resource->controller->put_offload(resource->offload); 69*8e02d188SDavid Lechner kfree(resource); 70*8e02d188SDavid Lechner } 71*8e02d188SDavid Lechner 72*8e02d188SDavid Lechner /** 73*8e02d188SDavid Lechner * devm_spi_offload_get() - Get an offload instance 74*8e02d188SDavid Lechner * @dev: Device for devm purposes 75*8e02d188SDavid Lechner * @spi: SPI device to use for the transfers 76*8e02d188SDavid Lechner * @config: Offload configuration 77*8e02d188SDavid Lechner * 78*8e02d188SDavid Lechner * Peripheral drivers call this function to get an offload instance that meets 79*8e02d188SDavid Lechner * the requirements specified in @config. If no suitable offload instance is 80*8e02d188SDavid Lechner * available, -ENODEV is returned. 81*8e02d188SDavid Lechner * 82*8e02d188SDavid Lechner * Return: Offload instance or error on failure. 83*8e02d188SDavid Lechner */ 84*8e02d188SDavid Lechner struct spi_offload *devm_spi_offload_get(struct device *dev, 85*8e02d188SDavid Lechner struct spi_device *spi, 86*8e02d188SDavid Lechner const struct spi_offload_config *config) 87*8e02d188SDavid Lechner { 88*8e02d188SDavid Lechner struct spi_controller_and_offload *resource; 89*8e02d188SDavid Lechner int ret; 90*8e02d188SDavid Lechner 91*8e02d188SDavid Lechner if (!spi || !config) 92*8e02d188SDavid Lechner return ERR_PTR(-EINVAL); 93*8e02d188SDavid Lechner 94*8e02d188SDavid Lechner if (!spi->controller->get_offload) 95*8e02d188SDavid Lechner return ERR_PTR(-ENODEV); 96*8e02d188SDavid Lechner 97*8e02d188SDavid Lechner resource = kzalloc(sizeof(*resource), GFP_KERNEL); 98*8e02d188SDavid Lechner if (!resource) 99*8e02d188SDavid Lechner return ERR_PTR(-ENOMEM); 100*8e02d188SDavid Lechner 101*8e02d188SDavid Lechner resource->controller = spi->controller; 102*8e02d188SDavid Lechner resource->offload = spi->controller->get_offload(spi, config); 103*8e02d188SDavid Lechner if (IS_ERR(resource->offload)) { 104*8e02d188SDavid Lechner kfree(resource); 105*8e02d188SDavid Lechner return resource->offload; 106*8e02d188SDavid Lechner } 107*8e02d188SDavid Lechner 108*8e02d188SDavid Lechner ret = devm_add_action_or_reset(dev, spi_offload_put, resource); 109*8e02d188SDavid Lechner if (ret) 110*8e02d188SDavid Lechner return ERR_PTR(ret); 111*8e02d188SDavid Lechner 112*8e02d188SDavid Lechner return resource->offload; 113*8e02d188SDavid Lechner } 114*8e02d188SDavid Lechner EXPORT_SYMBOL_GPL(devm_spi_offload_get); 115