linux/arch/arm/mach-omap2/i2c.c
<<
>>
Prefs
   1/*
   2 * Helper module for board specific I2C bus registration
   3 *
   4 * Copyright (C) 2009 Nokia Corporation.
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * version 2 as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 * General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  18 * 02110-1301 USA
  19 *
  20 */
  21
  22#include "soc.h"
  23#include "omap_hwmod.h"
  24#include "omap_device.h"
  25#include "omap-pm.h"
  26
  27#include "prm.h"
  28#include "common.h"
  29#include "mux.h"
  30#include "i2c.h"
  31
  32/* In register I2C_CON, Bit 15 is the I2C enable bit */
  33#define I2C_EN                                  BIT(15)
  34#define OMAP2_I2C_CON_OFFSET                    0x24
  35#define OMAP4_I2C_CON_OFFSET                    0xA4
  36
  37#define MAX_OMAP_I2C_HWMOD_NAME_LEN     16
  38
  39static void __init omap2_i2c_mux_pins(int bus_id)
  40{
  41        char mux_name[sizeof("i2c2_scl.i2c2_scl")];
  42
  43        /* First I2C bus is not muxable */
  44        if (bus_id == 1)
  45                return;
  46
  47        sprintf(mux_name, "i2c%i_scl.i2c%i_scl", bus_id, bus_id);
  48        omap_mux_init_signal(mux_name, OMAP_PIN_INPUT);
  49        sprintf(mux_name, "i2c%i_sda.i2c%i_sda", bus_id, bus_id);
  50        omap_mux_init_signal(mux_name, OMAP_PIN_INPUT);
  51}
  52
  53/**
  54 * omap_i2c_reset - reset the omap i2c module.
  55 * @oh: struct omap_hwmod *
  56 *
  57 * The i2c moudle in omap2, omap3 had a special sequence to reset. The
  58 * sequence is:
  59 * - Disable the I2C.
  60 * - Write to SOFTRESET bit.
  61 * - Enable the I2C.
  62 * - Poll on the RESETDONE bit.
  63 * The sequence is implemented in below function. This is called for 2420,
  64 * 2430 and omap3.
  65 */
  66int omap_i2c_reset(struct omap_hwmod *oh)
  67{
  68        u32 v;
  69        u16 i2c_con;
  70        int c = 0;
  71
  72        if (oh->class->rev == OMAP_I2C_IP_VERSION_2) {
  73                i2c_con = OMAP4_I2C_CON_OFFSET;
  74        } else if (oh->class->rev == OMAP_I2C_IP_VERSION_1) {
  75                i2c_con = OMAP2_I2C_CON_OFFSET;
  76        } else {
  77                WARN(1, "Cannot reset I2C block %s: unsupported revision\n",
  78                     oh->name);
  79                return -EINVAL;
  80        }
  81
  82        /* Disable I2C */
  83        v = omap_hwmod_read(oh, i2c_con);
  84        v &= ~I2C_EN;
  85        omap_hwmod_write(v, oh, i2c_con);
  86
  87        /* Write to the SOFTRESET bit */
  88        omap_hwmod_softreset(oh);
  89
  90        /* Enable I2C */
  91        v = omap_hwmod_read(oh, i2c_con);
  92        v |= I2C_EN;
  93        omap_hwmod_write(v, oh, i2c_con);
  94
  95        /* Poll on RESETDONE bit */
  96        omap_test_timeout((omap_hwmod_read(oh,
  97                                oh->class->sysc->syss_offs)
  98                                & SYSS_RESETDONE_MASK),
  99                                MAX_MODULE_SOFTRESET_WAIT, c);
 100
 101        if (c == MAX_MODULE_SOFTRESET_WAIT)
 102                pr_warn("%s: %s: softreset failed (waited %d usec)\n",
 103                        __func__, oh->name, MAX_MODULE_SOFTRESET_WAIT);
 104        else
 105                pr_debug("%s: %s: softreset in %d usec\n", __func__,
 106                        oh->name, c);
 107
 108        return 0;
 109}
 110
 111static int __init omap_i2c_nr_ports(void)
 112{
 113        int ports = 0;
 114
 115        if (cpu_is_omap24xx())
 116                ports = 2;
 117        else if (cpu_is_omap34xx())
 118                ports = 3;
 119        else if (cpu_is_omap44xx())
 120                ports = 4;
 121        return ports;
 122}
 123
 124/*
 125 * XXX This function is a temporary compatibility wrapper - only
 126 * needed until the I2C driver can be converted to call
 127 * omap_pm_set_max_dev_wakeup_lat() and handle a return code.
 128 */
 129static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t)
 130{
 131        omap_pm_set_max_mpu_wakeup_lat(dev, t);
 132}
 133
 134static const char name[] = "omap_i2c";
 135
 136int __init omap_i2c_add_bus(struct omap_i2c_bus_platform_data *i2c_pdata,
 137                                int bus_id)
 138{
 139        int l;
 140        struct omap_hwmod *oh;
 141        struct platform_device *pdev;
 142        char oh_name[MAX_OMAP_I2C_HWMOD_NAME_LEN];
 143        struct omap_i2c_bus_platform_data *pdata;
 144        struct omap_i2c_dev_attr *dev_attr;
 145
 146        if (bus_id > omap_i2c_nr_ports())
 147                return -EINVAL;
 148
 149        omap2_i2c_mux_pins(bus_id);
 150
 151        l = snprintf(oh_name, MAX_OMAP_I2C_HWMOD_NAME_LEN, "i2c%d", bus_id);
 152        WARN(l >= MAX_OMAP_I2C_HWMOD_NAME_LEN,
 153                "String buffer overflow in I2C%d device setup\n", bus_id);
 154        oh = omap_hwmod_lookup(oh_name);
 155        if (!oh) {
 156                        pr_err("Could not look up %s\n", oh_name);
 157                        return -EEXIST;
 158        }
 159
 160        pdata = i2c_pdata;
 161        /*
 162         * pass the hwmod class's CPU-specific knowledge of I2C IP revision in
 163         * use, and functionality implementation flags, up to the OMAP I2C
 164         * driver via platform data
 165         */
 166        pdata->rev = oh->class->rev;
 167
 168        dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr;
 169        pdata->flags = dev_attr->flags;
 170
 171        /*
 172         * When waiting for completion of a i2c transfer, we need to
 173         * set a wake up latency constraint for the MPU. This is to
 174         * ensure quick enough wakeup from idle, when transfer
 175         * completes.
 176         * Only omap3 has support for constraints
 177         */
 178        if (cpu_is_omap34xx())
 179                pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat;
 180        pdev = omap_device_build(name, bus_id, oh, pdata,
 181                                 sizeof(struct omap_i2c_bus_platform_data));
 182        WARN(IS_ERR(pdev), "Could not build omap_device for %s\n", name);
 183
 184        return PTR_ERR_OR_ZERO(pdev);
 185}
 186
 187static  int __init omap_i2c_cmdline(void)
 188{
 189        return omap_register_i2c_bus_cmdline();
 190}
 191omap_subsys_initcall(omap_i2c_cmdline);
 192