linux/drivers/mfd/twl4030-power.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/i2c/chips/twl4030-power.c
   3 *
   4 * Handle TWL4030 Power initialization
   5 *
   6 * Copyright (C) 2008 Nokia Corporation
   7 * Copyright (C) 2006 Texas Instruments, Inc
   8 *
   9 * Written by   Kalle Jokiniemi
  10 *              Peter De Schrijver <peter.de-schrijver@nokia.com>
  11 * Several fixes by Amit Kucheria <amit.kucheria@verdurent.com>
  12 *
  13 * This file is subject to the terms and conditions of the GNU General
  14 * Public License. See the file "COPYING" in the main directory of this
  15 * archive for more details.
  16 *
  17 * This program is distributed in the hope that it will be useful,
  18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20 * GNU General Public License for more details.
  21 *
  22 * You should have received a copy of the GNU General Public License
  23 * along with this program; if not, write to the Free Software
  24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  25 */
  26
  27#include <linux/module.h>
  28#include <linux/pm.h>
  29#include <linux/i2c/twl.h>
  30#include <linux/platform_device.h>
  31
  32#include <asm/mach-types.h>
  33
  34static u8 twl4030_start_script_address = 0x2b;
  35
  36#define PWR_P1_SW_EVENTS        0x10
  37#define PWR_DEVOFF      (1<<0)
  38
  39#define PHY_TO_OFF_PM_MASTER(p)         (p - 0x36)
  40#define PHY_TO_OFF_PM_RECEIVER(p)       (p - 0x5b)
  41
  42/* resource - hfclk */
  43#define R_HFCLKOUT_DEV_GRP      PHY_TO_OFF_PM_RECEIVER(0xe6)
  44
  45/* PM events */
  46#define R_P1_SW_EVENTS          PHY_TO_OFF_PM_MASTER(0x46)
  47#define R_P2_SW_EVENTS          PHY_TO_OFF_PM_MASTER(0x47)
  48#define R_P3_SW_EVENTS          PHY_TO_OFF_PM_MASTER(0x48)
  49#define R_CFG_P1_TRANSITION     PHY_TO_OFF_PM_MASTER(0x36)
  50#define R_CFG_P2_TRANSITION     PHY_TO_OFF_PM_MASTER(0x37)
  51#define R_CFG_P3_TRANSITION     PHY_TO_OFF_PM_MASTER(0x38)
  52
  53#define LVL_WAKEUP      0x08
  54
  55#define ENABLE_WARMRESET (1<<4)
  56
  57#define END_OF_SCRIPT           0x3f
  58
  59#define R_SEQ_ADD_A2S           PHY_TO_OFF_PM_MASTER(0x55)
  60#define R_SEQ_ADD_S2A12         PHY_TO_OFF_PM_MASTER(0x56)
  61#define R_SEQ_ADD_S2A3          PHY_TO_OFF_PM_MASTER(0x57)
  62#define R_SEQ_ADD_WARM          PHY_TO_OFF_PM_MASTER(0x58)
  63#define R_MEMORY_ADDRESS        PHY_TO_OFF_PM_MASTER(0x59)
  64#define R_MEMORY_DATA           PHY_TO_OFF_PM_MASTER(0x5a)
  65
  66/* resource configuration registers
  67   <RESOURCE>_DEV_GRP   at address 'n+0'
  68   <RESOURCE>_TYPE      at address 'n+1'
  69   <RESOURCE>_REMAP     at address 'n+2'
  70   <RESOURCE>_DEDICATED at address 'n+3'
  71*/
  72#define DEV_GRP_OFFSET          0
  73#define TYPE_OFFSET             1
  74#define REMAP_OFFSET            2
  75#define DEDICATED_OFFSET        3
  76
  77/* Bit positions in the registers */
  78
  79/* <RESOURCE>_DEV_GRP */
  80#define DEV_GRP_SHIFT           5
  81#define DEV_GRP_MASK            (7 << DEV_GRP_SHIFT)
  82
  83/* <RESOURCE>_TYPE */
  84#define TYPE_SHIFT              0
  85#define TYPE_MASK               (7 << TYPE_SHIFT)
  86#define TYPE2_SHIFT             3
  87#define TYPE2_MASK              (3 << TYPE2_SHIFT)
  88
  89/* <RESOURCE>_REMAP */
  90#define SLEEP_STATE_SHIFT       0
  91#define SLEEP_STATE_MASK        (0xf << SLEEP_STATE_SHIFT)
  92#define OFF_STATE_SHIFT         4
  93#define OFF_STATE_MASK          (0xf << OFF_STATE_SHIFT)
  94
  95static u8 res_config_addrs[] = {
  96        [RES_VAUX1]     = 0x17,
  97        [RES_VAUX2]     = 0x1b,
  98        [RES_VAUX3]     = 0x1f,
  99        [RES_VAUX4]     = 0x23,
 100        [RES_VMMC1]     = 0x27,
 101        [RES_VMMC2]     = 0x2b,
 102        [RES_VPLL1]     = 0x2f,
 103        [RES_VPLL2]     = 0x33,
 104        [RES_VSIM]      = 0x37,
 105        [RES_VDAC]      = 0x3b,
 106        [RES_VINTANA1]  = 0x3f,
 107        [RES_VINTANA2]  = 0x43,
 108        [RES_VINTDIG]   = 0x47,
 109        [RES_VIO]       = 0x4b,
 110        [RES_VDD1]      = 0x55,
 111        [RES_VDD2]      = 0x63,
 112        [RES_VUSB_1V5]  = 0x71,
 113        [RES_VUSB_1V8]  = 0x74,
 114        [RES_VUSB_3V1]  = 0x77,
 115        [RES_VUSBCP]    = 0x7a,
 116        [RES_REGEN]     = 0x7f,
 117        [RES_NRES_PWRON] = 0x82,
 118        [RES_CLKEN]     = 0x85,
 119        [RES_SYSEN]     = 0x88,
 120        [RES_HFCLKOUT]  = 0x8b,
 121        [RES_32KCLKOUT] = 0x8e,
 122        [RES_RESET]     = 0x91,
 123        [RES_Main_Ref]  = 0x94,
 124};
 125
 126static int __init twl4030_write_script_byte(u8 address, u8 byte)
 127{
 128        int err;
 129
 130        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
 131                                R_MEMORY_ADDRESS);
 132        if (err)
 133                goto out;
 134        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte,
 135                                R_MEMORY_DATA);
 136out:
 137        return err;
 138}
 139
 140static int __init twl4030_write_script_ins(u8 address, u16 pmb_message,
 141                                           u8 delay, u8 next)
 142{
 143        int err;
 144
 145        address *= 4;
 146        err = twl4030_write_script_byte(address++, pmb_message >> 8);
 147        if (err)
 148                goto out;
 149        err = twl4030_write_script_byte(address++, pmb_message & 0xff);
 150        if (err)
 151                goto out;
 152        err = twl4030_write_script_byte(address++, delay);
 153        if (err)
 154                goto out;
 155        err = twl4030_write_script_byte(address++, next);
 156out:
 157        return err;
 158}
 159
 160static int __init twl4030_write_script(u8 address, struct twl4030_ins *script,
 161                                       int len)
 162{
 163        int err;
 164
 165        for (; len; len--, address++, script++) {
 166                if (len == 1) {
 167                        err = twl4030_write_script_ins(address,
 168                                                script->pmb_message,
 169                                                script->delay,
 170                                                END_OF_SCRIPT);
 171                        if (err)
 172                                break;
 173                } else {
 174                        err = twl4030_write_script_ins(address,
 175                                                script->pmb_message,
 176                                                script->delay,
 177                                                address + 1);
 178                        if (err)
 179                                break;
 180                }
 181        }
 182        return err;
 183}
 184
 185static int __init twl4030_config_wakeup3_sequence(u8 address)
 186{
 187        int err;
 188        u8 data;
 189
 190        /* Set SLEEP to ACTIVE SEQ address for P3 */
 191        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
 192                                R_SEQ_ADD_S2A3);
 193        if (err)
 194                goto out;
 195
 196        /* P3 LVL_WAKEUP should be on LEVEL */
 197        err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
 198                                R_P3_SW_EVENTS);
 199        if (err)
 200                goto out;
 201        data |= LVL_WAKEUP;
 202        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
 203                                R_P3_SW_EVENTS);
 204out:
 205        if (err)
 206                pr_err("TWL4030 wakeup sequence for P3 config error\n");
 207        return err;
 208}
 209
 210static int __init twl4030_config_wakeup12_sequence(u8 address)
 211{
 212        int err = 0;
 213        u8 data;
 214
 215        /* Set SLEEP to ACTIVE SEQ address for P1 and P2 */
 216        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
 217                                R_SEQ_ADD_S2A12);
 218        if (err)
 219                goto out;
 220
 221        /* P1/P2 LVL_WAKEUP should be on LEVEL */
 222        err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
 223                                R_P1_SW_EVENTS);
 224        if (err)
 225                goto out;
 226
 227        data |= LVL_WAKEUP;
 228        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
 229                                R_P1_SW_EVENTS);
 230        if (err)
 231                goto out;
 232
 233        err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
 234                                R_P2_SW_EVENTS);
 235        if (err)
 236                goto out;
 237
 238        data |= LVL_WAKEUP;
 239        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
 240                                R_P2_SW_EVENTS);
 241        if (err)
 242                goto out;
 243
 244        if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) {
 245                /* Disabling AC charger effect on sleep-active transitions */
 246                err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
 247                                        R_CFG_P1_TRANSITION);
 248                if (err)
 249                        goto out;
 250                data &= ~(1<<1);
 251                err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data ,
 252                                        R_CFG_P1_TRANSITION);
 253                if (err)
 254                        goto out;
 255        }
 256
 257out:
 258        if (err)
 259                pr_err("TWL4030 wakeup sequence for P1 and P2" \
 260                        "config error\n");
 261        return err;
 262}
 263
 264static int __init twl4030_config_sleep_sequence(u8 address)
 265{
 266        int err;
 267
 268        /* Set ACTIVE to SLEEP SEQ address in T2 memory*/
 269        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
 270                                R_SEQ_ADD_A2S);
 271
 272        if (err)
 273                pr_err("TWL4030 sleep sequence config error\n");
 274
 275        return err;
 276}
 277
 278static int __init twl4030_config_warmreset_sequence(u8 address)
 279{
 280        int err;
 281        u8 rd_data;
 282
 283        /* Set WARM RESET SEQ address for P1 */
 284        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
 285                                R_SEQ_ADD_WARM);
 286        if (err)
 287                goto out;
 288
 289        /* P1/P2/P3 enable WARMRESET */
 290        err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
 291                                R_P1_SW_EVENTS);
 292        if (err)
 293                goto out;
 294
 295        rd_data |= ENABLE_WARMRESET;
 296        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
 297                                R_P1_SW_EVENTS);
 298        if (err)
 299                goto out;
 300
 301        err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
 302                                R_P2_SW_EVENTS);
 303        if (err)
 304                goto out;
 305
 306        rd_data |= ENABLE_WARMRESET;
 307        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
 308                                R_P2_SW_EVENTS);
 309        if (err)
 310                goto out;
 311
 312        err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
 313                                R_P3_SW_EVENTS);
 314        if (err)
 315                goto out;
 316
 317        rd_data |= ENABLE_WARMRESET;
 318        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
 319                                R_P3_SW_EVENTS);
 320out:
 321        if (err)
 322                pr_err("TWL4030 warmreset seq config error\n");
 323        return err;
 324}
 325
 326static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
 327{
 328        int rconfig_addr;
 329        int err;
 330        u8 type;
 331        u8 grp;
 332        u8 remap;
 333
 334        if (rconfig->resource > TOTAL_RESOURCES) {
 335                pr_err("TWL4030 Resource %d does not exist\n",
 336                        rconfig->resource);
 337                return -EINVAL;
 338        }
 339
 340        rconfig_addr = res_config_addrs[rconfig->resource];
 341
 342        /* Set resource group */
 343        err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp,
 344                              rconfig_addr + DEV_GRP_OFFSET);
 345        if (err) {
 346                pr_err("TWL4030 Resource %d group could not be read\n",
 347                        rconfig->resource);
 348                return err;
 349        }
 350
 351        if (rconfig->devgroup != TWL4030_RESCONFIG_UNDEF) {
 352                grp &= ~DEV_GRP_MASK;
 353                grp |= rconfig->devgroup << DEV_GRP_SHIFT;
 354                err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
 355                                       grp, rconfig_addr + DEV_GRP_OFFSET);
 356                if (err < 0) {
 357                        pr_err("TWL4030 failed to program devgroup\n");
 358                        return err;
 359                }
 360        }
 361
 362        /* Set resource types */
 363        err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &type,
 364                                rconfig_addr + TYPE_OFFSET);
 365        if (err < 0) {
 366                pr_err("TWL4030 Resource %d type could not be read\n",
 367                        rconfig->resource);
 368                return err;
 369        }
 370
 371        if (rconfig->type != TWL4030_RESCONFIG_UNDEF) {
 372                type &= ~TYPE_MASK;
 373                type |= rconfig->type << TYPE_SHIFT;
 374        }
 375
 376        if (rconfig->type2 != TWL4030_RESCONFIG_UNDEF) {
 377                type &= ~TYPE2_MASK;
 378                type |= rconfig->type2 << TYPE2_SHIFT;
 379        }
 380
 381        err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
 382                                type, rconfig_addr + TYPE_OFFSET);
 383        if (err < 0) {
 384                pr_err("TWL4030 failed to program resource type\n");
 385                return err;
 386        }
 387
 388        /* Set remap states */
 389        err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &remap,
 390                              rconfig_addr + REMAP_OFFSET);
 391        if (err < 0) {
 392                pr_err("TWL4030 Resource %d remap could not be read\n",
 393                        rconfig->resource);
 394                return err;
 395        }
 396
 397        if (rconfig->remap_off != TWL4030_RESCONFIG_UNDEF) {
 398                remap &= ~OFF_STATE_MASK;
 399                remap |= rconfig->remap_off << OFF_STATE_SHIFT;
 400        }
 401
 402        if (rconfig->remap_sleep != TWL4030_RESCONFIG_UNDEF) {
 403                remap &= ~SLEEP_STATE_MASK;
 404                remap |= rconfig->remap_sleep << SLEEP_STATE_SHIFT;
 405        }
 406
 407        err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
 408                               remap,
 409                               rconfig_addr + REMAP_OFFSET);
 410        if (err < 0) {
 411                pr_err("TWL4030 failed to program remap\n");
 412                return err;
 413        }
 414
 415        return 0;
 416}
 417
 418static int __init load_twl4030_script(struct twl4030_script *tscript,
 419               u8 address)
 420{
 421        int err;
 422        static int order;
 423
 424        /* Make sure the script isn't going beyond last valid address (0x3f) */
 425        if ((address + tscript->size) > END_OF_SCRIPT) {
 426                pr_err("TWL4030 scripts too big error\n");
 427                return -EINVAL;
 428        }
 429
 430        err = twl4030_write_script(address, tscript->script, tscript->size);
 431        if (err)
 432                goto out;
 433
 434        if (tscript->flags & TWL4030_WRST_SCRIPT) {
 435                err = twl4030_config_warmreset_sequence(address);
 436                if (err)
 437                        goto out;
 438        }
 439        if (tscript->flags & TWL4030_WAKEUP12_SCRIPT) {
 440                err = twl4030_config_wakeup12_sequence(address);
 441                if (err)
 442                        goto out;
 443                order = 1;
 444        }
 445        if (tscript->flags & TWL4030_WAKEUP3_SCRIPT) {
 446                err = twl4030_config_wakeup3_sequence(address);
 447                if (err)
 448                        goto out;
 449        }
 450        if (tscript->flags & TWL4030_SLEEP_SCRIPT)
 451                if (order)
 452                        pr_warning("TWL4030: Bad order of scripts (sleep "\
 453                                        "script before wakeup) Leads to boot"\
 454                                        "failure on some boards\n");
 455                err = twl4030_config_sleep_sequence(address);
 456out:
 457        return err;
 458}
 459
 460int twl4030_remove_script(u8 flags)
 461{
 462        int err = 0;
 463
 464        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
 465                        TWL4030_PM_MASTER_KEY_CFG1,
 466                        TWL4030_PM_MASTER_PROTECT_KEY);
 467        if (err) {
 468                pr_err("twl4030: unable to unlock PROTECT_KEY\n");
 469                return err;
 470        }
 471
 472        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
 473                        TWL4030_PM_MASTER_KEY_CFG2,
 474                        TWL4030_PM_MASTER_PROTECT_KEY);
 475        if (err) {
 476                pr_err("twl4030: unable to unlock PROTECT_KEY\n");
 477                return err;
 478        }
 479
 480        if (flags & TWL4030_WRST_SCRIPT) {
 481                err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
 482                                R_SEQ_ADD_WARM);
 483                if (err)
 484                        return err;
 485        }
 486        if (flags & TWL4030_WAKEUP12_SCRIPT) {
 487                if (err)
 488                err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
 489                                R_SEQ_ADD_S2A12);
 490                        return err;
 491        }
 492        if (flags & TWL4030_WAKEUP3_SCRIPT) {
 493                err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
 494                                R_SEQ_ADD_S2A3);
 495                if (err)
 496                        return err;
 497        }
 498        if (flags & TWL4030_SLEEP_SCRIPT) {
 499                err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
 500                                R_SEQ_ADD_A2S);
 501                if (err)
 502                        return err;
 503        }
 504
 505        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0,
 506                        TWL4030_PM_MASTER_PROTECT_KEY);
 507        if (err)
 508                pr_err("TWL4030 Unable to relock registers\n");
 509
 510        return err;
 511}
 512
 513void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
 514{
 515        int err = 0;
 516        int i;
 517        struct twl4030_resconfig *resconfig;
 518        u8 address = twl4030_start_script_address;
 519
 520        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
 521                        TWL4030_PM_MASTER_KEY_CFG1,
 522                        TWL4030_PM_MASTER_PROTECT_KEY);
 523        if (err)
 524                goto unlock;
 525
 526        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
 527                        TWL4030_PM_MASTER_KEY_CFG2,
 528                        TWL4030_PM_MASTER_PROTECT_KEY);
 529        if (err)
 530                goto unlock;
 531
 532        for (i = 0; i < twl4030_scripts->num; i++) {
 533                err = load_twl4030_script(twl4030_scripts->scripts[i], address);
 534                if (err)
 535                        goto load;
 536                address += twl4030_scripts->scripts[i]->size;
 537        }
 538
 539        resconfig = twl4030_scripts->resource_config;
 540        if (resconfig) {
 541                while (resconfig->resource) {
 542                        err = twl4030_configure_resource(resconfig);
 543                        if (err)
 544                                goto resource;
 545                        resconfig++;
 546
 547                }
 548        }
 549
 550        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0,
 551                        TWL4030_PM_MASTER_PROTECT_KEY);
 552        if (err)
 553                pr_err("TWL4030 Unable to relock registers\n");
 554        return;
 555
 556unlock:
 557        if (err)
 558                pr_err("TWL4030 Unable to unlock registers\n");
 559        return;
 560load:
 561        if (err)
 562                pr_err("TWL4030 failed to load scripts\n");
 563        return;
 564resource:
 565        if (err)
 566                pr_err("TWL4030 failed to configure resource\n");
 567        return;
 568}
 569