dmaengine: Create a generic dma_slave_caps callback
[firefly-linux-kernel-4.4.55.git] / include / linux / dmaengine.h
index 40cd75e21ea2145fc535a255bfbd292f2a5e8a07..adf22089cc932692124f77f01113eb3112574f49 100644 (file)
@@ -387,7 +387,7 @@ enum dma_residue_granularity {
 /* struct dma_slave_caps - expose capabilities of a slave channel only
  *
  * @src_addr_widths: bit mask of src addr widths the channel supports
- * @dstn_addr_widths: bit mask of dstn addr widths the channel supports
+ * @dst_addr_widths: bit mask of dstn addr widths the channel supports
  * @directions: bit mask of slave direction the channel supported
  *     since the enum dma_transfer_direction is not defined as bits for each
  *     type of direction, the dma controller should fill (1 << <TYPE>) and same
@@ -398,7 +398,7 @@ enum dma_residue_granularity {
  */
 struct dma_slave_caps {
        u32 src_addr_widths;
-       u32 dstn_addr_widths;
+       u32 dst_addr_widths;
        u32 directions;
        bool cmd_pause;
        bool cmd_terminate;
@@ -594,6 +594,14 @@ struct dma_tx_state {
  * @fill_align: alignment shift for memset operations
  * @dev_id: unique device ID
  * @dev: struct device reference for dma mapping api
+ * @src_addr_widths: bit mask of src addr widths the device supports
+ * @dst_addr_widths: bit mask of dst addr widths the device supports
+ * @directions: bit mask of slave direction the device supports since
+ *     the enum dma_transfer_direction is not defined as bits for
+ *     each type of direction, the dma controller should fill (1 <<
+ *     <TYPE>) and same should be checked by controller as well
+ * @residue_granularity: granularity of the transfer residue reported
+ *     by tx_status
  * @device_alloc_chan_resources: allocate resources and return the
  *     number of allocated descriptors
  * @device_free_chan_resources: release DMA channel's resources
@@ -608,8 +616,16 @@ struct dma_tx_state {
  *     The function takes a buffer of size buf_len. The callback function will
  *     be called after period_len bytes have been transferred.
  * @device_prep_interleaved_dma: Transfer expression in a generic way.
+ * @device_config: Pushes a new configuration to a channel, return 0 or an error
+ *     code
  * @device_control: manipulate all pending operations on a channel, returns
  *     zero or error code
+ * @device_pause: Pauses any transfer happening on a channel. Returns
+ *     0 or an error code
+ * @device_resume: Resumes any transfer on a channel previously
+ *     paused. Returns 0 or an error code
+ * @device_terminate_all: Aborts all transfers on a channel. Returns 0
+ *     or an error code
  * @device_tx_status: poll for transaction completion, the optional
  *     txstate parameter can be supplied with a pointer to get a
  *     struct with auxiliary transfer status information, otherwise the call
@@ -635,14 +651,19 @@ struct dma_device {
        int dev_id;
        struct device *dev;
 
+       u32 src_addr_widths;
+       u32 dst_addr_widths;
+       u32 directions;
+       enum dma_residue_granularity residue_granularity;
+
        int (*device_alloc_chan_resources)(struct dma_chan *chan);
        void (*device_free_chan_resources)(struct dma_chan *chan);
 
        struct dma_async_tx_descriptor *(*device_prep_dma_memcpy)(
-               struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
+               struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
                size_t len, unsigned long flags);
        struct dma_async_tx_descriptor *(*device_prep_dma_xor)(
-               struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
+               struct dma_chan *chan, dma_addr_t dst, dma_addr_t *src,
                unsigned int src_cnt, size_t len, unsigned long flags);
        struct dma_async_tx_descriptor *(*device_prep_dma_xor_val)(
                struct dma_chan *chan, dma_addr_t *src, unsigned int src_cnt,
@@ -674,8 +695,14 @@ struct dma_device {
        struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)(
                struct dma_chan *chan, struct dma_interleaved_template *xt,
                unsigned long flags);
+
+       int (*device_config)(struct dma_chan *chan,
+                            struct dma_slave_config *config);
        int (*device_control)(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
                unsigned long arg);
+       int (*device_pause)(struct dma_chan *chan);
+       int (*device_resume)(struct dma_chan *chan);
+       int (*device_terminate_all)(struct dma_chan *chan);
 
        enum dma_status (*device_tx_status)(struct dma_chan *chan,
                                            dma_cookie_t cookie,
@@ -697,6 +724,9 @@ static inline int dmaengine_device_control(struct dma_chan *chan,
 static inline int dmaengine_slave_config(struct dma_chan *chan,
                                          struct dma_slave_config *config)
 {
+       if (chan->device->device_config)
+               return chan->device->device_config(chan, config);
+
        return dmaengine_device_control(chan, DMA_SLAVE_CONFIG,
                        (unsigned long)config);
 }
@@ -767,31 +797,60 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_sg(
 
 static inline int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
 {
+       struct dma_device *device;
+
        if (!chan || !caps)
                return -EINVAL;
 
+       device = chan->device;
+
        /* check if the channel supports slave transactions */
-       if (!test_bit(DMA_SLAVE, chan->device->cap_mask.bits))
+       if (!test_bit(DMA_SLAVE, device->cap_mask.bits))
+               return -ENXIO;
+
+       if (device->device_slave_caps)
+               return device->device_slave_caps(chan, caps);
+
+       /*
+        * Check whether it reports it uses the generic slave
+        * capabilities, if not, that means it doesn't support any
+        * kind of slave capabilities reporting.
+        */
+       if (!device->directions)
                return -ENXIO;
 
-       if (chan->device->device_slave_caps)
-               return chan->device->device_slave_caps(chan, caps);
+       caps->src_addr_widths = device->src_addr_widths;
+       caps->dst_addr_widths = device->dst_addr_widths;
+       caps->directions = device->directions;
+       caps->residue_granularity = device->residue_granularity;
 
-       return -ENXIO;
+       caps->cmd_pause = !!device->device_pause;
+       caps->cmd_terminate = !!device->device_terminate_all;
+
+       return 0;
 }
 
 static inline int dmaengine_terminate_all(struct dma_chan *chan)
 {
+       if (chan->device->device_terminate_all)
+               return chan->device->device_terminate_all(chan);
+
        return dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0);
 }
 
 static inline int dmaengine_pause(struct dma_chan *chan)
 {
+       if (chan->device->device_pause)
+               return chan->device->device_pause(chan);
+
        return dmaengine_device_control(chan, DMA_PAUSE, 0);
 }
 
 static inline int dmaengine_resume(struct dma_chan *chan)
 {
+       if (chan->device->device_resume)
+               return chan->device->device_resume(chan);
+
        return dmaengine_device_control(chan, DMA_RESUME, 0);
 }