1ce44bf5b5544cbe6358abb01f039361a99b80901David Brown/* Copyright (c) 2009-2013, The Linux Foundation. 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> 27ce44bf5b5544cbe6358abb01f039361a99b80901David Brown#include <linux/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 68bae911a055a3d88c8754e9c1879f29da6ba16663Stephen Boydenum ssbi_controller_type { 69bae911a055a3d88c8754e9c1879f29da6ba16663Stephen Boyd MSM_SBI_CTRL_SSBI = 0, 70bae911a055a3d88c8754e9c1879f29da6ba16663Stephen Boyd MSM_SBI_CTRL_SSBI2, 71bae911a055a3d88c8754e9c1879f29da6ba16663Stephen Boyd MSM_SBI_CTRL_PMIC_ARBITER, 72bae911a055a3d88c8754e9c1879f29da6ba16663Stephen Boyd}; 73bae911a055a3d88c8754e9c1879f29da6ba16663Stephen Boyd 74ce44bf5b5544cbe6358abb01f039361a99b80901David Brownstruct ssbi { 75e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke struct device *slave; 76e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke void __iomem *base; 77e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke spinlock_t lock; 78ce44bf5b5544cbe6358abb01f039361a99b80901David Brown enum ssbi_controller_type controller_type; 79ce44bf5b5544cbe6358abb01f039361a99b80901David Brown int (*read)(struct ssbi *, u16 addr, u8 *buf, int len); 805eec14ccf90942fecd89e147e0b88ab12dd83e70Stephen Boyd int (*write)(struct ssbi *, u16 addr, const u8 *buf, int len); 81e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke}; 82e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 83ce44bf5b5544cbe6358abb01f039361a99b80901David Brown#define to_ssbi(dev) platform_get_drvdata(to_platform_device(dev)) 84e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 85ce44bf5b5544cbe6358abb01f039361a99b80901David Brownstatic inline u32 ssbi_readl(struct ssbi *ssbi, u32 reg) 86e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 87e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return readl(ssbi->base + reg); 88e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 89e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 90ce44bf5b5544cbe6358abb01f039361a99b80901David Brownstatic inline void ssbi_writel(struct ssbi *ssbi, u32 val, u32 reg) 91e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 92e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke writel(val, ssbi->base + reg); 93e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 94e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 953f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown/* 963f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * Via private exchange with one of the original authors, the hardware 973f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * should generally finish a transaction in about 5us. The worst 983f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * case, is when using the arbiter and both other CPUs have just 993f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * started trying to use the SSBI bus will result in a time of about 1003f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * 20us. It should never take longer than this. 1013f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * 1023f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * As such, this wait merely spins, with a udelay. 1033f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown */ 104ce44bf5b5544cbe6358abb01f039361a99b80901David Brownstatic int ssbi_wait_mask(struct ssbi *ssbi, u32 set_mask, u32 clr_mask) 105e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 106e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 timeout = SSBI_TIMEOUT_US; 107e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 val; 108e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 109e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke while (timeout--) { 110e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke val = ssbi_readl(ssbi, SSBI2_STATUS); 111e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (((val & set_mask) == set_mask) && ((val & clr_mask) == 0)) 112e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return 0; 113e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke udelay(1); 114e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 115e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 116e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return -ETIMEDOUT; 117e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 118e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 119e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic int 120ce44bf5b5544cbe6358abb01f039361a99b80901David Brownssbi_read_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len) 121e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 122e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 cmd = SSBI_CMD_RDWRN | ((addr & 0xff) << 16); 123e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke int ret = 0; 124e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 125e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) { 126e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2); 127e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke mode2 = SET_SSBI_MODE2_REG_ADDR_15_8(mode2, addr); 128e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi_writel(ssbi, mode2, SSBI2_MODE2); 129e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 130e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 131e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke while (len) { 132e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0); 133e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ret) 134e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke goto err; 135e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 136e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi_writel(ssbi, cmd, SSBI2_CMD); 137e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ret = ssbi_wait_mask(ssbi, SSBI_STATUS_RD_READY, 0); 138e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ret) 139e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke goto err; 140e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke *buf++ = ssbi_readl(ssbi, SSBI2_RD) & 0xff; 141e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke len--; 142e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 143e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 144e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkeerr: 145e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return ret; 146e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 147e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 148e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic int 1495eec14ccf90942fecd89e147e0b88ab12dd83e70Stephen Boydssbi_write_bytes(struct ssbi *ssbi, u16 addr, const u8 *buf, int len) 150e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 151e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke int ret = 0; 152e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 153e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) { 154e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2); 155e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke mode2 = SET_SSBI_MODE2_REG_ADDR_15_8(mode2, addr); 156e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi_writel(ssbi, mode2, SSBI2_MODE2); 157e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 158e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 159e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke while (len) { 160e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0); 161e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ret) 162e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke goto err; 163e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 164e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi_writel(ssbi, ((addr & 0xff) << 16) | *buf, SSBI2_CMD); 165e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ret = ssbi_wait_mask(ssbi, 0, SSBI_STATUS_MCHN_BUSY); 166e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ret) 167e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke goto err; 168e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke buf++; 169e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke len--; 170e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 171e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 172e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkeerr: 173e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return ret; 174e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 175e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 1763f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown/* 1773f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * See ssbi_wait_mask for an explanation of the time and the 1783f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown * busywait. 1793f7a73b57c2f57aa25342ebdb7312f78c68502ebDavid Brown */ 180e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic inline int 181ce44bf5b5544cbe6358abb01f039361a99b80901David Brownssbi_pa_transfer(struct ssbi *ssbi, u32 cmd, u8 *data) 182e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 183e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 timeout = SSBI_TIMEOUT_US; 184e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 rd_status = 0; 185e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 186e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ssbi_writel(ssbi, cmd, SSBI_PA_CMD); 187e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 188e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke while (timeout--) { 189e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke rd_status = ssbi_readl(ssbi, SSBI_PA_RD_STATUS); 190e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 19137799ef4fa95ceec09b5c214fb281c6e6acddf5bDavid Brown if (rd_status & SSBI_PA_RD_STATUS_TRANS_DENIED) 192e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return -EPERM; 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 return -ETIMEDOUT; 203e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 204e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 205e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic int 206ce44bf5b5544cbe6358abb01f039361a99b80901David Brownssbi_pa_read_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len) 207e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 208e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 cmd; 209e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke int ret = 0; 210e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 211e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke cmd = SSBI_PA_CMD_RDWRN | (addr & SSBI_PA_CMD_ADDR_MASK) << 8; 212e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 213e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke while (len) { 214ce44bf5b5544cbe6358abb01f039361a99b80901David Brown ret = ssbi_pa_transfer(ssbi, cmd, buf); 215e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ret) 216e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke goto err; 217e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke buf++; 218e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke len--; 219e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 220e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 221e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkeerr: 222e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return ret; 223e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 224e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 225e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkestatic int 2265eec14ccf90942fecd89e147e0b88ab12dd83e70Stephen Boydssbi_pa_write_bytes(struct ssbi *ssbi, u16 addr, const u8 *buf, int len) 227e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 228e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke u32 cmd; 229e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke int ret = 0; 230e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 231e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke while (len) { 232e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke cmd = (addr & SSBI_PA_CMD_ADDR_MASK) << 8 | *buf; 233ce44bf5b5544cbe6358abb01f039361a99b80901David Brown ret = ssbi_pa_transfer(ssbi, cmd, NULL); 234e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ret) 235e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke goto err; 236e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke buf++; 237e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke len--; 238e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 239e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 240e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitkeerr: 241e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return ret; 242e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 243e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 244ce44bf5b5544cbe6358abb01f039361a99b80901David Brownint ssbi_read(struct device *dev, u16 addr, u8 *buf, int len) 245e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 246ce44bf5b5544cbe6358abb01f039361a99b80901David Brown struct ssbi *ssbi = to_ssbi(dev); 247e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke unsigned long flags; 248e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke int ret; 249e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 250e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke spin_lock_irqsave(&ssbi->lock, flags); 251e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ret = ssbi->read(ssbi, addr, buf, len); 252e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke spin_unlock_irqrestore(&ssbi->lock, flags); 253e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 254e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return ret; 255e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 256ce44bf5b5544cbe6358abb01f039361a99b80901David BrownEXPORT_SYMBOL_GPL(ssbi_read); 257e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 2585eec14ccf90942fecd89e147e0b88ab12dd83e70Stephen Boydint ssbi_write(struct device *dev, u16 addr, const u8 *buf, int len) 259e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 260ce44bf5b5544cbe6358abb01f039361a99b80901David Brown struct ssbi *ssbi = to_ssbi(dev); 261e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke unsigned long flags; 262e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke int ret; 263e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 264e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke spin_lock_irqsave(&ssbi->lock, flags); 265e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke ret = ssbi->write(ssbi, addr, buf, len); 266e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke spin_unlock_irqrestore(&ssbi->lock, flags); 267e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 268e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return ret; 269e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 270ce44bf5b5544cbe6358abb01f039361a99b80901David BrownEXPORT_SYMBOL_GPL(ssbi_write); 271e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 272ce44bf5b5544cbe6358abb01f039361a99b80901David Brownstatic int ssbi_probe(struct platform_device *pdev) 273e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke{ 27497f00f7120fe3396302693cdc4b1d11bbacad963David Brown struct device_node *np = pdev->dev.of_node; 275e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke struct resource *mem_res; 276ce44bf5b5544cbe6358abb01f039361a99b80901David Brown struct ssbi *ssbi; 27797f00f7120fe3396302693cdc4b1d11bbacad963David Brown const char *type; 278e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 279e578438820cdca91cb5eab477ec062236433ce5fStephen Boyd ssbi = devm_kzalloc(&pdev->dev, sizeof(*ssbi), GFP_KERNEL); 280e578438820cdca91cb5eab477ec062236433ce5fStephen Boyd if (!ssbi) 281e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke return -ENOMEM; 282e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 283e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 284e578438820cdca91cb5eab477ec062236433ce5fStephen Boyd ssbi->base = devm_ioremap_resource(&pdev->dev, mem_res); 285e578438820cdca91cb5eab477ec062236433ce5fStephen Boyd if (IS_ERR(ssbi->base)) 286e578438820cdca91cb5eab477ec062236433ce5fStephen Boyd return PTR_ERR(ssbi->base); 287e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 288e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke platform_set_drvdata(pdev, ssbi); 289e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 29097f00f7120fe3396302693cdc4b1d11bbacad963David Brown type = of_get_property(np, "qcom,controller-type", NULL); 29197f00f7120fe3396302693cdc4b1d11bbacad963David Brown if (type == NULL) { 292e578438820cdca91cb5eab477ec062236433ce5fStephen Boyd dev_err(&pdev->dev, "Missing qcom,controller-type property\n"); 293e578438820cdca91cb5eab477ec062236433ce5fStephen Boyd return -EINVAL; 29497f00f7120fe3396302693cdc4b1d11bbacad963David Brown } 29597f00f7120fe3396302693cdc4b1d11bbacad963David Brown dev_info(&pdev->dev, "SSBI controller type: '%s'\n", type); 29697f00f7120fe3396302693cdc4b1d11bbacad963David Brown if (strcmp(type, "ssbi") == 0) 29797f00f7120fe3396302693cdc4b1d11bbacad963David Brown ssbi->controller_type = MSM_SBI_CTRL_SSBI; 29897f00f7120fe3396302693cdc4b1d11bbacad963David Brown else if (strcmp(type, "ssbi2") == 0) 29997f00f7120fe3396302693cdc4b1d11bbacad963David Brown ssbi->controller_type = MSM_SBI_CTRL_SSBI2; 30097f00f7120fe3396302693cdc4b1d11bbacad963David Brown else if (strcmp(type, "pmic-arbiter") == 0) 30197f00f7120fe3396302693cdc4b1d11bbacad963David Brown ssbi->controller_type = MSM_SBI_CTRL_PMIC_ARBITER; 30297f00f7120fe3396302693cdc4b1d11bbacad963David Brown else { 303e578438820cdca91cb5eab477ec062236433ce5fStephen Boyd dev_err(&pdev->dev, "Unknown qcom,controller-type\n"); 304e578438820cdca91cb5eab477ec062236433ce5fStephen Boyd return -EINVAL; 30597f00f7120fe3396302693cdc4b1d11bbacad963David Brown } 30697f00f7120fe3396302693cdc4b1d11bbacad963David Brown 307e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke if (ssbi->controller_type == MSM_SBI_CTRL_PMIC_ARBITER) { 308ce44bf5b5544cbe6358abb01f039361a99b80901David Brown ssbi->read = ssbi_pa_read_bytes; 309ce44bf5b5544cbe6358abb01f039361a99b80901David Brown ssbi->write = ssbi_pa_write_bytes; 310e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } else { 311ce44bf5b5544cbe6358abb01f039361a99b80901David Brown ssbi->read = ssbi_read_bytes; 312ce44bf5b5544cbe6358abb01f039361a99b80901David Brown ssbi->write = ssbi_write_bytes; 313e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke } 314e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 315e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke spin_lock_init(&ssbi->lock); 316e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 317e578438820cdca91cb5eab477ec062236433ce5fStephen Boyd return of_platform_populate(np, NULL, NULL, &pdev->dev); 318e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke} 319e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 32012eda2a2e644d319dfc49bede1620c2f48ccbc8aStephen Boydstatic const struct of_device_id ssbi_match_table[] = { 32197f00f7120fe3396302693cdc4b1d11bbacad963David Brown { .compatible = "qcom,ssbi" }, 32297f00f7120fe3396302693cdc4b1d11bbacad963David Brown {} 32397f00f7120fe3396302693cdc4b1d11bbacad963David Brown}; 3246378c1e511d97218f33936f47888095023c9ffafStephen BoydMODULE_DEVICE_TABLE(of, ssbi_match_table); 32597f00f7120fe3396302693cdc4b1d11bbacad963David Brown 326ce44bf5b5544cbe6358abb01f039361a99b80901David Brownstatic struct platform_driver ssbi_driver = { 327ce44bf5b5544cbe6358abb01f039361a99b80901David Brown .probe = ssbi_probe, 328e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke .driver = { 329ce44bf5b5544cbe6358abb01f039361a99b80901David Brown .name = "ssbi", 330e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke .owner = THIS_MODULE, 33197f00f7120fe3396302693cdc4b1d11bbacad963David Brown .of_match_table = ssbi_match_table, 332e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke }, 333e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke}; 334e578438820cdca91cb5eab477ec062236433ce5fStephen Boydmodule_platform_driver(ssbi_driver); 335e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth Heitke 336e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth HeitkeMODULE_LICENSE("GPL v2"); 337e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth HeitkeMODULE_VERSION("1.0"); 338ce44bf5b5544cbe6358abb01f039361a99b80901David BrownMODULE_ALIAS("platform:ssbi"); 339e44b0ceee4cc2a926225e73ac1e20b9a5bb22c2dKenneth HeitkeMODULE_AUTHOR("Dima Zavin <dima@android.com>"); 340