linux/arch/arm/mach-u300/padmux.c
<<
>>
Prefs
   1/*
   2 *
   3 * arch/arm/mach-u300/padmux.c
   4 *
   5 *
   6 * Copyright (C) 2009 ST-Ericsson AB
   7 * License terms: GNU General Public License (GPL) version 2
   8 * U300 PADMUX functions
   9 * Author: Martin Persson <martin.persson@stericsson.com>
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/kernel.h>
  14#include <linux/device.h>
  15#include <linux/err.h>
  16#include <linux/errno.h>
  17#include <linux/io.h>
  18#include <linux/mutex.h>
  19#include <linux/string.h>
  20#include <linux/bug.h>
  21#include <linux/debugfs.h>
  22#include <linux/seq_file.h>
  23#include <mach/u300-regs.h>
  24#include <mach/syscon.h>
  25#include "padmux.h"
  26
  27static DEFINE_MUTEX(pmx_mutex);
  28
  29const u32 pmx_registers[] = {
  30        (U300_SYSCON_VBASE + U300_SYSCON_PMC1LR),
  31        (U300_SYSCON_VBASE + U300_SYSCON_PMC1HR),
  32        (U300_SYSCON_VBASE + U300_SYSCON_PMC2R),
  33        (U300_SYSCON_VBASE + U300_SYSCON_PMC3R),
  34        (U300_SYSCON_VBASE + U300_SYSCON_PMC4R)
  35};
  36
  37/* High level functionality */
  38
  39/* Lazy dog:
  40 * onmask = {
  41 *   {"PMC1LR" mask, "PMC1LR" value},
  42 *   {"PMC1HR" mask, "PMC1HR" value},
  43 *   {"PMC2R"  mask, "PMC2R"  value},
  44 *   {"PMC3R"  mask, "PMC3R"  value},
  45 *   {"PMC4R"  mask, "PMC4R"  value}
  46 * }
  47 */
  48static struct pmx mmc_setting = {
  49        .setting = U300_APP_PMX_MMC_SETTING,
  50        .default_on = false,
  51        .activated = false,
  52        .name = "MMC",
  53        .onmask = {
  54                   {U300_SYSCON_PMC1LR_MMCSD_MASK,
  55                    U300_SYSCON_PMC1LR_MMCSD_MMCSD},
  56                   {0, 0},
  57                   {0, 0},
  58                   {0, 0},
  59                   {U300_SYSCON_PMC4R_APP_MISC_12_MASK,
  60                    U300_SYSCON_PMC4R_APP_MISC_12_APP_GPIO}
  61                   },
  62};
  63
  64static struct pmx spi_setting = {
  65        .setting = U300_APP_PMX_SPI_SETTING,
  66        .default_on = false,
  67        .activated = false,
  68        .name = "SPI",
  69        .onmask = {{0, 0},
  70                   {U300_SYSCON_PMC1HR_APP_SPI_2_MASK |
  71                    U300_SYSCON_PMC1HR_APP_SPI_CS_1_MASK |
  72                    U300_SYSCON_PMC1HR_APP_SPI_CS_2_MASK,
  73                    U300_SYSCON_PMC1HR_APP_SPI_2_SPI |
  74                    U300_SYSCON_PMC1HR_APP_SPI_CS_1_SPI |
  75                    U300_SYSCON_PMC1HR_APP_SPI_CS_2_SPI},
  76                   {0, 0},
  77                   {0, 0},
  78                   {0, 0}
  79                   },
  80};
  81
  82/* Available padmux settings */
  83static struct pmx *pmx_settings[] = {
  84        &mmc_setting,
  85        &spi_setting,
  86};
  87
  88static void update_registers(struct pmx *pmx, bool activate)
  89{
  90        u16 regval, val, mask;
  91        int i;
  92
  93        for (i = 0; i < ARRAY_SIZE(pmx_registers); i++) {
  94                if (activate)
  95                        val = pmx->onmask[i].val;
  96                else
  97                        val = 0;
  98
  99                mask = pmx->onmask[i].mask;
 100                if (mask != 0) {
 101                        regval = readw(pmx_registers[i]);
 102                        regval &= ~mask;
 103                        regval |= val;
 104                        writew(regval, pmx_registers[i]);
 105                }
 106        }
 107}
 108
 109struct pmx *pmx_get(struct device *dev, enum pmx_settings setting)
 110{
 111        int i;
 112        struct pmx *pmx = ERR_PTR(-ENOENT);
 113
 114        if (dev == NULL)
 115                return ERR_PTR(-EINVAL);
 116
 117        mutex_lock(&pmx_mutex);
 118        for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
 119
 120                if (setting == pmx_settings[i]->setting) {
 121
 122                        if (pmx_settings[i]->dev != NULL) {
 123                                WARN(1, "padmux: required setting "
 124                                     "in use by another consumer\n");
 125                        } else {
 126                                pmx = pmx_settings[i];
 127                                pmx->dev = dev;
 128                                dev_dbg(dev, "padmux: setting nr %d is now "
 129                                        "bound to %s and ready to use\n",
 130                                        setting, dev_name(dev));
 131                                break;
 132                        }
 133                }
 134        }
 135        mutex_unlock(&pmx_mutex);
 136
 137        return pmx;
 138}
 139EXPORT_SYMBOL(pmx_get);
 140
 141int pmx_put(struct device *dev, struct pmx *pmx)
 142{
 143        int i;
 144        int ret = -ENOENT;
 145
 146        if (pmx == NULL || dev == NULL)
 147                return -EINVAL;
 148
 149        mutex_lock(&pmx_mutex);
 150        for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
 151
 152                if (pmx->setting == pmx_settings[i]->setting) {
 153
 154                        if (dev != pmx->dev) {
 155                                WARN(1, "padmux: cannot release handle as "
 156                                        "it is bound to another consumer\n");
 157                                ret = -EINVAL;
 158                                break;
 159                        } else {
 160                                pmx_settings[i]->dev = NULL;
 161                                ret = 0;
 162                                break;
 163                        }
 164                }
 165        }
 166        mutex_unlock(&pmx_mutex);
 167
 168        return ret;
 169}
 170EXPORT_SYMBOL(pmx_put);
 171
 172int pmx_activate(struct device *dev, struct pmx *pmx)
 173{
 174        int i, j, ret;
 175        ret = 0;
 176
 177        if (pmx == NULL || dev == NULL)
 178                return -EINVAL;
 179
 180        mutex_lock(&pmx_mutex);
 181
 182        /* Make sure the required bits are not used */
 183        for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
 184
 185                if (pmx_settings[i]->dev == NULL || pmx_settings[i] == pmx)
 186                        continue;
 187
 188                for (j = 0; j < ARRAY_SIZE(pmx_registers); j++) {
 189
 190                        if (pmx_settings[i]->onmask[j].mask & pmx->
 191                                onmask[j].mask) {
 192                                /* More than one entry on the same bits */
 193                                WARN(1, "padmux: cannot activate "
 194                                        "setting. Bit conflict with "
 195                                        "an active setting\n");
 196
 197                                ret = -EUSERS;
 198                                goto exit;
 199                        }
 200                }
 201        }
 202        update_registers(pmx, true);
 203        pmx->activated = true;
 204        dev_dbg(dev, "padmux: setting nr %d is activated\n",
 205                pmx->setting);
 206
 207exit:
 208        mutex_unlock(&pmx_mutex);
 209        return ret;
 210}
 211EXPORT_SYMBOL(pmx_activate);
 212
 213int pmx_deactivate(struct device *dev, struct pmx *pmx)
 214{
 215        int i;
 216        int ret = -ENOENT;
 217
 218        if (pmx == NULL || dev == NULL)
 219                return -EINVAL;
 220
 221        mutex_lock(&pmx_mutex);
 222        for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
 223
 224                if (pmx_settings[i]->dev == NULL)
 225                        continue;
 226
 227                if (pmx->setting == pmx_settings[i]->setting) {
 228
 229                        if (dev != pmx->dev) {
 230                                WARN(1, "padmux: cannot deactivate "
 231                                     "pmx setting as it was activated "
 232                                     "by another consumer\n");
 233
 234                                ret = -EBUSY;
 235                                continue;
 236                        } else {
 237                                update_registers(pmx, false);
 238                                pmx_settings[i]->dev = NULL;
 239                                pmx->activated = false;
 240                                ret = 0;
 241                                dev_dbg(dev, "padmux: setting nr %d is deactivated",
 242                                        pmx->setting);
 243                                break;
 244                        }
 245                }
 246        }
 247        mutex_unlock(&pmx_mutex);
 248
 249        return ret;
 250}
 251EXPORT_SYMBOL(pmx_deactivate);
 252
 253/*
 254 * For internal use only. If it is to be exported,
 255 * it should be reentrant. Notice that pmx_activate
 256 * (i.e. runtime settings) always override default settings.
 257 */
 258static int pmx_set_default(void)
 259{
 260        /* Used to identify several entries on the same bits */
 261        u16 modbits[ARRAY_SIZE(pmx_registers)];
 262
 263        int i, j;
 264
 265        memset(modbits, 0, ARRAY_SIZE(pmx_registers) * sizeof(u16));
 266
 267        for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
 268
 269                if (!pmx_settings[i]->default_on)
 270                        continue;
 271
 272                for (j = 0; j < ARRAY_SIZE(pmx_registers); j++) {
 273
 274                        /* Make sure there is only one entry on the same bits */
 275                        if (modbits[j] & pmx_settings[i]->onmask[j].mask) {
 276                                BUG();
 277                                return -EUSERS;
 278                        }
 279                        modbits[j] |= pmx_settings[i]->onmask[j].mask;
 280                }
 281                update_registers(pmx_settings[i], true);
 282        }
 283        return 0;
 284}
 285
 286#if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_U300_DEBUG))
 287static int pmx_show(struct seq_file *s, void *data)
 288{
 289        int i;
 290        seq_printf(s, "-------------------------------------------------\n");
 291        seq_printf(s, "SETTING     BOUND TO DEVICE               STATE\n");
 292        seq_printf(s, "-------------------------------------------------\n");
 293        mutex_lock(&pmx_mutex);
 294        for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
 295                /* Format pmx and device name nicely */
 296                char cdp[33];
 297                int chars;
 298
 299                chars = snprintf(&cdp[0], 17, "%s", pmx_settings[i]->name);
 300                while (chars < 16) {
 301                        cdp[chars] = ' ';
 302                        chars++;
 303                }
 304                chars = snprintf(&cdp[16], 17, "%s", pmx_settings[i]->dev ?
 305                                dev_name(pmx_settings[i]->dev) : "N/A");
 306                while (chars < 16) {
 307                        cdp[chars+16] = ' ';
 308                        chars++;
 309                }
 310                cdp[32] = '\0';
 311
 312                seq_printf(s,
 313                        "%s\t%s\n",
 314                        &cdp[0],
 315                        pmx_settings[i]->activated ?
 316                        "ACTIVATED" : "DEACTIVATED"
 317                        );
 318
 319        }
 320        mutex_unlock(&pmx_mutex);
 321        return 0;
 322}
 323
 324static int pmx_open(struct inode *inode, struct file *file)
 325{
 326        return single_open(file, pmx_show, NULL);
 327}
 328
 329static const struct file_operations pmx_operations = {
 330        .owner          = THIS_MODULE,
 331        .open           = pmx_open,
 332        .read           = seq_read,
 333        .llseek         = seq_lseek,
 334        .release        = single_release,
 335};
 336
 337static int __init init_pmx_read_debugfs(void)
 338{
 339        /* Expose a simple debugfs interface to view pmx settings */
 340        (void) debugfs_create_file("padmux", S_IFREG | S_IRUGO,
 341                                   NULL, NULL,
 342                                   &pmx_operations);
 343        return 0;
 344}
 345
 346/*
 347 * This needs to come in after the core_initcall(),
 348 * because debugfs is not available until
 349 * the subsystems come up.
 350 */
 351module_init(init_pmx_read_debugfs);
 352#endif
 353
 354static int __init pmx_init(void)
 355{
 356        int ret;
 357
 358        ret = pmx_set_default();
 359
 360        if (IS_ERR_VALUE(ret))
 361                pr_crit("padmux: default settings could not be set\n");
 362
 363        return 0;
 364}
 365
 366/* Should be initialized before consumers */
 367core_initcall(pmx_init);
 368