uboot/arch/arm/mach-omap2/vc.c
<<
>>
Prefs
   1/*
   2 * Voltage Controller implementation for OMAP
   3 *
   4 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
   5 *      Nishanth Menon
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  12 * kind, whether express or implied; without even the implied warranty
  13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 */
  16
  17#include <common.h>
  18#include <asm/omap_common.h>
  19#include <asm/arch/sys_proto.h>
  20#include <asm/arch/clock.h>
  21
  22/* Register defines and masks for VC IP Block */
  23/* PRM_VC_CFG_I2C_MODE */
  24#define PRM_VC_CFG_I2C_MODE_DFILTEREN_BIT       (0x1 << 6)
  25#define PRM_VC_CFG_I2C_MODE_SRMODEEN_BIT        (0x1 << 4)
  26#define PRM_VC_CFG_I2C_MODE_HSMODEEN_BIT        (0x1 << 3)
  27#define PRM_VC_CFG_I2C_MODE_HSMCODE_SHIFT       0x0
  28#define PRM_VC_CFG_I2C_MODE_HSMCODE_MASK        0x3
  29
  30/* PRM_VC_CFG_I2C_CLK */
  31#define PRM_VC_CFG_I2C_CLK_HSCLL_SHIFT          24
  32#define PRM_VC_CFG_I2C_CLK_HSCLL_MASK           0xFF
  33#define PRM_VC_CFG_I2C_CLK_HSCLH_SHIFT          16
  34#define PRM_VC_CFG_I2C_CLK_HSCLH_MASK           0xFF
  35#define PRM_VC_CFG_I2C_CLK_SCLH_SHIFT           0
  36#define PRM_VC_CFG_I2C_CLK_SCLH_MASK            0xFF
  37#define PRM_VC_CFG_I2C_CLK_SCLL_SHIFT           8
  38#define PRM_VC_CFG_I2C_CLK_SCLL_MASK            (0xFF << 8)
  39
  40/* PRM_VC_VAL_BYPASS */
  41#define PRM_VC_VAL_BYPASS_VALID_BIT             (0x1 << 24)
  42#define PRM_VC_VAL_BYPASS_SLAVEADDR_SHIFT       0
  43#define PRM_VC_VAL_BYPASS_SLAVEADDR_MASK        0x7F
  44#define PRM_VC_VAL_BYPASS_REGADDR_SHIFT         8
  45#define PRM_VC_VAL_BYPASS_REGADDR_MASK          0xFF
  46#define PRM_VC_VAL_BYPASS_DATA_SHIFT            16
  47#define PRM_VC_VAL_BYPASS_DATA_MASK             0xFF
  48
  49/**
  50 * omap_vc_init() - Initialization for Voltage controller
  51 * @speed_khz: I2C buspeed in KHz
  52 */
  53static void omap_vc_init(u16 speed_khz)
  54{
  55        u32 val;
  56        u32 sys_clk_khz, cycles_hi, cycles_low;
  57
  58        sys_clk_khz = get_sys_clk_freq() / 1000;
  59
  60        if (speed_khz > 400) {
  61                puts("higher speed requested - throttle to 400Khz\n");
  62                speed_khz = 400;
  63        }
  64
  65        /*
  66         * Setup the dedicated I2C controller for Voltage Control
  67         * I2C clk - high period 40% low period 60%
  68         */
  69        speed_khz /= 10;
  70        cycles_hi = sys_clk_khz * 4 / speed_khz;
  71        cycles_low = sys_clk_khz * 6 / speed_khz;
  72        /* values to be set in register - less by 5 & 7 respectively */
  73        cycles_hi -= 5;
  74        cycles_low -= 7;
  75        val = (cycles_hi << PRM_VC_CFG_I2C_CLK_SCLH_SHIFT) |
  76               (cycles_low << PRM_VC_CFG_I2C_CLK_SCLL_SHIFT);
  77        writel(val, (*prcm)->prm_vc_cfg_i2c_clk);
  78
  79        /*
  80         * Master code if there are multiple masters on the I2C_SR bus.
  81         */
  82        val = 0x0 << PRM_VC_CFG_I2C_MODE_HSMCODE_SHIFT;
  83        /* No HS mode for now */
  84        val &= ~PRM_VC_CFG_I2C_MODE_HSMODEEN_BIT;
  85        writel(val, (*prcm)->prm_vc_cfg_i2c_mode);
  86}
  87
  88/**
  89 * omap_vc_bypass_send_value() - Send a data using VC Bypass command
  90 * @sa:         7 bit I2C slave address of the PMIC
  91 * @reg_addr:   I2C register address(8 bit) address in PMIC
  92 * @reg_data:   what 8 bit data to write
  93 */
  94int omap_vc_bypass_send_value(u8 sa, u8 reg_addr, u8 reg_data)
  95{
  96        /*
  97         * Unfortunately we need to loop here instead of a defined time
  98         * use arbitary large value
  99         */
 100        u32 timeout = 0xFFFF;
 101        u32 reg_val;
 102
 103        sa &= PRM_VC_VAL_BYPASS_SLAVEADDR_MASK;
 104        reg_addr &= PRM_VC_VAL_BYPASS_REGADDR_MASK;
 105        reg_data &= PRM_VC_VAL_BYPASS_DATA_MASK;
 106
 107        /* program VC to send data */
 108        reg_val = sa << PRM_VC_VAL_BYPASS_SLAVEADDR_SHIFT |
 109            reg_addr << PRM_VC_VAL_BYPASS_REGADDR_SHIFT |
 110            reg_data << PRM_VC_VAL_BYPASS_DATA_SHIFT;
 111        writel(reg_val, (*prcm)->prm_vc_val_bypass);
 112
 113        /* Signal VC to send data */
 114        writel(reg_val | PRM_VC_VAL_BYPASS_VALID_BIT,
 115                                (*prcm)->prm_vc_val_bypass);
 116
 117        /* Wait on VC to complete transmission */
 118        do {
 119                reg_val = readl((*prcm)->prm_vc_val_bypass) &
 120                                PRM_VC_VAL_BYPASS_VALID_BIT;
 121                if (!reg_val)
 122                        break;
 123
 124                sdelay(100);
 125        } while (--timeout);
 126
 127        /* Optional: cleanup PRM_IRQSTATUS_Ax */
 128        /* In case we can do something about it in future.. */
 129        if (!timeout)
 130                return -1;
 131
 132        /* All good.. */
 133        return 0;
 134}
 135
 136void sri2c_init(void)
 137{
 138        static int sri2c = 1;
 139
 140        if (sri2c) {
 141                omap_vc_init(PRM_VC_I2C_CHANNEL_FREQ_KHZ);
 142                sri2c = 0;
 143        }
 144        return;
 145}
 146