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