linux/drivers/mfd/arizona-core.c
<<
>>
Prefs
   1/*
   2 * Arizona core driver
   3 *
   4 * Copyright 2012 Wolfson Microelectronics plc
   5 *
   6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.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/delay.h>
  14#include <linux/err.h>
  15#include <linux/gpio.h>
  16#include <linux/interrupt.h>
  17#include <linux/mfd/core.h>
  18#include <linux/module.h>
  19#include <linux/pm_runtime.h>
  20#include <linux/regmap.h>
  21#include <linux/regulator/consumer.h>
  22#include <linux/slab.h>
  23
  24#include <linux/mfd/arizona/core.h>
  25#include <linux/mfd/arizona/registers.h>
  26
  27#include "arizona.h"
  28
  29static const char *wm5102_core_supplies[] = {
  30        "AVDD",
  31        "DBVDD1",
  32};
  33
  34int arizona_clk32k_enable(struct arizona *arizona)
  35{
  36        int ret = 0;
  37
  38        mutex_lock(&arizona->clk_lock);
  39
  40        arizona->clk32k_ref++;
  41
  42        if (arizona->clk32k_ref == 1)
  43                ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
  44                                         ARIZONA_CLK_32K_ENA,
  45                                         ARIZONA_CLK_32K_ENA);
  46
  47        if (ret != 0)
  48                arizona->clk32k_ref--;
  49
  50        mutex_unlock(&arizona->clk_lock);
  51
  52        return ret;
  53}
  54EXPORT_SYMBOL_GPL(arizona_clk32k_enable);
  55
  56int arizona_clk32k_disable(struct arizona *arizona)
  57{
  58        int ret = 0;
  59
  60        mutex_lock(&arizona->clk_lock);
  61
  62        BUG_ON(arizona->clk32k_ref <= 0);
  63
  64        arizona->clk32k_ref--;
  65
  66        if (arizona->clk32k_ref == 0)
  67                regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
  68                                   ARIZONA_CLK_32K_ENA, 0);
  69
  70        mutex_unlock(&arizona->clk_lock);
  71
  72        return ret;
  73}
  74EXPORT_SYMBOL_GPL(arizona_clk32k_disable);
  75
  76static irqreturn_t arizona_clkgen_err(int irq, void *data)
  77{
  78        struct arizona *arizona = data;
  79
  80        dev_err(arizona->dev, "CLKGEN error\n");
  81
  82        return IRQ_HANDLED;
  83}
  84
  85static irqreturn_t arizona_underclocked(int irq, void *data)
  86{
  87        struct arizona *arizona = data;
  88        unsigned int val;
  89        int ret;
  90
  91        ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_8,
  92                          &val);
  93        if (ret != 0) {
  94                dev_err(arizona->dev, "Failed to read underclock status: %d\n",
  95                        ret);
  96                return IRQ_NONE;
  97        }
  98
  99        if (val & ARIZONA_AIF3_UNDERCLOCKED_STS)
 100                dev_err(arizona->dev, "AIF3 underclocked\n");
 101        if (val & ARIZONA_AIF3_UNDERCLOCKED_STS)
 102                dev_err(arizona->dev, "AIF3 underclocked\n");
 103        if (val & ARIZONA_AIF2_UNDERCLOCKED_STS)
 104                dev_err(arizona->dev, "AIF1 underclocked\n");
 105        if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS)
 106                dev_err(arizona->dev, "ISRC2 underclocked\n");
 107        if (val & ARIZONA_ISRC1_UNDERCLOCKED_STS)
 108                dev_err(arizona->dev, "ISRC1 underclocked\n");
 109        if (val & ARIZONA_FX_UNDERCLOCKED_STS)
 110                dev_err(arizona->dev, "FX underclocked\n");
 111        if (val & ARIZONA_ASRC_UNDERCLOCKED_STS)
 112                dev_err(arizona->dev, "ASRC underclocked\n");
 113        if (val & ARIZONA_DAC_UNDERCLOCKED_STS)
 114                dev_err(arizona->dev, "DAC underclocked\n");
 115        if (val & ARIZONA_ADC_UNDERCLOCKED_STS)
 116                dev_err(arizona->dev, "ADC underclocked\n");
 117        if (val & ARIZONA_MIXER_UNDERCLOCKED_STS)
 118                dev_err(arizona->dev, "Mixer underclocked\n");
 119
 120        return IRQ_HANDLED;
 121}
 122
 123static irqreturn_t arizona_overclocked(int irq, void *data)
 124{
 125        struct arizona *arizona = data;
 126        unsigned int val[2];
 127        int ret;
 128        
 129        ret = regmap_bulk_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_6,
 130                               &val[0], 2);
 131        if (ret != 0) {
 132                dev_err(arizona->dev, "Failed to read overclock status: %d\n",
 133                        ret);
 134                return IRQ_NONE;
 135        }
 136
 137        if (val[0] & ARIZONA_PWM_OVERCLOCKED_STS)
 138                dev_err(arizona->dev, "PWM overclocked\n");
 139        if (val[0] & ARIZONA_FX_CORE_OVERCLOCKED_STS)
 140                dev_err(arizona->dev, "FX core overclocked\n");
 141        if (val[0] & ARIZONA_DAC_SYS_OVERCLOCKED_STS)
 142                dev_err(arizona->dev, "DAC SYS overclocked\n");
 143        if (val[0] & ARIZONA_DAC_WARP_OVERCLOCKED_STS)
 144                dev_err(arizona->dev, "DAC WARP overclocked\n");
 145        if (val[0] & ARIZONA_ADC_OVERCLOCKED_STS)
 146                dev_err(arizona->dev, "ADC overclocked\n");
 147        if (val[0] & ARIZONA_MIXER_OVERCLOCKED_STS)
 148                dev_err(arizona->dev, "Mixer overclocked\n");
 149        if (val[0] & ARIZONA_AIF3_SYNC_OVERCLOCKED_STS)
 150                dev_err(arizona->dev, "AIF3 overclocked\n");
 151        if (val[0] & ARIZONA_AIF2_SYNC_OVERCLOCKED_STS)
 152                dev_err(arizona->dev, "AIF2 overclocked\n");
 153        if (val[0] & ARIZONA_AIF1_SYNC_OVERCLOCKED_STS)
 154                dev_err(arizona->dev, "AIF1 overclocked\n");
 155        if (val[0] & ARIZONA_PAD_CTRL_OVERCLOCKED_STS)
 156                dev_err(arizona->dev, "Pad control overclocked\n");
 157
 158        if (val[1] & ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS)
 159                dev_err(arizona->dev, "Slimbus subsystem overclocked\n");
 160        if (val[1] & ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS)
 161                dev_err(arizona->dev, "Slimbus async overclocked\n");
 162        if (val[1] & ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS)
 163                dev_err(arizona->dev, "Slimbus sync overclocked\n");
 164        if (val[1] & ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS)
 165                dev_err(arizona->dev, "ASRC async system overclocked\n");
 166        if (val[1] & ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS)
 167                dev_err(arizona->dev, "ASRC async WARP overclocked\n");
 168        if (val[1] & ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS)
 169                dev_err(arizona->dev, "ASRC sync system overclocked\n");
 170        if (val[1] & ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS)
 171                dev_err(arizona->dev, "ASRC sync WARP overclocked\n");
 172        if (val[1] & ARIZONA_ADSP2_1_OVERCLOCKED_STS)
 173                dev_err(arizona->dev, "DSP1 overclocked\n");
 174        if (val[1] & ARIZONA_ISRC2_OVERCLOCKED_STS)
 175                dev_err(arizona->dev, "ISRC2 overclocked\n");
 176        if (val[1] & ARIZONA_ISRC1_OVERCLOCKED_STS)
 177                dev_err(arizona->dev, "ISRC1 overclocked\n");
 178
 179        return IRQ_HANDLED;
 180}
 181
 182static int arizona_wait_for_boot(struct arizona *arizona)
 183{
 184        unsigned int reg;
 185        int ret, i;
 186
 187        /*
 188         * We can't use an interrupt as we need to runtime resume to do so,
 189         * we won't race with the interrupt handler as it'll be blocked on
 190         * runtime resume.
 191         */
 192        for (i = 0; i < 5; i++) {
 193                msleep(1);
 194
 195                ret = regmap_read(arizona->regmap,
 196                                  ARIZONA_INTERRUPT_RAW_STATUS_5, &reg);
 197                if (ret != 0) {
 198                        dev_err(arizona->dev, "Failed to read boot state: %d\n",
 199                                ret);
 200                        continue;
 201                }
 202
 203                if (reg & ARIZONA_BOOT_DONE_STS)
 204                        break;
 205        }
 206
 207        if (reg & ARIZONA_BOOT_DONE_STS) {
 208                regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5,
 209                             ARIZONA_BOOT_DONE_STS);
 210        } else {
 211                dev_err(arizona->dev, "Device boot timed out: %x\n", reg);
 212                return -ETIMEDOUT;
 213        }
 214
 215        pm_runtime_mark_last_busy(arizona->dev);
 216
 217        return 0;
 218}
 219
 220#ifdef CONFIG_PM_RUNTIME
 221static int arizona_runtime_resume(struct device *dev)
 222{
 223        struct arizona *arizona = dev_get_drvdata(dev);
 224        int ret;
 225
 226        dev_dbg(arizona->dev, "Leaving AoD mode\n");
 227
 228        ret = regulator_enable(arizona->dcvdd);
 229        if (ret != 0) {
 230                dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret);
 231                return ret;
 232        }
 233
 234        regcache_cache_only(arizona->regmap, false);
 235
 236        ret = arizona_wait_for_boot(arizona);
 237        if (ret != 0) {
 238                regulator_disable(arizona->dcvdd);
 239                return ret;
 240        }
 241
 242        regcache_sync(arizona->regmap);
 243
 244        return 0;
 245}
 246
 247static int arizona_runtime_suspend(struct device *dev)
 248{
 249        struct arizona *arizona = dev_get_drvdata(dev);
 250
 251        dev_dbg(arizona->dev, "Entering AoD mode\n");
 252
 253        regulator_disable(arizona->dcvdd);
 254        regcache_cache_only(arizona->regmap, true);
 255        regcache_mark_dirty(arizona->regmap);
 256
 257        return 0;
 258}
 259#endif
 260
 261const struct dev_pm_ops arizona_pm_ops = {
 262        SET_RUNTIME_PM_OPS(arizona_runtime_suspend,
 263                           arizona_runtime_resume,
 264                           NULL)
 265};
 266EXPORT_SYMBOL_GPL(arizona_pm_ops);
 267
 268static struct mfd_cell early_devs[] = {
 269        { .name = "arizona-ldo1" },
 270};
 271
 272static struct mfd_cell wm5102_devs[] = {
 273        { .name = "arizona-extcon" },
 274        { .name = "arizona-gpio" },
 275        { .name = "arizona-micsupp" },
 276        { .name = "arizona-pwm" },
 277        { .name = "wm5102-codec" },
 278};
 279
 280static struct mfd_cell wm5110_devs[] = {
 281        { .name = "arizona-extcon" },
 282        { .name = "arizona-gpio" },
 283        { .name = "arizona-micsupp" },
 284        { .name = "arizona-pwm" },
 285        { .name = "wm5110-codec" },
 286};
 287
 288int __devinit arizona_dev_init(struct arizona *arizona)
 289{
 290        struct device *dev = arizona->dev;
 291        const char *type_name;
 292        unsigned int reg, val;
 293        int ret, i;
 294
 295        dev_set_drvdata(arizona->dev, arizona);
 296        mutex_init(&arizona->clk_lock);
 297
 298        if (dev_get_platdata(arizona->dev))
 299                memcpy(&arizona->pdata, dev_get_platdata(arizona->dev),
 300                       sizeof(arizona->pdata));
 301
 302        regcache_cache_only(arizona->regmap, true);
 303
 304        switch (arizona->type) {
 305        case WM5102:
 306        case WM5110:
 307                for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++)
 308                        arizona->core_supplies[i].supply
 309                                = wm5102_core_supplies[i];
 310                arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies);
 311                break;
 312        default:
 313                dev_err(arizona->dev, "Unknown device type %d\n",
 314                        arizona->type);
 315                return -EINVAL;
 316        }
 317
 318        ret = mfd_add_devices(arizona->dev, -1, early_devs,
 319                              ARRAY_SIZE(early_devs), NULL, 0, NULL);
 320        if (ret != 0) {
 321                dev_err(dev, "Failed to add early children: %d\n", ret);
 322                return ret;
 323        }
 324
 325        ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies,
 326                                      arizona->core_supplies);
 327        if (ret != 0) {
 328                dev_err(dev, "Failed to request core supplies: %d\n",
 329                        ret);
 330                goto err_early;
 331        }
 332
 333        arizona->dcvdd = devm_regulator_get(arizona->dev, "DCVDD");
 334        if (IS_ERR(arizona->dcvdd)) {
 335                ret = PTR_ERR(arizona->dcvdd);
 336                dev_err(dev, "Failed to request DCVDD: %d\n", ret);
 337                goto err_early;
 338        }
 339
 340        ret = regulator_bulk_enable(arizona->num_core_supplies,
 341                                    arizona->core_supplies);
 342        if (ret != 0) {
 343                dev_err(dev, "Failed to enable core supplies: %d\n",
 344                        ret);
 345                goto err_early;
 346        }
 347
 348        ret = regulator_enable(arizona->dcvdd);
 349        if (ret != 0) {
 350                dev_err(dev, "Failed to enable DCVDD: %d\n", ret);
 351                goto err_enable;
 352        }
 353
 354        if (arizona->pdata.reset) {
 355                /* Start out with /RESET low to put the chip into reset */
 356                ret = gpio_request_one(arizona->pdata.reset,
 357                                       GPIOF_DIR_OUT | GPIOF_INIT_LOW,
 358                                       "arizona /RESET");
 359                if (ret != 0) {
 360                        dev_err(dev, "Failed to request /RESET: %d\n", ret);
 361                        goto err_dcvdd;
 362                }
 363
 364                gpio_set_value_cansleep(arizona->pdata.reset, 1);
 365        }
 366
 367        regcache_cache_only(arizona->regmap, false);
 368
 369        ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, &reg);
 370        if (ret != 0) {
 371                dev_err(dev, "Failed to read ID register: %d\n", ret);
 372                goto err_reset;
 373        }
 374
 375        ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION,
 376                          &arizona->rev);
 377        if (ret != 0) {
 378                dev_err(dev, "Failed to read revision register: %d\n", ret);
 379                goto err_reset;
 380        }
 381        arizona->rev &= ARIZONA_DEVICE_REVISION_MASK;
 382
 383        switch (reg) {
 384#ifdef CONFIG_MFD_WM5102
 385        case 0x5102:
 386                type_name = "WM5102";
 387                if (arizona->type != WM5102) {
 388                        dev_err(arizona->dev, "WM5102 registered as %d\n",
 389                                arizona->type);
 390                        arizona->type = WM5102;
 391                }
 392                ret = wm5102_patch(arizona);
 393                break;
 394#endif
 395#ifdef CONFIG_MFD_WM5110
 396        case 0x5110:
 397                type_name = "WM5110";
 398                if (arizona->type != WM5110) {
 399                        dev_err(arizona->dev, "WM5110 registered as %d\n",
 400                                arizona->type);
 401                        arizona->type = WM5110;
 402                }
 403                ret = wm5110_patch(arizona);
 404                break;
 405#endif
 406        default:
 407                dev_err(arizona->dev, "Unknown device ID %x\n", reg);
 408                goto err_reset;
 409        }
 410
 411        dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A');
 412
 413        if (ret != 0)
 414                dev_err(arizona->dev, "Failed to apply patch: %d\n", ret);
 415
 416        /* If we have a /RESET GPIO we'll already be reset */
 417        if (!arizona->pdata.reset) {
 418                ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0);
 419                if (ret != 0) {
 420                        dev_err(dev, "Failed to reset device: %d\n", ret);
 421                        goto err_reset;
 422                }
 423        }
 424
 425        ret = arizona_wait_for_boot(arizona);
 426        if (ret != 0) {
 427                dev_err(arizona->dev, "Device failed initial boot: %d\n", ret);
 428                goto err_reset;
 429        }
 430
 431        for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
 432                if (!arizona->pdata.gpio_defaults[i])
 433                        continue;
 434
 435                regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i,
 436                             arizona->pdata.gpio_defaults[i]);
 437        }
 438
 439        pm_runtime_set_autosuspend_delay(arizona->dev, 100);
 440        pm_runtime_use_autosuspend(arizona->dev);
 441        pm_runtime_enable(arizona->dev);
 442
 443        /* Chip default */
 444        if (!arizona->pdata.clk32k_src)
 445                arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2;
 446
 447        switch (arizona->pdata.clk32k_src) {
 448        case ARIZONA_32KZ_MCLK1:
 449        case ARIZONA_32KZ_MCLK2:
 450                regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
 451                                   ARIZONA_CLK_32K_SRC_MASK,
 452                                   arizona->pdata.clk32k_src - 1);
 453                break;
 454        case ARIZONA_32KZ_NONE:
 455                regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
 456                                   ARIZONA_CLK_32K_SRC_MASK, 2);
 457                break;
 458        default:
 459                dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n",
 460                        arizona->pdata.clk32k_src);
 461                ret = -EINVAL;
 462                goto err_reset;
 463        }
 464
 465        for (i = 0; i < ARIZONA_MAX_INPUT; i++) {
 466                /* Default for both is 0 so noop with defaults */
 467                val = arizona->pdata.dmic_ref[i]
 468                        << ARIZONA_IN1_DMIC_SUP_SHIFT;
 469                val |= arizona->pdata.inmode[i] << ARIZONA_IN1_MODE_SHIFT;
 470
 471                regmap_update_bits(arizona->regmap,
 472                                   ARIZONA_IN1L_CONTROL + (i * 8),
 473                                   ARIZONA_IN1_DMIC_SUP_MASK |
 474                                   ARIZONA_IN1_MODE_MASK, val);
 475        }
 476
 477        for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) {
 478                /* Default is 0 so noop with defaults */
 479                if (arizona->pdata.out_mono[i])
 480                        val = ARIZONA_OUT1_MONO;
 481                else
 482                        val = 0;
 483
 484                regmap_update_bits(arizona->regmap,
 485                                   ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8),
 486                                   ARIZONA_OUT1_MONO, val);
 487        }
 488
 489        for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) {
 490                if (arizona->pdata.spk_mute[i])
 491                        regmap_update_bits(arizona->regmap,
 492                                           ARIZONA_PDM_SPK1_CTRL_1 + (i * 2),
 493                                           ARIZONA_SPK1_MUTE_ENDIAN_MASK |
 494                                           ARIZONA_SPK1_MUTE_SEQ1_MASK,
 495                                           arizona->pdata.spk_mute[i]);
 496
 497                if (arizona->pdata.spk_fmt[i])
 498                        regmap_update_bits(arizona->regmap,
 499                                           ARIZONA_PDM_SPK1_CTRL_2 + (i * 2),
 500                                           ARIZONA_SPK1_FMT_MASK,
 501                                           arizona->pdata.spk_fmt[i]);
 502        }
 503
 504        /* Set up for interrupts */
 505        ret = arizona_irq_init(arizona);
 506        if (ret != 0)
 507                goto err_reset;
 508
 509        arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error",
 510                            arizona_clkgen_err, arizona);
 511        arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked",
 512                            arizona_overclocked, arizona);
 513        arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked",
 514                            arizona_underclocked, arizona);
 515
 516        switch (arizona->type) {
 517        case WM5102:
 518                ret = mfd_add_devices(arizona->dev, -1, wm5102_devs,
 519                                      ARRAY_SIZE(wm5102_devs), NULL, 0, NULL);
 520                break;
 521        case WM5110:
 522                ret = mfd_add_devices(arizona->dev, -1, wm5110_devs,
 523                                      ARRAY_SIZE(wm5102_devs), NULL, 0, NULL);
 524                break;
 525        }
 526
 527        if (ret != 0) {
 528                dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret);
 529                goto err_irq;
 530        }
 531
 532#ifdef CONFIG_PM_RUNTIME
 533        regulator_disable(arizona->dcvdd);
 534#endif
 535
 536        return 0;
 537
 538err_irq:
 539        arizona_irq_exit(arizona);
 540err_reset:
 541        if (arizona->pdata.reset) {
 542                gpio_set_value_cansleep(arizona->pdata.reset, 1);
 543                gpio_free(arizona->pdata.reset);
 544        }
 545err_dcvdd:
 546        regulator_disable(arizona->dcvdd);
 547err_enable:
 548        regulator_bulk_disable(arizona->num_core_supplies,
 549                               arizona->core_supplies);
 550err_early:
 551        mfd_remove_devices(dev);
 552        return ret;
 553}
 554EXPORT_SYMBOL_GPL(arizona_dev_init);
 555
 556int __devexit arizona_dev_exit(struct arizona *arizona)
 557{
 558        mfd_remove_devices(arizona->dev);
 559        arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona);
 560        arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona);
 561        arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona);
 562        pm_runtime_disable(arizona->dev);
 563        arizona_irq_exit(arizona);
 564        return 0;
 565}
 566EXPORT_SYMBOL_GPL(arizona_dev_exit);
 567
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.