ssbi.c revision 3f7a73b57c2f57aa25342ebdb7312f78c68502eb
1e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. 2e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke * Copyright (c) 2010, Google Inc. 3e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke * 4e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke * Original authors: Code Aurora Forum 5e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke * 6e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke * Author: Dima Zavin <dima@android.com> 7e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke * - Largely rewritten from original to not be an i2c driver. 8e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke * 9e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke * This program is free software; you can redistribute it and/or modify 10e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke * it under the terms of the GNU General Public License version 2 and 11e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke * only version 2 as published by the Free Software Foundation. 12e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke * 13e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke * This program is distributed in the hope that it will be useful, 14e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke * but WITHOUT ANY WARRANTY; without even the implied warranty of 15e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke * GNU General Public License for more details. 17e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke */ 18e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 19e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define pr_fmt(fmt) "%s: " fmt, __func__ 20e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 21e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#include <linux/delay.h> 22e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#include <linux/err.h> 23e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#include <linux/io.h> 24e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#include <linux/kernel.h> 25e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#include <linux/platform_device.h> 26e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#include <linux/slab.h> 27e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#include <linux/msm_ssbi.h> 28e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#include <linux/module.h> 2997f00f7120fe3396302693cdc4b1d11bbacad963David Brown#include <linux/of.h> 3097f00f7120fe3396302693cdc4b1d11bbacad963David Brown#include <linux/of_device.h> 31e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 32e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke/* SSBI 2.0 controller registers */ 33e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI2_CMD 0x0008 34e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI2_RD 0x0010 35e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI2_STATUS 0x0014 36e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI2_MODE2 0x001C 37e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 38e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke/* SSBI_CMD fields */ 39e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI_CMD_RDWRN (1 << 24) 40e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 41e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke/* SSBI_STATUS fields */ 42e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI_STATUS_RD_READY (1 << 2) 43e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI_STATUS_READY (1 << 1) 44e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI_STATUS_MCHN_BUSY (1 << 0) 45e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 46e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke/* SSBI_MODE2 fields */ 47e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI_MODE2_REG_ADDR_15_8_SHFT 0x04 48e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI_MODE2_REG_ADDR_15_8_MASK (0x7f << SSBI_MODE2_REG_ADDR_15_8_SHFT) 49e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 50e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SET_SSBI_MODE2_REG_ADDR_15_8(MD, AD) \ 51e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke (((MD) & 0x0F) | ((((AD) >> 8) << SSBI_MODE2_REG_ADDR_15_8_SHFT) & \ 52e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke SSBI_MODE2_REG_ADDR_15_8_MASK)) 53e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 54e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke/* SSBI PMIC Arbiter command registers */ 55e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI_PA_CMD 0x0000 56e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI_PA_RD_STATUS 0x0004 57e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 58e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke/* SSBI_PA_CMD fields */ 59e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI_PA_CMD_RDWRN (1 << 24) 60e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI_PA_CMD_ADDR_MASK 0x7fff /* REG_ADDR_7_0, REG_ADDR_8_14*/ 61e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 62e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke/* SSBI_PA_RD_STATUS fields */ 63e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI_PA_RD_STATUS_TRANS_DONE (1 << 27) 64e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI_PA_RD_STATUS_TRANS_DENIED (1 << 26) 65e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 66e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define SSBI_TIMEOUT_US 100 67e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 68e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestruct msm_ssbi { 69e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke struct device *dev; 70e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke struct device *slave; 71e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke void __iomem *base; 72e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke spinlock_t lock; 73e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke enum msm_ssbi_controller_type controller_type; 74e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke int (*read)(struct msm_ssbi *, u16 addr, u8 *buf, int len); 75e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke int (*write)(struct msm_ssbi *, u16 addr, u8 *buf, int len); 76e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke}; 77e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 78e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke#define to_msm_ssbi(dev) platform_get_drvdata(to_platform_device(dev)) 79e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 80e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic inline u32 ssbi_readl(struct msm_ssbi *ssbi, u32 reg) 81e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 82e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return readl(ssbi->base + reg); 83e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 84e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 85e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic inline void ssbi_writel(struct msm_ssbi *ssbi, u32 val, u32 reg) 86e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 87e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke writel(val, ssbi->base + reg); 88e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 89e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 903f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown/* 913f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * Via private exchange with one of the original authors, the hardware 923f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * should generally finish a transaction in about 5us. The worst 933f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * case, is when using the arbiter and both other CPUs have just 943f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * started trying to use the SSBI bus will result in a time of about 953f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * 20us. It should never take longer than this. 963f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * 973f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * As such, this wait merely spins, with a udelay. 983f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown */ 99e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic int ssbi_wait_mask(struct msm_ssbi *ssbi, u32 set_mask, u32 clr_mask) 100e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 101e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 timeout = SSBI_TIMEOUT_US; 102e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 val; 103e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 104e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke while (timeout--) { 105e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke val = ssbi_readl(ssbi, SSBI2_STATUS); 106e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (((val & set_mask) == set_mask) && ((val & clr_mask) == 0)) 107e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return 0; 108e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke udelay(1); 109e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 110e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 111e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke dev_err(ssbi->dev, "%s: timeout (status %x set_mask %x clr_mask %x)\n", 112e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke __func__, ssbi_readl(ssbi, SSBI2_STATUS), set_mask, clr_mask); 113e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return -ETIMEDOUT; 114e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 115e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 116e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic int 117e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkemsm_ssbi_read_bytes(struct msm_ssbi *ssbi, u16 addr, u8 *buf, int len) 118e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 119e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 cmd = SSBI_CMD_RDWRN | ((addr & 0xff) << 16); 120e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke int ret = 0; 121e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 122e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) { 123e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2); 124e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke mode2 = SET_SSBI_MODE2_REG_ADDR_15_8(mode2, addr); 125e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi_writel(ssbi, mode2, SSBI2_MODE2); 126e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 127e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 128e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke while (len) { 129e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0); 130e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ret) 131e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke goto err; 132e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 133e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi_writel(ssbi, cmd, SSBI2_CMD); 134e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ret = ssbi_wait_mask(ssbi, SSBI_STATUS_RD_READY, 0); 135e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ret) 136e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke goto err; 137e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke *buf++ = ssbi_readl(ssbi, SSBI2_RD) & 0xff; 138e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke len--; 139e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 140e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 141e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkeerr: 142e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return ret; 143e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 144e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 145e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic int 146e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkemsm_ssbi_write_bytes(struct msm_ssbi *ssbi, u16 addr, u8 *buf, int len) 147e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 148e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke int ret = 0; 149e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 150e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) { 151e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2); 152e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke mode2 = SET_SSBI_MODE2_REG_ADDR_15_8(mode2, addr); 153e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi_writel(ssbi, mode2, SSBI2_MODE2); 154e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 155e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 156e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke while (len) { 157e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0); 158e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ret) 159e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke goto err; 160e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 161e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi_writel(ssbi, ((addr & 0xff) << 16) | *buf, SSBI2_CMD); 162e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ret = ssbi_wait_mask(ssbi, 0, SSBI_STATUS_MCHN_BUSY); 163e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ret) 164e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke goto err; 165e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke buf++; 166e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke len--; 167e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 168e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 169e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkeerr: 170e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return ret; 171e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 172e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 1733f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown/* 1743f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * See ssbi_wait_mask for an explanation of the time and the 1753f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * busywait. 1763f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown */ 177e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic inline int 178e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkemsm_ssbi_pa_transfer(struct msm_ssbi *ssbi, u32 cmd, u8 *data) 179e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 180e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 timeout = SSBI_TIMEOUT_US; 181e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 rd_status = 0; 182e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 183e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi_writel(ssbi, cmd, SSBI_PA_CMD); 184e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 185e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke while (timeout--) { 186e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke rd_status = ssbi_readl(ssbi, SSBI_PA_RD_STATUS); 187e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 188e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (rd_status & SSBI_PA_RD_STATUS_TRANS_DENIED) { 189e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke dev_err(ssbi->dev, "%s: transaction denied (0x%x)\n", 190e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke __func__, rd_status); 191e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return -EPERM; 192e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 193e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 194e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (rd_status & SSBI_PA_RD_STATUS_TRANS_DONE) { 195e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (data) 196e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke *data = rd_status & 0xff; 197e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return 0; 198e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 199e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke udelay(1); 200e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 201e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 202e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke dev_err(ssbi->dev, "%s: timeout, status 0x%x\n", __func__, rd_status); 203e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return -ETIMEDOUT; 204e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 205e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 206e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic int 207e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkemsm_ssbi_pa_read_bytes(struct msm_ssbi *ssbi, u16 addr, u8 *buf, int len) 208e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 209e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 cmd; 210e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke int ret = 0; 211e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 212e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke cmd = SSBI_PA_CMD_RDWRN | (addr & SSBI_PA_CMD_ADDR_MASK) << 8; 213e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 214e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke while (len) { 215e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ret = msm_ssbi_pa_transfer(ssbi, cmd, buf); 216e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ret) 217e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke goto err; 218e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke buf++; 219e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke len--; 220e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 221e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 222e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkeerr: 223e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return ret; 224e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 225e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 226e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic int 227e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkemsm_ssbi_pa_write_bytes(struct msm_ssbi *ssbi, u16 addr, u8 *buf, int len) 228e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 229e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 cmd; 230e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke int ret = 0; 231e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 232e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke while (len) { 233e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke cmd = (addr & SSBI_PA_CMD_ADDR_MASK) << 8 | *buf; 234e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ret = msm_ssbi_pa_transfer(ssbi, cmd, NULL); 235e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ret) 236e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke goto err; 237e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke buf++; 238e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke len--; 239e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 240e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 241e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkeerr: 242e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return ret; 243e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 244e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 245e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkeint msm_ssbi_read(struct device *dev, u16 addr, u8 *buf, int len) 246e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 247e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke struct msm_ssbi *ssbi = to_msm_ssbi(dev); 248e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke unsigned long flags; 249e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke int ret; 250e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 251e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ssbi->dev != dev) 252e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return -ENXIO; 253e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 254e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke spin_lock_irqsave(&ssbi->lock, flags); 255e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ret = ssbi->read(ssbi, addr, buf, len); 256e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke spin_unlock_irqrestore(&ssbi->lock, flags); 257e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 258e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return ret; 259e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 260a1a906c5721f05252e0dbd4b11ef25539d7bd9d0David BrownEXPORT_SYMBOL_GPL(msm_ssbi_read); 261e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 262e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkeint msm_ssbi_write(struct device *dev, u16 addr, u8 *buf, int len) 263e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 264e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke struct msm_ssbi *ssbi = to_msm_ssbi(dev); 265e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke unsigned long flags; 266e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke int ret; 267e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 268e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ssbi->dev != dev) 269e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return -ENXIO; 270e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 271e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke spin_lock_irqsave(&ssbi->lock, flags); 272e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ret = ssbi->write(ssbi, addr, buf, len); 273e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke spin_unlock_irqrestore(&ssbi->lock, flags); 274e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 275e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return ret; 276e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 277a1a906c5721f05252e0dbd4b11ef25539d7bd9d0David BrownEXPORT_SYMBOL_GPL(msm_ssbi_write); 278e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 279e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic int msm_ssbi_probe(struct platform_device *pdev) 280e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 28197f00f7120fe3396302693cdc4b1d11bbacad963David Brown struct device_node *np = pdev->dev.of_node; 282e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke struct resource *mem_res; 283e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke struct msm_ssbi *ssbi; 284e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke int ret = 0; 28597f00f7120fe3396302693cdc4b1d11bbacad963David Brown const char *type; 286e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 287e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi = kzalloc(sizeof(struct msm_ssbi), GFP_KERNEL); 288e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (!ssbi) { 289e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke pr_err("can not allocate ssbi_data\n"); 290e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return -ENOMEM; 291e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 292e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 293e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 294e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (!mem_res) { 295e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke pr_err("missing mem resource\n"); 296e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ret = -EINVAL; 297e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke goto err_get_mem_res; 298e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 299e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 300e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi->base = ioremap(mem_res->start, resource_size(mem_res)); 301e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (!ssbi->base) { 302e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke pr_err("ioremap of 0x%p failed\n", (void *)mem_res->start); 303e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ret = -EINVAL; 304e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke goto err_ioremap; 305e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 306e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi->dev = &pdev->dev; 307e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke platform_set_drvdata(pdev, ssbi); 308e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 30997f00f7120fe3396302693cdc4b1d11bbacad963David Brown type = of_get_property(np, "qcom,controller-type", NULL); 31097f00f7120fe3396302693cdc4b1d11bbacad963David Brown if (type == NULL) { 31197f00f7120fe3396302693cdc4b1d11bbacad963David Brown pr_err("Missing qcom,controller-type property\n"); 31297f00f7120fe3396302693cdc4b1d11bbacad963David Brown ret = -EINVAL; 31397f00f7120fe3396302693cdc4b1d11bbacad963David Brown goto err_ssbi_controller; 31497f00f7120fe3396302693cdc4b1d11bbacad963David Brown } 31597f00f7120fe3396302693cdc4b1d11bbacad963David Brown dev_info(&pdev->dev, "SSBI controller type: '%s'\n", type); 31697f00f7120fe3396302693cdc4b1d11bbacad963David Brown if (strcmp(type, "ssbi") == 0) 31797f00f7120fe3396302693cdc4b1d11bbacad963David Brown ssbi->controller_type = MSM_SBI_CTRL_SSBI; 31897f00f7120fe3396302693cdc4b1d11bbacad963David Brown else if (strcmp(type, "ssbi2") == 0) 31997f00f7120fe3396302693cdc4b1d11bbacad963David Brown ssbi->controller_type = MSM_SBI_CTRL_SSBI2; 32097f00f7120fe3396302693cdc4b1d11bbacad963David Brown else if (strcmp(type, "pmic-arbiter") == 0) 32197f00f7120fe3396302693cdc4b1d11bbacad963David Brown ssbi->controller_type = MSM_SBI_CTRL_PMIC_ARBITER; 32297f00f7120fe3396302693cdc4b1d11bbacad963David Brown else { 32397f00f7120fe3396302693cdc4b1d11bbacad963David Brown pr_err("Unknown qcom,controller-type\n"); 32497f00f7120fe3396302693cdc4b1d11bbacad963David Brown ret = -EINVAL; 32597f00f7120fe3396302693cdc4b1d11bbacad963David Brown goto err_ssbi_controller; 32697f00f7120fe3396302693cdc4b1d11bbacad963David Brown } 32797f00f7120fe3396302693cdc4b1d11bbacad963David Brown 328e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ssbi->controller_type == MSM_SBI_CTRL_PMIC_ARBITER) { 329e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi->read = msm_ssbi_pa_read_bytes; 330e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi->write = msm_ssbi_pa_write_bytes; 331e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } else { 332e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi->read = msm_ssbi_read_bytes; 333e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi->write = msm_ssbi_write_bytes; 334e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 335e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 336e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke spin_lock_init(&ssbi->lock); 337e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 33897f00f7120fe3396302693cdc4b1d11bbacad963David Brown ret = of_platform_populate(np, NULL, NULL, &pdev->dev); 339e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ret) 34097f00f7120fe3396302693cdc4b1d11bbacad963David Brown goto err_ssbi_controller; 341e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 342e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return 0; 343e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 34497f00f7120fe3396302693cdc4b1d11bbacad963David Brownerr_ssbi_controller: 345e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke platform_set_drvdata(pdev, NULL); 346e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke iounmap(ssbi->base); 347e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkeerr_ioremap: 348e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkeerr_get_mem_res: 349e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke kfree(ssbi); 350e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return ret; 351e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 352e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 353e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic int msm_ssbi_remove(struct platform_device *pdev) 354e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 355e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke struct msm_ssbi *ssbi = platform_get_drvdata(pdev); 356e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 357e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke platform_set_drvdata(pdev, NULL); 358e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke iounmap(ssbi->base); 359e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke kfree(ssbi); 360e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return 0; 361e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 362e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 36397f00f7120fe3396302693cdc4b1d11bbacad963David Brownstatic struct of_device_id ssbi_match_table[] = { 36497f00f7120fe3396302693cdc4b1d11bbacad963David Brown { .compatible = "qcom,ssbi" }, 36597f00f7120fe3396302693cdc4b1d11bbacad963David Brown {} 36697f00f7120fe3396302693cdc4b1d11bbacad963David Brown}; 36797f00f7120fe3396302693cdc4b1d11bbacad963David Brown 368e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic struct platform_driver msm_ssbi_driver = { 369e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke .probe = msm_ssbi_probe, 3707b67d5610879c8f1851a47fd5adfe7e924f3fe53David Brown .remove = msm_ssbi_remove, 371e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke .driver = { 372e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke .name = "msm_ssbi", 373e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke .owner = THIS_MODULE, 37497f00f7120fe3396302693cdc4b1d11bbacad963David Brown .of_match_table = ssbi_match_table, 375e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke }, 376e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke}; 377e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 378e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic int __init msm_ssbi_init(void) 379e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 380e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return platform_driver_register(&msm_ssbi_driver); 381e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 382e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkepostcore_initcall(msm_ssbi_init); 383e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 384e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic void __exit msm_ssbi_exit(void) 385e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 386e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke platform_driver_unregister(&msm_ssbi_driver); 387e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 388e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkemodule_exit(msm_ssbi_exit) 389e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 390e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth HeitkeMODULE_LICENSE("GPL v2"); 391e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth HeitkeMODULE_VERSION("1.0"); 392e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth HeitkeMODULE_ALIAS("platform:msm_ssbi"); 393e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth HeitkeMODULE_AUTHOR("Dima Zavin <dima@android.com>"); 394