linux/arch/arm/plat-spear/padmux.c
<<
>>
Prefs
   1/*
   2 * arch/arm/plat-spear/include/plat/padmux.c
   3 *
   4 * SPEAr platform specific gpio pads muxing source file
   5 *
   6 * Copyright (C) 2009 ST Microelectronics
   7 * Viresh Kumar<viresh.kumar@st.com>
   8 *
   9 * This file is licensed under the terms of the GNU General Public
  10 * License version 2. This program is licensed "as is" without any
  11 * warranty of any kind, whether express or implied.
  12 */
  13
  14#include <linux/err.h>
  15#include <linux/io.h>
  16#include <linux/slab.h>
  17#include <plat/padmux.h>
  18
  19/*
  20 * struct pmx: pmx definition structure
  21 *
  22 * base: base address of configuration registers
  23 * mode_reg: mode configurations
  24 * mux_reg: muxing configurations
  25 * active_mode: pointer to current active mode
  26 */
  27struct pmx {
  28        u32 base;
  29        struct pmx_reg mode_reg;
  30        struct pmx_reg mux_reg;
  31        struct pmx_mode *active_mode;
  32};
  33
  34static struct pmx *pmx;
  35
  36/**
  37 * pmx_mode_set - Enables an multiplexing mode
  38 * @mode - pointer to pmx mode
  39 *
  40 * It will set mode of operation in hardware.
  41 * Returns -ve on Err otherwise 0
  42 */
  43static int pmx_mode_set(struct pmx_mode *mode)
  44{
  45        u32 val;
  46
  47        if (!mode->name)
  48                return -EFAULT;
  49
  50        pmx->active_mode = mode;
  51
  52        val = readl(pmx->base + pmx->mode_reg.offset);
  53        val &= ~pmx->mode_reg.mask;
  54        val |= mode->mask & pmx->mode_reg.mask;
  55        writel(val, pmx->base + pmx->mode_reg.offset);
  56
  57        return 0;
  58}
  59
  60/**
  61 * pmx_devs_enable - Enables list of devices
  62 * @devs - pointer to pmx device array
  63 * @count - number of devices to enable
  64 *
  65 * It will enable pads for all required peripherals once and only once.
  66 * If peripheral is not supported by current mode then request is rejected.
  67 * Conflicts between peripherals are not handled and peripherals will be
  68 * enabled in the order they are present in pmx_dev array.
  69 * In case of conflicts last peripheral enabled will be present.
  70 * Returns -ve on Err otherwise 0
  71 */
  72static int pmx_devs_enable(struct pmx_dev **devs, u8 count)
  73{
  74        u32 val, i, mask;
  75
  76        if (!count)
  77                return -EINVAL;
  78
  79        val = readl(pmx->base + pmx->mux_reg.offset);
  80        for (i = 0; i < count; i++) {
  81                u8 j = 0;
  82
  83                if (!devs[i]->name || !devs[i]->modes) {
  84                        printk(KERN_ERR "padmux: dev name or modes is null\n");
  85                        continue;
  86                }
  87                /* check if peripheral exists in active mode */
  88                if (pmx->active_mode) {
  89                        bool found = false;
  90                        for (j = 0; j < devs[i]->mode_count; j++) {
  91                                if (devs[i]->modes[j].ids &
  92                                                pmx->active_mode->id) {
  93                                        found = true;
  94                                        break;
  95                                }
  96                        }
  97                        if (found == false) {
  98                                printk(KERN_ERR "%s device not available in %s"\
  99                                                "mode\n", devs[i]->name,
 100                                                pmx->active_mode->name);
 101                                continue;
 102                        }
 103                }
 104
 105                /* enable peripheral */
 106                mask = devs[i]->modes[j].mask & pmx->mux_reg.mask;
 107                if (devs[i]->enb_on_reset)
 108                        val &= ~mask;
 109                else
 110                        val |= mask;
 111
 112                devs[i]->is_active = true;
 113        }
 114        writel(val, pmx->base + pmx->mux_reg.offset);
 115        kfree(pmx);
 116
 117        /* this will ensure that multiplexing can't be changed now */
 118        pmx = (struct pmx *)-1;
 119
 120        return 0;
 121}
 122
 123/**
 124 * pmx_register - registers a platform requesting pad mux feature
 125 * @driver - pointer to driver structure containing driver specific parameters
 126 *
 127 * Also this must be called only once. This will allocate memory for pmx
 128 * structure, will call pmx_mode_set, will call pmx_devs_enable.
 129 * Returns -ve on Err otherwise 0
 130 */
 131int pmx_register(struct pmx_driver *driver)
 132{
 133        int ret = 0;
 134
 135        if (pmx)
 136                return -EPERM;
 137        if (!driver->base || !driver->devs)
 138                return -EFAULT;
 139
 140        pmx = kzalloc(sizeof(*pmx), GFP_KERNEL);
 141        if (!pmx)
 142                return -ENOMEM;
 143
 144        pmx->base = (u32)driver->base;
 145        pmx->mode_reg.offset = driver->mode_reg.offset;
 146        pmx->mode_reg.mask = driver->mode_reg.mask;
 147        pmx->mux_reg.offset = driver->mux_reg.offset;
 148        pmx->mux_reg.mask = driver->mux_reg.mask;
 149
 150        /* choose mode to enable */
 151        if (driver->mode) {
 152                ret = pmx_mode_set(driver->mode);
 153                if (ret)
 154                        goto pmx_fail;
 155        }
 156        ret = pmx_devs_enable(driver->devs, driver->devs_count);
 157        if (ret)
 158                goto pmx_fail;
 159
 160        return 0;
 161
 162pmx_fail:
 163        return ret;
 164}
 165