linux/drivers/dma/of-dma.c
<<
>>
Prefs
   1/*
   2 * Device tree helpers for DMA request / controller
   3 *
   4 * Based on of_gpio.c
   5 *
   6 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12
  13#include <linux/device.h>
  14#include <linux/err.h>
  15#include <linux/module.h>
  16#include <linux/rculist.h>
  17#include <linux/slab.h>
  18#include <linux/of.h>
  19#include <linux/of_dma.h>
  20
  21static LIST_HEAD(of_dma_list);
  22static DEFINE_SPINLOCK(of_dma_lock);
  23
  24/**
  25 * of_dma_get_controller - Get a DMA controller in DT DMA helpers list
  26 * @dma_spec:   pointer to DMA specifier as found in the device tree
  27 *
  28 * Finds a DMA controller with matching device node and number for dma cells
  29 * in a list of registered DMA controllers. If a match is found the use_count
  30 * variable is increased and a valid pointer to the DMA data stored is retuned.
  31 * A NULL pointer is returned if no match is found.
  32 */
  33static struct of_dma *of_dma_get_controller(struct of_phandle_args *dma_spec)
  34{
  35        struct of_dma *ofdma;
  36
  37        spin_lock(&of_dma_lock);
  38
  39        if (list_empty(&of_dma_list)) {
  40                spin_unlock(&of_dma_lock);
  41                return NULL;
  42        }
  43
  44        list_for_each_entry(ofdma, &of_dma_list, of_dma_controllers)
  45                if ((ofdma->of_node == dma_spec->np) &&
  46                    (ofdma->of_dma_nbcells == dma_spec->args_count)) {
  47                        ofdma->use_count++;
  48                        spin_unlock(&of_dma_lock);
  49                        return ofdma;
  50                }
  51
  52        spin_unlock(&of_dma_lock);
  53
  54        pr_debug("%s: can't find DMA controller %s\n", __func__,
  55                 dma_spec->np->full_name);
  56
  57        return NULL;
  58}
  59
  60/**
  61 * of_dma_put_controller - Decrement use count for a registered DMA controller
  62 * @of_dma:     pointer to DMA controller data
  63 *
  64 * Decrements the use_count variable in the DMA data structure. This function
  65 * should be called only when a valid pointer is returned from
  66 * of_dma_get_controller() and no further accesses to data referenced by that
  67 * pointer are needed.
  68 */
  69static void of_dma_put_controller(struct of_dma *ofdma)
  70{
  71        spin_lock(&of_dma_lock);
  72        ofdma->use_count--;
  73        spin_unlock(&of_dma_lock);
  74}
  75
  76/**
  77 * of_dma_controller_register - Register a DMA controller to DT DMA helpers
  78 * @np:                 device node of DMA controller
  79 * @of_dma_xlate:       translation function which converts a phandle
  80 *                      arguments list into a dma_chan structure
  81 * @data                pointer to controller specific data to be used by
  82 *                      translation function
  83 *
  84 * Returns 0 on success or appropriate errno value on error.
  85 *
  86 * Allocated memory should be freed with appropriate of_dma_controller_free()
  87 * call.
  88 */
  89int of_dma_controller_register(struct device_node *np,
  90                                struct dma_chan *(*of_dma_xlate)
  91                                (struct of_phandle_args *, struct of_dma *),
  92                                void *data)
  93{
  94        struct of_dma   *ofdma;
  95        int             nbcells;
  96        const __be32    *prop;
  97
  98        if (!np || !of_dma_xlate) {
  99                pr_err("%s: not enough information provided\n", __func__);
 100                return -EINVAL;
 101        }
 102
 103        ofdma = kzalloc(sizeof(*ofdma), GFP_KERNEL);
 104        if (!ofdma)
 105                return -ENOMEM;
 106
 107        prop = of_get_property(np, "#dma-cells", NULL);
 108        if (prop)
 109                nbcells = be32_to_cpup(prop);
 110
 111        if (!prop || !nbcells) {
 112                pr_err("%s: #dma-cells property is missing or invalid\n",
 113                       __func__);
 114                kfree(ofdma);
 115                return -EINVAL;
 116        }
 117
 118        ofdma->of_node = np;
 119        ofdma->of_dma_nbcells = nbcells;
 120        ofdma->of_dma_xlate = of_dma_xlate;
 121        ofdma->of_dma_data = data;
 122        ofdma->use_count = 0;
 123
 124        /* Now queue of_dma controller structure in list */
 125        spin_lock(&of_dma_lock);
 126        list_add_tail(&ofdma->of_dma_controllers, &of_dma_list);
 127        spin_unlock(&of_dma_lock);
 128
 129        return 0;
 130}
 131EXPORT_SYMBOL_GPL(of_dma_controller_register);
 132
 133/**
 134 * of_dma_controller_free - Remove a DMA controller from DT DMA helpers list
 135 * @np:         device node of DMA controller
 136 *
 137 * Memory allocated by of_dma_controller_register() is freed here.
 138 */
 139int of_dma_controller_free(struct device_node *np)
 140{
 141        struct of_dma *ofdma;
 142
 143        spin_lock(&of_dma_lock);
 144
 145        if (list_empty(&of_dma_list)) {
 146                spin_unlock(&of_dma_lock);
 147                return -ENODEV;
 148        }
 149
 150        list_for_each_entry(ofdma, &of_dma_list, of_dma_controllers)
 151                if (ofdma->of_node == np) {
 152                        if (ofdma->use_count) {
 153                                spin_unlock(&of_dma_lock);
 154                                return -EBUSY;
 155                        }
 156
 157                        list_del(&ofdma->of_dma_controllers);
 158                        spin_unlock(&of_dma_lock);
 159                        kfree(ofdma);
 160                        return 0;
 161                }
 162
 163        spin_unlock(&of_dma_lock);
 164        return -ENODEV;
 165}
 166EXPORT_SYMBOL_GPL(of_dma_controller_free);
 167
 168/**
 169 * of_dma_match_channel - Check if a DMA specifier matches name
 170 * @np:         device node to look for DMA channels
 171 * @name:       channel name to be matched
 172 * @index:      index of DMA specifier in list of DMA specifiers
 173 * @dma_spec:   pointer to DMA specifier as found in the device tree
 174 *
 175 * Check if the DMA specifier pointed to by the index in a list of DMA
 176 * specifiers, matches the name provided. Returns 0 if the name matches and
 177 * a valid pointer to the DMA specifier is found. Otherwise returns -ENODEV.
 178 */
 179static int of_dma_match_channel(struct device_node *np, char *name, int index,
 180                                struct of_phandle_args *dma_spec)
 181{
 182        const char *s;
 183
 184        if (of_property_read_string_index(np, "dma-names", index, &s))
 185                return -ENODEV;
 186
 187        if (strcmp(name, s))
 188                return -ENODEV;
 189
 190        if (of_parse_phandle_with_args(np, "dmas", "#dma-cells", index,
 191                                       dma_spec))
 192                return -ENODEV;
 193
 194        return 0;
 195}
 196
 197/**
 198 * of_dma_request_slave_channel - Get the DMA slave channel
 199 * @np:         device node to get DMA request from
 200 * @name:       name of desired channel
 201 *
 202 * Returns pointer to appropriate dma channel on success or NULL on error.
 203 */
 204struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
 205                                              char *name)
 206{
 207        struct of_phandle_args  dma_spec;
 208        struct of_dma           *ofdma;
 209        struct dma_chan         *chan;
 210        int                     count, i;
 211
 212        if (!np || !name) {
 213                pr_err("%s: not enough information provided\n", __func__);
 214                return NULL;
 215        }
 216
 217        count = of_property_count_strings(np, "dma-names");
 218        if (count < 0) {
 219                pr_err("%s: dma-names property missing or empty\n", __func__);
 220                return NULL;
 221        }
 222
 223        for (i = 0; i < count; i++) {
 224                if (of_dma_match_channel(np, name, i, &dma_spec))
 225                        continue;
 226
 227                ofdma = of_dma_get_controller(&dma_spec);
 228
 229                if (!ofdma)
 230                        continue;
 231
 232                chan = ofdma->of_dma_xlate(&dma_spec, ofdma);
 233
 234                of_dma_put_controller(ofdma);
 235
 236                of_node_put(dma_spec.np);
 237
 238                if (chan)
 239                        return chan;
 240        }
 241
 242        return NULL;
 243}
 244
 245/**
 246 * of_dma_simple_xlate - Simple DMA engine translation function
 247 * @dma_spec:   pointer to DMA specifier as found in the device tree
 248 * @of_dma:     pointer to DMA controller data
 249 *
 250 * A simple translation function for devices that use a 32-bit value for the
 251 * filter_param when calling the DMA engine dma_request_channel() function.
 252 * Note that this translation function requires that #dma-cells is equal to 1
 253 * and the argument of the dma specifier is the 32-bit filter_param. Returns
 254 * pointer to appropriate dma channel on success or NULL on error.
 255 */
 256struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
 257                                                struct of_dma *ofdma)
 258{
 259        int count = dma_spec->args_count;
 260        struct of_dma_filter_info *info = ofdma->of_dma_data;
 261
 262        if (!info || !info->filter_fn)
 263                return NULL;
 264
 265        if (count != 1)
 266                return NULL;
 267
 268        return dma_request_channel(info->dma_cap, info->filter_fn,
 269                        &dma_spec->args[0]);
 270}
 271EXPORT_SYMBOL_GPL(of_dma_simple_xlate);
 272
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.