lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <4C9D2AD2.4030102@codeaurora.org>
Date:	Fri, 24 Sep 2010 16:48:50 -0600
From:	Kenneth Heitke <kheitke@...eaurora.org>
To:	Ben Dooks <ben-linux@...ff.org>, khali@...ux-fr.org,
	linux-i2c@...r.kernel.org
CC:	linux-arm-msm@...r.kernel.org,
	Samuel Ortiz <sameo@...ux.intel.com>,
	Linus Walleij <linus.walleij@...ricsson.com>,
	Ralf Baechle <ralf@...ux-mips.org>,
	srinidhi kasagar <srinidhi.kasagar@...ricsson.com>,
	linux-kernel@...r.kernel.org
Subject: Re: [PATCH] i2c: Single-wire Serial Bus Interface for Qualcomm MSM
 chipsets

Ben,

Can you comment on whether or not you would be willing to accept this 
driver as part of the I2C subsystem.  I have an updated patch that I'm 
ready to submit if you are willing to consider this driver.

thank you,
Ken

On 07/21/2010 11:52 AM, Kenneth Heitke wrote:
> This bus driver supports the Single-wire Serial Bus Interface (SSBI)
> controller in the Qualcomm MSM SOCs.  SSBI is not an I2C but is
> functionally related enough such that it is able to leverage the I2C
> framework.
>
> Unlike I2C, SSBI is a point-to-point connection, and therefore there is no
> need to specify a slave device address. The SSBI implementation
> overrides the slave device address to be a device register address
> instead.  This restricts the client drivers from using the SMBus
> communication APIs unless they update the address field (addr) of the
> i2c_client structure prior to every SMBus function call.  Instead it is
> recommended to use the i2c_transfer function where the address is
> specified as part of the i2c_msg structure.  The i2c_transfer function
> also provides more flexibility for performing multiple transactions in a
> single function call.
>
> Signed-off-by: Kenneth Heitke<kheitke@...eaurora.org>
> ---
>   drivers/i2c/busses/Kconfig    |   10 +
>   drivers/i2c/busses/Makefile   |    1 +
>   drivers/i2c/busses/i2c-ssbi.c |  472 +++++++++++++++++++++++++++++++++++++++++
>   include/linux/i2c-ssbi.h      |   33 +++
>   4 files changed, 516 insertions(+), 0 deletions(-)
>   create mode 100644 drivers/i2c/busses/i2c-ssbi.c
>   create mode 100755 include/linux/i2c-ssbi.h
>
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index bceafbf..690d601 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -569,6 +569,16 @@ config I2C_SIMTEC
>   	  This driver can also be built as a module. If so, the module
>   	  will be called i2c-simtec.
>
> +config I2C_SSBI
> +	tristate "Qualcomm Single-wire Serial Bus Interface (SSBI)"
> +	depends on I2C&&  (ARCH_MSM7X30 || ARCH_MSM8X60)
> +	help
> +	  If you say yes to this option, support will be included for the
> +	  built-in SSBI interface on Qualcomm MSM family processors.
> +
> +          Note that SSBI is not an I2C bus, but is functionally related
> +          enough such that it is able to leverages the I2C framework.
> +
>   config I2C_STU300
>   	tristate "ST Microelectronics DDC I2C interface"
>   	depends on MACH_U300
> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> index 936880b..79a7ad9 100644
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -55,6 +55,7 @@ obj-$(CONFIG_I2C_S6000)		+= i2c-s6000.o
>   obj-$(CONFIG_I2C_SH7760)	+= i2c-sh7760.o
>   obj-$(CONFIG_I2C_SH_MOBILE)	+= i2c-sh_mobile.o
>   obj-$(CONFIG_I2C_SIMTEC)	+= i2c-simtec.o
> +obj-$(CONFIG_I2C_SSBI)          += i2c-ssbi.o
>   obj-$(CONFIG_I2C_STU300)	+= i2c-stu300.o
>   obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
>   obj-$(CONFIG_I2C_OCTEON)	+= i2c-octeon.o
> diff --git a/drivers/i2c/busses/i2c-ssbi.c b/drivers/i2c/busses/i2c-ssbi.c
> new file mode 100644
> index 0000000..1763ea5
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-ssbi.c
> @@ -0,0 +1,472 @@
> +/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> + * 02110-1301, USA.
> + *
> + */
> +/*
> + * SSBI driver for Qualcomm MSM platforms
> + *
> + */
> +#include<linux/kernel.h>
> +#include<linux/platform_device.h>
> +#include<linux/err.h>
> +#include<linux/slab.h>
> +#include<linux/delay.h>
> +#include<linux/io.h>
> +#include<linux/i2c.h>
> +#include<linux/i2c-ssbi.h>
> +
> +/* SSBI 2.0 controller registers */
> +#define SSBI2_CMD			0x0008
> +#define SSBI2_RD			0x0010
> +#define SSBI2_STATUS			0x0014
> +#define SSBI2_MODE2			0x001C
> +
> +/* SSBI_CMD fields */
> +#define SSBI_CMD_RDWRN			(0x01<<  24)
> +#define SSBI_CMD_REG_ADDR_SHFT		(0x10)
> +#define SSBI_CMD_REG_ADDR_MASK		(0xFF<<  SSBI_CMD_REG_ADDR_SHFT)
> +#define SSBI_CMD_REG_DATA_SHFT		(0x00)
> +#define SSBI_CMD_REG_DATA_MASK		(0xFF<<  SSBI_CMD_REG_DATA_SHFT)
> +
> +/* SSBI_STATUS fields */
> +#define SSBI_STATUS_DATA_IN		0x10
> +#define SSBI_STATUS_RD_CLOBBERED	0x08
> +#define SSBI_STATUS_RD_READY		0x04
> +#define SSBI_STATUS_READY		0x02
> +#define SSBI_STATUS_MCHN_BUSY		0x01
> +
> +/* SSBI_RD fields */
> +#define SSBI_RD_RDWRN			0x01000000
> +#define SSBI_RD_REG_ADDR_SHFT		0x10
> +#define SSBI_RD_REG_ADDR_MASK		(0xFF<<  SSBI_RD_REG_ADDR_SHFT)
> +#define SSBI_RD_REG_DATA_SHFT		(0x00)
> +#define SSBI_RD_REG_DATA_MASK		(0xFF<<  SSBI_RD_REG_DATA_SHFT)
> +
> +/* SSBI_MODE2 fields */
> +#define SSBI_MODE2_REG_ADDR_15_8_SHFT	0x04
> +#define SSBI_MODE2_REG_ADDR_15_8_MASK	(0x7F<<  SSBI_MODE2_REG_ADDR_15_8_SHFT)
> +#define SSBI_MODE2_ADDR_WIDTH_SHFT	0x01
> +#define SSBI_MODE2_ADDR_WIDTH_MASK	(0x07<<  SSBI_MODE2_ADDR_WIDTH_SHFT)
> +#define SSBI_MODE2_SSBI2_MODE		0x00000001
> +
> +#define SSBI_MODE2_REG_ADDR_15_8(MD, AD) \
> +	(((MD)&  0x0F) | ((((AD)>>  8)<<  SSBI_MODE2_REG_ADDR_15_8_SHFT)&  \
> +	SSBI_MODE2_REG_ADDR_15_8_MASK))
> +
> +#define SSBI_MODE2_ADDR_WIDTH(N) \
> +	((((N) - 8)<<  SSBI_MODE2_ADDR_WIDTH_SHFT)&  SSBI_MODE2_ADDR_WIDTH_MASK)
> +
> +#define SSBI_TIMEOUT_US			100
> +
> +#define SSBI_CMD_READ(AD) \
> +	(SSBI_CMD_RDWRN | (((AD)&  0xFF)<<  SSBI_CMD_REG_ADDR_SHFT))
> +
> +#define SSBI_CMD_WRITE(AD, DT) \
> +	((((AD)&  0xFF)<<  SSBI_CMD_REG_ADDR_SHFT) | \
> +	 (((DT)&  0xFF)<<  SSBI_CMD_REG_DATA_SHFT))
> +
> +/* SSBI PMIC Arbiter command registers */
> +#define SSBI_PA_CMD			0x0000
> +#define SSBI_PA_RD_STATUS		0x0004
> +
> +/* SSBI_PA_CMD fields */
> +#define SSBI_PA_CMD_RDWRN		(0x01<<  24)
> +#define SSBI_PA_CMD_REG_ADDR_14_8_SHFT	(0x10)
> +#define SSBI_PA_CMD_REG_ADDR_14_8_MASK	(0x7F<<  SSBI_PA_CMD_REG_ADDR_14_8_SHFT)
> +#define SSBI_PA_CMD_REG_ADDR_7_0_SHFT	(0x08)
> +#define SSBI_PA_CMD_REG_ADDR_7_0_MASK	(0xFF<<  SSBI_PA_CMD_REG_ADDR_7_0_SHFT)
> +#define SSBI_PA_CMD_REG_DATA_SHFT	(0x00)
> +#define SSBI_PA_CMD_REG_DATA_MASK	(0xFF<<  SSBI_PA_CMD_REG_DATA_SHFT)
> +
> +#define SSBI_PA_CMD_REG_DATA(DT) \
> +	(((DT)<<  SSBI_PA_CMD_REG_DATA_SHFT)&  SSBI_PA_CMD_REG_DATA_MASK)
> +
> +#define SSBI_PA_CMD_REG_ADDR(AD) \
> +	(((AD)<<  SSBI_PA_CMD_REG_ADDR_7_0_SHFT)&  \
> +	(SSBI_PA_CMD_REG_ADDR_14_8_MASK|SSBI_PA_CMD_REG_ADDR_7_0_MASK))
> +
> +/* SSBI_PA_RD_STATUS fields */
> +#define SSBI_PA_RD_STATUS_TRANS_DONE	(0x01<<  27)
> +#define SSBI_PA_RD_STATUS_TRANS_DENIED	(0x01<<  26)
> +#define SSBI_PA_RD_STATUS_REG_DATA_SHFT	(0x00)
> +#define SSBI_PA_RD_STATUS_REG_DATA_MASK	(0xFF<<  SSBI_PA_CMD_REG_DATA_SHFT)
> +#define SSBI_PA_RD_STATUS_TRANS_COMPLETE \
> +	(SSBI_PA_RD_STATUS_TRANS_DONE|SSBI_PA_RD_STATUS_TRANS_DENIED)
> +
> +#define SSBI_MSM_NAME			"i2c_ssbi"
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_VERSION("2.0");
> +MODULE_ALIAS("platform:i2c_ssbi");
> +MODULE_AUTHOR("Kenneth Heitke<kheitke@...eaurora.org>");
> +
> +struct i2c_ssbi_dev {
> +	void __iomem		*base;
> +	struct device           *dev;
> +	struct i2c_adapter	 adapter;
> +	unsigned long		 mem_phys_addr;
> +	size_t			 mem_size;
> +	enum msm_ssbi_controller_type controller_type;
> +	int (*read)(struct i2c_ssbi_dev *, struct i2c_msg *);
> +	int (*write)(struct i2c_ssbi_dev *, struct i2c_msg *);
> +};
> +
> +static inline int
> +i2c_ssbi_poll_for_device_ready(struct i2c_ssbi_dev *ssbi)
> +{
> +	u32 timeout = SSBI_TIMEOUT_US;
> +
> +	while (!(readl(ssbi->base + SSBI2_STATUS)&  SSBI_STATUS_READY)) {
> +		if (--timeout == 0) {
> +			dev_err(ssbi->dev, "%s: timeout, status %x\n", __func__,
> +				readl(ssbi->base + SSBI2_STATUS));
> +			return -ETIMEDOUT;
> +		}
> +		udelay(1);
> +	}
> +
> +	return 0;
> +}
> +
> +static inline int
> +i2c_ssbi_poll_for_read_completed(struct i2c_ssbi_dev *ssbi)
> +{
> +	u32 timeout = SSBI_TIMEOUT_US;
> +
> +	while (!(readl(ssbi->base + SSBI2_STATUS)&  SSBI_STATUS_RD_READY)) {
> +		if (--timeout == 0) {
> +			dev_err(ssbi->dev, "%s: timeout, status %x\n", __func__,
> +				readl(ssbi->base + SSBI2_STATUS));
> +			return -ETIMEDOUT;
> +		}
> +		udelay(1);
> +	}
> +
> +	return 0;
> +}
> +
> +static inline int
> +i2c_ssbi_poll_for_transfer_completed(struct i2c_ssbi_dev *ssbi)
> +{
> +	u32 timeout = SSBI_TIMEOUT_US;
> +
> +	while ((readl(ssbi->base + SSBI2_STATUS)&  SSBI_STATUS_MCHN_BUSY)) {
> +		if (--timeout == 0) {
> +			dev_err(ssbi->dev, "%s: timeout, status %x\n", __func__,
> +				readl(ssbi->base + SSBI2_STATUS));
> +			return -ETIMEDOUT;
> +		}
> +		udelay(1);
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +i2c_ssbi_read_bytes(struct i2c_ssbi_dev *ssbi, struct i2c_msg *msg)
> +{
> +	int ret = 0;
> +	u8 *buf = msg->buf;
> +	u16 len = msg->len;
> +	u16 addr = msg->addr;
> +	u32 read_cmd = SSBI_CMD_READ(addr);
> +
> +	if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) {
> +		u32 mode2 = readl(ssbi->base + SSBI2_MODE2);
> +		writel(SSBI_MODE2_REG_ADDR_15_8(mode2, addr),
> +				ssbi->base + SSBI2_MODE2);
> +	}
> +
> +	while (len) {
> +		ret = i2c_ssbi_poll_for_device_ready(ssbi);
> +		if (ret)
> +			goto read_failed;
> +
> +		writel(read_cmd, ssbi->base + SSBI2_CMD);
> +
> +		ret = i2c_ssbi_poll_for_read_completed(ssbi);
> +		if (ret)
> +			goto read_failed;
> +
> +		*buf++ = readl(ssbi->base + SSBI2_RD)&  SSBI_RD_REG_DATA_MASK;
> +		len--;
> +	}
> +
> +read_failed:
> +	return ret;
> +}
> +
> +static int
> +i2c_ssbi_write_bytes(struct i2c_ssbi_dev *ssbi, struct i2c_msg *msg)
> +{
> +	int ret = 0;
> +	u8 *buf = msg->buf;
> +	u16 len = msg->len;
> +	u16 addr = msg->addr;
> +
> +	if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) {
> +		u32 mode2 = readl(ssbi->base + SSBI2_MODE2);
> +		writel(SSBI_MODE2_REG_ADDR_15_8(mode2, addr),
> +				ssbi->base + SSBI2_MODE2);
> +	}
> +
> +	while (len) {
> +		ret = i2c_ssbi_poll_for_device_ready(ssbi);
> +		if (ret)
> +			goto write_failed;
> +
> +		writel(SSBI_CMD_WRITE(addr, *buf++), ssbi->base + SSBI2_CMD);
> +
> +		ret = i2c_ssbi_poll_for_transfer_completed(ssbi);
> +		if (ret)
> +			goto write_failed;
> +
> +		len--;
> +	}
> +
> +write_failed:
> +	return ret;
> +}
> +
> +static inline int
> +i2c_ssbi_pa_transfer(struct i2c_ssbi_dev *ssbi, u32 cmd, u8 *data)
> +{
> +	u32 rd_status;
> +	u32 timeout = SSBI_TIMEOUT_US;
> +
> +	writel(cmd, ssbi->base + SSBI_PA_CMD);
> +	rd_status = readl(ssbi->base + SSBI_PA_RD_STATUS);
> +
> +	while ((rd_status&  (SSBI_PA_RD_STATUS_TRANS_COMPLETE)) == 0) {
> +
> +		if (--timeout == 0) {
> +			dev_err(ssbi->dev, "%s: timeout, status %x\n",
> +					__func__, rd_status);
> +			return -ETIMEDOUT;
> +		}
> +		udelay(1);
> +		rd_status = readl(ssbi->base + SSBI_PA_RD_STATUS);
> +	}
> +
> +	if (rd_status&  SSBI_PA_RD_STATUS_TRANS_DENIED) {
> +		dev_err(ssbi->dev, "%s: transaction denied, status %x\n",
> +				__func__, rd_status);
> +		return -EPERM;
> +	}
> +
> +	if (data)
> +		*data = (rd_status&  SSBI_PA_RD_STATUS_REG_DATA_MASK)>>
> +					SSBI_PA_CMD_REG_DATA_SHFT;
> +	return 0;
> +}
> +
> +static int
> +i2c_ssbi_pa_read_bytes(struct i2c_ssbi_dev *ssbi, struct i2c_msg *msg)
> +{
> +	int ret = 0;
> +	u8  data;
> +	u8 *buf = msg->buf;
> +	u16 len = msg->len;
> +	u32 read_cmd = (SSBI_PA_CMD_RDWRN | SSBI_PA_CMD_REG_ADDR(msg->addr));
> +
> +	while (len) {
> +
> +		ret = i2c_ssbi_pa_transfer(ssbi, read_cmd,&data);
> +		if (ret)
> +			goto read_failed;
> +
> +		*buf++ = data;
> +		len--;
> +	}
> +
> +read_failed:
> +	return ret;
> +}
> +
> +static int
> +i2c_ssbi_pa_write_bytes(struct i2c_ssbi_dev *ssbi, struct i2c_msg *msg)
> +{
> +	int ret = 0;
> +	u8 *buf = msg->buf;
> +	u16 len = msg->len;
> +	u32 addr = SSBI_PA_CMD_REG_ADDR(msg->addr);
> +
> +	while (len) {
> +
> +		u32 write_cmd = addr | (*buf++&  SSBI_PA_CMD_REG_DATA_MASK);
> +
> +		ret = i2c_ssbi_pa_transfer(ssbi, write_cmd, NULL);
> +		if (ret)
> +			goto write_failed;
> +		len--;
> +	}
> +
> +write_failed:
> +	return ret;
> +}
> +
> +static int
> +i2c_ssbi_transfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
> +{
> +	int ret = 0;
> +	int rem = num;
> +	struct i2c_ssbi_dev *ssbi = i2c_get_adapdata(adap);
> +
> +	while (rem) {
> +		if (msgs->flags&  I2C_M_RD) {
> +			ret = ssbi->read(ssbi, msgs);
> +			if (ret)
> +				goto transfer_failed;
> +		} else {
> +			ret = ssbi->write(ssbi, msgs);
> +			if (ret)
> +				goto transfer_failed;
> +		}
> +
> +		msgs++;
> +		rem--;
> +	}
> +
> +	return num;
> +
> +transfer_failed:
> +	return ret;
> +}
> +
> +static u32 i2c_ssbi_i2c_func(struct i2c_adapter *adap)
> +{
> +	return I2C_FUNC_I2C;
> +}
> +
> +static const struct i2c_algorithm msm_i2c_algo = {
> +	.master_xfer	= i2c_ssbi_transfer,
> +	.functionality	= i2c_ssbi_i2c_func,
> +};
> +
> +static int __devinit i2c_ssbi_probe(struct platform_device *pdev)
> +{
> +	int			 ret = 0;
> +	struct resource		*ssbi_res;
> +	struct i2c_ssbi_dev	*ssbi;
> +	struct msm_ssbi_platform_data *pdata;
> +
> +	pdata = pdev->dev.platform_data;
> +	if (!pdata) {
> +		ret = -ENXIO;
> +		dev_err(&pdev->dev, "platform data not initialized\n");
> +		goto err_probe_exit;
> +	}
> +
> +	ssbi = kzalloc(sizeof(struct i2c_ssbi_dev), GFP_KERNEL);
> +	if (!ssbi) {
> +		ret = -ENOMEM;
> +		dev_err(&pdev->dev, "allocation failed\n");
> +		goto err_probe_exit;
> +	}
> +
> +	ssbi_res = platform_get_resource_byname(pdev,
> +						IORESOURCE_MEM, "ssbi_base");
> +	if (!ssbi_res) {
> +		ret = -ENXIO;
> +		dev_err(&pdev->dev, "get_resource_byname failed\n");
> +		goto err_probe_res;
> +	}
> +
> +	ssbi->mem_phys_addr = ssbi_res->start;
> +	ssbi->mem_size = resource_size(ssbi_res);
> +	if (!request_mem_region(ssbi->mem_phys_addr, ssbi->mem_size,
> +				SSBI_MSM_NAME)) {
> +		ret = -ENXIO;
> +		dev_err(&pdev->dev, "request_mem_region failed\n");
> +		goto err_probe_reqmem;
> +	}
> +
> +	ssbi->base = ioremap(ssbi->mem_phys_addr, ssbi->mem_size);
> +	if (!ssbi->base) {
> +		dev_err(&pdev->dev, "ioremap failed\n");
> +		goto err_probe_ioremap;
> +	}
> +
> +	ssbi->dev =&pdev->dev;
> +	platform_set_drvdata(pdev, ssbi);
> +
> +	ssbi->controller_type = pdata->controller_type;
> +	if (ssbi->controller_type == MSM_SBI_CTRL_PMIC_ARBITER) {
> +		ssbi->read = i2c_ssbi_pa_read_bytes;
> +		ssbi->write = i2c_ssbi_pa_write_bytes;
> +	} else {
> +		ssbi->read = i2c_ssbi_read_bytes;
> +		ssbi->write = i2c_ssbi_write_bytes;
> +	}
> +
> +	i2c_set_adapdata(&ssbi->adapter, ssbi);
> +	ssbi->adapter.algo =&msm_i2c_algo;
> +	strlcpy(ssbi->adapter.name,
> +		"MSM SSBI adapter",
> +		sizeof(ssbi->adapter.name));
> +
> +	ssbi->adapter.nr = pdev->id;
> +	ret = i2c_add_numbered_adapter(&ssbi->adapter);
> +	if (ret) {
> +		dev_err(&pdev->dev, "i2c_add_numbered_adapter failed\n");
> +		goto err_add_adapter_failed;
> +	}
> +	return 0;
> +
> +err_add_adapter_failed:
> +	iounmap(ssbi->base);
> +	platform_set_drvdata(pdev, NULL);
> +err_probe_ioremap:
> +	release_mem_region(ssbi->mem_phys_addr, ssbi->mem_size);
> +err_probe_reqmem:
> +err_probe_res:
> +	kfree(ssbi);
> +err_probe_exit:
> +	return ret;
> +}
> +
> +static int __devexit i2c_ssbi_remove(struct platform_device *pdev)
> +{
> +	struct i2c_ssbi_dev *ssbi = platform_get_drvdata(pdev);
> +
> +	platform_set_drvdata(pdev, NULL);
> +	i2c_del_adapter(&ssbi->adapter);
> +	iounmap(ssbi->base);
> +	release_mem_region(ssbi->mem_phys_addr, ssbi->mem_size);
> +	kfree(ssbi);
> +	return 0;
> +}
> +
> +static struct platform_driver i2c_ssbi_driver = {
> +	.probe          = i2c_ssbi_probe,
> +	.driver		= {
> +		.name	= "i2c_ssbi",
> +		.owner	= THIS_MODULE,
> +	},
> +	.remove		= __devexit_p(i2c_ssbi_remove),
> +};
> +
> +static int __init i2c_ssbi_init(void)
> +{
> +	return platform_driver_register(&i2c_ssbi_driver);
> +}
> +arch_initcall(i2c_ssbi_init);
> +
> +static void __exit i2c_ssbi_exit(void)
> +{
> +	platform_driver_unregister(&i2c_ssbi_driver);
> +}
> +module_exit(i2c_ssbi_exit);
> diff --git a/include/linux/i2c-ssbi.h b/include/linux/i2c-ssbi.h
> new file mode 100755
> index 0000000..75386d5
> --- /dev/null
> +++ b/include/linux/i2c-ssbi.h
> @@ -0,0 +1,33 @@
> +/*
> + * Qualcomm MSM i2c Controller Platform Data
> + *
> + * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> + * 02110-1301, USA.
> + */
> +#ifndef __LINUX_I2C_SSBI_H
> +#define __LINUX_I2C_SSBI_H
> +
> +enum msm_ssbi_controller_type {
> +	MSM_SBI_CTRL_SSBI = 0,
> +	MSM_SBI_CTRL_SSBI2,
> +	MSM_SBI_CTRL_PMIC_ARBITER,
> +};
> +
> +struct msm_ssbi_platform_data {
> +	enum msm_ssbi_controller_type controller_type;
> +};
> +
> +#endif /* __LINUX_I2C_SSBI_H */


-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ