uboot/arch/arm/cpu/armv7/omap-common/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/*
  23 * Define Master code if there are multiple masters on the I2C_SR bus.
  24 * Normally not required
  25 */
  26#ifndef CONFIG_OMAP_VC_I2C_HS_MCODE
  27#define CONFIG_OMAP_VC_I2C_HS_MCODE 0x0
  28#endif
  29
  30/* Register defines and masks for VC IP Block */
  31/* PRM_VC_CFG_I2C_MODE */
  32#define PRM_VC_CFG_I2C_MODE_DFILTEREN_BIT       (0x1 << 6)
  33#define PRM_VC_CFG_I2C_MODE_SRMODEEN_BIT        (0x1 << 4)
  34#define PRM_VC_CFG_I2C_MODE_HSMODEEN_BIT        (0x1 << 3)
  35#define PRM_VC_CFG_I2C_MODE_HSMCODE_SHIFT       0x0
  36#define PRM_VC_CFG_I2C_MODE_HSMCODE_MASK        0x3
  37
  38/* PRM_VC_CFG_I2C_CLK */
  39#define PRM_VC_CFG_I2C_CLK_HSCLL_SHIFT          24
  40#define PRM_VC_CFG_I2C_CLK_HSCLL_MASK           0xFF
  41#define PRM_VC_CFG_I2C_CLK_HSCLH_SHIFT          16
  42#define PRM_VC_CFG_I2C_CLK_HSCLH_MASK           0xFF
  43#define PRM_VC_CFG_I2C_CLK_SCLH_SHIFT           0
  44#define PRM_VC_CFG_I2C_CLK_SCLH_MASK            0xFF
  45#define PRM_VC_CFG_I2C_CLK_SCLL_SHIFT           8
  46#define PRM_VC_CFG_I2C_CLK_SCLL_MASK            (0xFF << 8)
  47
  48/* PRM_VC_VAL_BYPASS */
  49#define PRM_VC_VAL_BYPASS_VALID_BIT             (0x1 << 24)
  50#define PRM_VC_VAL_BYPASS_SLAVEADDR_SHIFT       0
  51#define PRM_VC_VAL_BYPASS_SLAVEADDR_MASK        0x7F
  52#define PRM_VC_VAL_BYPASS_REGADDR_SHIFT         8
  53#define PRM_VC_VAL_BYPASS_REGADDR_MASK          0xFF
  54#define PRM_VC_VAL_BYPASS_DATA_SHIFT            16
  55#define PRM_VC_VAL_BYPASS_DATA_MASK             0xFF
  56
  57/**
  58 * omap_vc_init() - Initialization for Voltage controller
  59 * @speed_khz: I2C buspeed in KHz
  60 */
  61static void omap_vc_init(u16 speed_khz)
  62{
  63        u32 val;
  64        u32 sys_clk_khz, cycles_hi, cycles_low;
  65
  66        sys_clk_khz = get_sys_clk_freq() / 1000;
  67
  68        if (speed_khz > 400) {
  69                puts("higher speed requested - throttle to 400Khz\n");
  70                speed_khz = 400;
  71        }
  72
  73        /*
  74         * Setup the dedicated I2C controller for Voltage Control
  75         * I2C clk - high period 40% low period 60%
  76         */
  77        speed_khz /= 10;
  78        cycles_hi = sys_clk_khz * 4 / speed_khz;
  79        cycles_low = sys_clk_khz * 6 / speed_khz;
  80        /* values to be set in register - less by 5 & 7 respectively */
  81        cycles_hi -= 5;
  82        cycles_low -= 7;
  83        val = (cycles_hi << PRM_VC_CFG_I2C_CLK_SCLH_SHIFT) |
  84               (cycles_low << PRM_VC_CFG_I2C_CLK_SCLL_SHIFT);
  85        writel(val, (*prcm)->prm_vc_cfg_i2c_clk);
  86
  87        val = CONFIG_OMAP_VC_I2C_HS_MCODE <<
  88                PRM_VC_CFG_I2C_MODE_HSMCODE_SHIFT;
  89        /* No HS mode for now */
  90        val &= ~PRM_VC_CFG_I2C_MODE_HSMODEEN_BIT;
  91        writel(val, (*prcm)->prm_vc_cfg_i2c_mode);
  92}
  93
  94/**
  95 * omap_vc_bypass_send_value() - Send a data using VC Bypass command
  96 * @sa:         7 bit I2C slave address of the PMIC
  97 * @reg_addr:   I2C register address(8 bit) address in PMIC
  98 * @reg_data:   what 8 bit data to write
  99 */
 100int omap_vc_bypass_send_value(u8 sa, u8 reg_addr, u8 reg_data)
 101{
 102        /*
 103         * Unfortunately we need to loop here instead of a defined time
 104         * use arbitary large value
 105         */
 106        u32 timeout = 0xFFFF;
 107        u32 reg_val;
 108
 109        sa &= PRM_VC_VAL_BYPASS_SLAVEADDR_MASK;
 110        reg_addr &= PRM_VC_VAL_BYPASS_REGADDR_MASK;
 111        reg_data &= PRM_VC_VAL_BYPASS_DATA_MASK;
 112
 113        /* program VC to send data */
 114        reg_val = sa << PRM_VC_VAL_BYPASS_SLAVEADDR_SHIFT |
 115            reg_addr << PRM_VC_VAL_BYPASS_REGADDR_SHIFT |
 116            reg_data << PRM_VC_VAL_BYPASS_DATA_SHIFT;
 117        writel(reg_val, (*prcm)->prm_vc_val_bypass);
 118
 119        /* Signal VC to send data */
 120        writel(reg_val | PRM_VC_VAL_BYPASS_VALID_BIT,
 121                                (*prcm)->prm_vc_val_bypass);
 122
 123        /* Wait on VC to complete transmission */
 124        do {
 125                reg_val = readl((*prcm)->prm_vc_val_bypass) &
 126                                PRM_VC_VAL_BYPASS_VALID_BIT;
 127                if (!reg_val)
 128                        break;
 129
 130                sdelay(100);
 131        } while (--timeout);
 132
 133        /* Optional: cleanup PRM_IRQSTATUS_Ax */
 134        /* In case we can do something about it in future.. */
 135        if (!timeout)
 136                return -1;
 137
 138        /* All good.. */
 139        return 0;
 140}
 141
 142void sri2c_init(void)
 143{
 144        static int sri2c = 1;
 145
 146        if (sri2c) {
 147                omap_vc_init(PRM_VC_I2C_CHANNEL_FREQ_KHZ);
 148                sri2c = 0;
 149        }
 150        return;
 151}
 152