From: Ken Lierman<[email protected]>
Add 3rd party device driver and associated platform support for
Broadcom BCM4751 GPS chip on customer hardware.
Please enabled in the default config for mid as well, ie:
CONFIG_BCM4751_GPS=y
Change-Id: I7934fd953283f8bd9551f84077a5db697826f860
Signed-off-by: Ken Lierman<[email protected]>
---
arch/x86/kernel/mrst.c | 144 ++++++++++++
drivers/misc/Kconfig | 11 +
drivers/misc/Makefile | 1 +
drivers/misc/bcm4751-gps.c | 482 +++++++++++++++++++++++++++++++++++++++
include/linux/i2c/bcm4751-gps.h | 58 +++++
5 files changed, 696 insertions(+), 0 deletions(-)
create mode 100644 drivers/misc/bcm4751-gps.c
create mode 100644 include/linux/i2c/bcm4751-gps.h
diff --git a/arch/x86/kernel/mrst.c b/arch/x86/kernel/mrst.c
index 4e1e181..ab634d1 100644
--- a/arch/x86/kernel/mrst.c
+++ b/arch/x86/kernel/mrst.c
@@ -31,6 +31,7 @@
#include<linux/cyttsp.h>
#include<linux/i2c.h>
#include<linux/i2c/pca953x.h>
+#include<linux/i2c/bcm4751-gps.h>
#include<linux/lis3lv02d.h>
#include<linux/i2c/tc35894xbg.h>
#include<linux/bh1770glc.h>
@@ -801,6 +802,148 @@ void *bh1770glc_platform_data_init(void *info)
return&prox_pdata;
}
+#define BCM4751_GPIO_IRQ "GPS-request"
+#define BCM4751_GPIO_ENABLE "GPS-reset"
+#define BCM4751_GPIO_WAKEUP "GPS-wakeup"
+#define BCM4751_IRQ_ADDR (0x1FA)
+
+static int bcm4751_gps_setup(struct i2c_client *client)
+{
+
+ struct bcm4751_gps_data *data = i2c_get_clientdata(client);
+ int err;
+
+ err = gpio_request(data->gpio_irq, BCM4751_GPIO_IRQ);
+ if (err) {
+ dev_err(&client->dev,
+ "Failed to request GPIO%d (HOST_REQ)\n",
+ data->gpio_irq);
+ return err;
+ }
+
+ err = gpio_direction_input(data->gpio_irq);
+ if (err) {
+ dev_err(&client->dev, "Failed to change direction\n");
+ goto clean_gpio_irq;
+ }
+
+ /* Request GPIO for NSHUTDOWN == GPS_ENABLE */
+ err = gpio_request(data->gpio_enable, BCM4751_GPIO_ENABLE);
+ if (err< 0) {
+ dev_err(&client->dev,
+ "Failed to request GPIO%d (GPS_ENABLE)\n",
+ data->gpio_enable);
+ goto clean_gpio_irq;
+ }
+
+ err = gpio_direction_output(data->gpio_enable, 0);
+ if (err) {
+ dev_err(&client->dev, "Failed to change direction\n");
+ goto clean_gpio_irq;
+ }
+
+ /* Request GPIO for GPS WAKEUP */
+ err = gpio_request(data->gpio_wakeup, BCM4751_GPIO_WAKEUP);
+ if (err< 0) {
+ dev_err(&client->dev,
+ "Failed to request GPIO%d (GPS_WAKEUP)\n",
+ data->gpio_wakeup);
+ goto clean_gpio_en;
+ }
+
+ err = gpio_direction_output(data->gpio_wakeup, 0);
+ if (err) {
+ dev_err(&client->dev, "Failed to change direction\n");
+ goto clean_gpio_wakeup;
+ }
+
+ return 0;
+
+clean_gpio_wakeup: gpio_free(data->gpio_wakeup);
+
+clean_gpio_en: gpio_free(data->gpio_enable);
+
+clean_gpio_irq: gpio_free(data->gpio_irq);
+
+ return err;
+
+}
+
+static void bcm4751_gps_cleanup(struct i2c_client *client)
+{
+ struct bcm4751_gps_data *data = i2c_get_clientdata(client);
+
+ gpio_free(data->gpio_irq);
+ gpio_free(data->gpio_wakeup);
+ gpio_free(data->gpio_enable);
+}
+
+static int bcm4751_gps_show_gpio_irq(struct i2c_client *client)
+{
+ struct bcm4751_gps_data *data = i2c_get_clientdata(client);
+
+ return gpio_get_value(data->gpio_irq);
+}
+
+static void bcm4751_gps_enable(struct i2c_client *client)
+{
+ struct bcm4751_gps_data *data = i2c_get_clientdata(client);
+
+ gpio_set_value(data->gpio_enable, 1);
+ data->enable = 1;
+}
+
+static void bcm4751_gps_disable(struct i2c_client *client)
+{
+ struct bcm4751_gps_data *data = i2c_get_clientdata(client);
+
+ gpio_set_value(data->gpio_enable, 0);
+ data->enable = 0;
+}
+
+static void bcm4751_gps_wakeup_ctrl(struct i2c_client *client, int value)
+{
+ struct bcm4751_gps_data *data = i2c_get_clientdata(client);
+
+ gpio_set_value(data->gpio_wakeup, value);
+ data->wakeup = value;
+}
+
+void *bcm4751_platform_data(void *info)
+{
+ struct i2c_board_info *i2c_info = (struct i2c_board_info *) info;
+ static struct bcm4751_gps_platform_data mfld_bcm4751_gps_platform_data;
+ int intr;
+ int enable;
+ int wakeup;
+
+ memset(&mfld_bcm4751_gps_platform_data, 0x00,
+ sizeof(struct bcm4751_gps_platform_data));
+
+ intr = get_gpio_by_name(BCM4751_GPIO_IRQ);
+ enable = get_gpio_by_name(BCM4751_GPIO_ENABLE);
+ wakeup = get_gpio_by_name(BCM4751_GPIO_WAKEUP);
+ if ((intr == -1) || (enable == -1) || (wakeup == -1)) {
+ printk(KERN_ERR "Missing SFI entry(ies) for BCM4751 pin(s)\n");
+ return NULL;
+ }
+
+ i2c_info->irq = intr + MRST_IRQ_OFFSET;
+ i2c_info->flags |= I2C_CLIENT_TEN;
+ mfld_bcm4751_gps_platform_data.gps_gpio_irq = intr;
+ mfld_bcm4751_gps_platform_data.gps_gpio_enable = enable;
+ mfld_bcm4751_gps_platform_data.gps_gpio_wakeup = wakeup;
+ mfld_bcm4751_gps_platform_data.setup = bcm4751_gps_setup;
+ mfld_bcm4751_gps_platform_data.cleanup = bcm4751_gps_cleanup;
+ mfld_bcm4751_gps_platform_data.enable = bcm4751_gps_enable;
+ mfld_bcm4751_gps_platform_data.disable = bcm4751_gps_disable;
+ mfld_bcm4751_gps_platform_data.wakeup_ctrl = bcm4751_gps_wakeup_ctrl;
+ mfld_bcm4751_gps_platform_data.show_irq = bcm4751_gps_show_gpio_irq;
+
+ printk(KERN_INFO "File: %s, Line: %d\n", __FILE__, __LINE__);
+ return&mfld_bcm4751_gps_platform_data;
+}
+
#define CY8CTMG110_RESET_PIN_GPIO 43
#define CY8CTMG110_IRQ_PIN_GPIO 59
#define CY8CTMG110_TOUCH_IRQ 21
@@ -1108,6 +1251,7 @@ static const struct devs_id device_ids[] = {
{"i2c_TC35894-i", SFI_DEV_TYPE_I2C, 0,&tc35894xbg_i_platform_data},
{"bh1770glc", SFI_DEV_TYPE_I2C, 0,&bh1770glc_platform_data_init},
{"lp5523", SFI_DEV_TYPE_I2C, 0,&lp5523_platform_data_init},
+ {"bcm4751-gps", SFI_DEV_TYPE_I2C, 0,&bcm4751_platform_data },
{},
};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index f12bf52..677560d 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -456,6 +456,17 @@ config BT_PCM
This driver provides support for sending/sending PCM samples to BT
WL 1271/3
+config BCM4751_GPS
+ tristate "BCM4751 GPS driver"
+ depends on I2C
+ default n
+ ---help---
+ If you say yes here you get support for the Broadcom BCM4751 GPS
+ chip driver.
+
+ The driver supports only GPS in BCM4751 chip. When built as a driver
+ driver name is: bcm4751-gps. If unsure, say N here.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/cmt/Kconfig"
source "drivers/misc/eeprom/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 45eff03..a40069b 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o
obj-$(CONFIG_DS1682) += ds1682.o
obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o
obj-$(CONFIG_BH1770GLC) += bh1770glc.o
+obj-$(CONFIG_BCM4751_GPS) += bcm4751-gps.o
obj-$(CONFIG_C2PORT) += c2port/
obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/
obj-$(CONFIG_IFX_SPEECH) += ifx-speech/
diff --git a/drivers/misc/bcm4751-gps.c b/drivers/misc/bcm4751-gps.c
new file mode 100644
index 0000000..04769c0
--- /dev/null
+++ b/drivers/misc/bcm4751-gps.c
@@ -0,0 +1,482 @@
+/*
+ * bcm4751-gps.c - Hardware interface for Broadcom BCM4751 GPS chip.
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Written by Andrei Emeltchenko<[email protected]>
+ * Modified by Yuri Zaporozhets<[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+/* #define DEBUG */
+
+#include<linux/kernel.h>
+#include<linux/module.h>
+#include<linux/fs.h>
+#include<linux/err.h>
+#include<linux/mutex.h>
+#include<linux/i2c.h>
+#include<linux/i2c-dev.h>
+#include<linux/interrupt.h>
+#include<linux/gpio.h>
+#include<linux/poll.h>
+#include<linux/miscdevice.h>
+#include<linux/delay.h>
+#include<linux/slab.h>
+
+#include<linux/i2c/bcm4751-gps.h>
+
+static struct bcm4751_gps_data *bcm4751_gps_device;
+
+/*
+ * Part of initialization is done in the board support file.
+ */
+
+static inline void bcm4751_gps_enable(struct bcm4751_gps_data *self)
+{
+ if (self->pdata->enable)
+ self->pdata->enable(self->client);
+}
+
+static inline void bcm4751_gps_disable(struct bcm4751_gps_data *self)
+{
+ if (self->pdata->disable)
+ self->pdata->disable(self->client);
+}
+
+static inline void bcm4751_gps_wakeup_value(struct bcm4751_gps_data *self,
+ int value)
+{
+ if (self->pdata->wakeup_ctrl)
+ self->pdata->wakeup_ctrl(self->client, value);
+}
+
+
+/*
+ * miscdevice interface
+ */
+
+static int bcm4751_gps_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int bcm4751_gps_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static ssize_t bcm4751_gps_read(struct file *file, char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct i2c_client *client = bcm4751_gps_device->client;
+ int num_read;
+ uint8_t tmp[BCM4751_MAX_BINPKT_RX_LEN];
+
+ /* Adjust for binary packet size */
+ if (count> BCM4751_MAX_BINPKT_RX_LEN)
+ count = BCM4751_MAX_BINPKT_RX_LEN;
+
+ dev_dbg(&client->dev, "GPS Address: 0x%x\n", client->addr);
+
+ dev_dbg(&client->dev, "reading %d bytes\n", count);
+
+ num_read = i2c_master_recv(client, tmp, count);
+
+ if (num_read< 0) {
+ dev_err(&client->dev, "got %d bytes instead of %d\n",
+ num_read, count);
+ return num_read;
+ } else {
+ dev_dbg(&client->dev, "reading %d bytes returns %d",
+ count, num_read);
+ }
+
+ return copy_to_user(buf, tmp, num_read) ? -EFAULT : num_read;
+}
+
+static ssize_t bcm4751_gps_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct i2c_client *client = bcm4751_gps_device->client;
+ uint8_t tmp[BCM4751_MAX_BINPKT_TX_LEN];
+ int num_sent;
+
+ if (count> BCM4751_MAX_BINPKT_TX_LEN)
+ count = BCM4751_MAX_BINPKT_TX_LEN;
+
+ dev_dbg(&client->dev, "writing %d bytes\n", count);
+
+ if (copy_from_user(tmp, buf, count))
+ return -EFAULT;
+
+ num_sent = i2c_master_send(client, tmp, count);
+
+ dev_dbg(&client->dev, "writing %d bytes returns %d",
+ count, num_sent);
+
+ return num_sent;
+}
+
+static int bcm4751_gps_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct i2c_client *client = bcm4751_gps_device->client;
+
+ dev_dbg(&client->dev, "ioctl: cmd = 0x%02x, arg=0x%02lx\n", cmd, arg);
+
+ switch (cmd) {
+ case I2C_SLAVE:
+ case I2C_SLAVE_FORCE:
+ if ((arg> 0x3ff) ||
+ (((client->flags& I2C_M_TEN) == 0)&&
+ arg> 0x7f))
+ return -EINVAL;
+ client->addr = arg;
+ dev_dbg(&client->dev, "ioctl: client->addr = %x", client->addr);
+ return 0;
+ case I2C_TENBIT:
+ if (arg)
+ client->flags |= I2C_M_TEN;
+ else
+ client->flags&= ~I2C_M_TEN;
+ return 0;
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static const struct file_operations bcm4751_gps_fileops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = bcm4751_gps_read,
+ .write = bcm4751_gps_write,
+ .ioctl = bcm4751_gps_ioctl,
+ .open = bcm4751_gps_open,
+ .release = bcm4751_gps_release,
+};
+
+static struct miscdevice bcm4751_gps_miscdevice = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "bcm4751-gps",
+ .fops =&bcm4751_gps_fileops
+};
+
+
+/*
+ * sysfs interface
+ */
+
+static ssize_t bcm4751_gps_show_hostreq(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bcm4751_gps_data *self = dev_get_drvdata(dev);
+ int value = -1;
+
+ if (self->pdata->show_irq)
+ value = self->pdata->show_irq(self->client);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+static ssize_t bcm4751_gps_show_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bcm4751_gps_data *self = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", self->enable);
+}
+
+static ssize_t bcm4751_gps_set_enable(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct bcm4751_gps_data *self = dev_get_drvdata(dev);
+ int value;
+
+ sscanf(buf, "%d",&value);
+ dev_dbg(dev, "enable: %d", value);
+
+ switch (value) {
+ case 0:
+ bcm4751_gps_disable(self);
+ break;
+
+ case 1:
+ bcm4751_gps_enable(self);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ self->enable = value;
+ return len;
+}
+
+static ssize_t bcm4751_gps_show_wakeup(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bcm4751_gps_data *self = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", self->wakeup);
+}
+
+static ssize_t bcm4751_gps_set_wakeup(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ unsigned long val;
+ int ret;
+ struct bcm4751_gps_data *self = dev_get_drvdata(dev);
+
+ ret = strict_strtoul(buf, 0,&val);
+ if (ret&& val> 1)
+ return -EINVAL;
+ else {
+ bcm4751_gps_wakeup_value(self, val);
+ dev_dbg(dev, "new wakeup value = %d", self->wakeup);
+ }
+
+ return len;
+}
+
+static struct device_attribute bcm4751_gps_attrs[] = {
+ __ATTR(enable, S_IRUGO|S_IWUSR,
+ bcm4751_gps_show_enable, bcm4751_gps_set_enable),
+ __ATTR(hostreq, S_IRUGO|S_IWUSR,
+ bcm4751_gps_show_hostreq, NULL),
+ __ATTR(wakeup, S_IRUGO|S_IWUSR,
+ bcm4751_gps_show_wakeup, bcm4751_gps_set_wakeup),
+};
+
+static int bcm4751_gps_register_sysfs(struct i2c_client *client)
+{
+ struct device *dev =&client->dev;
+ int i, ret;
+
+ for (i = 0; i< ARRAY_SIZE(bcm4751_gps_attrs); i++) {
+ ret = device_create_file(dev,&bcm4751_gps_attrs[i]);
+ if (ret)
+ goto fail;
+ }
+ return 0;
+fail:
+ while (i--)
+ device_remove_file(dev,&bcm4751_gps_attrs[i]);
+
+ return ret;
+}
+
+static void bcm4751_gps_unregister_sysfs(struct i2c_client *client)
+{
+ struct device *dev =&client->dev;
+ int i;
+
+ for (i = ARRAY_SIZE(bcm4751_gps_attrs) - 1; i>= 0; i--)
+ device_remove_file(dev,&bcm4751_gps_attrs[i]);
+}
+
+/*
+ * "Bottom half" of the interrupt.
+ * It gets called only when the "main" handler detects HOST_IRQ=1
+ */
+static void bcm4751_gps_bottom_half(struct work_struct *work)
+{
+ struct bcm4751_gps_data *data =
+ container_of(work, struct bcm4751_gps_data, work);
+
+ dev_dbg(&data->client->dev, "irq, HOST_REQ=%d",
+ data->pdata->show_irq(data->client));
+
+ /* Update sysfs GPIO line here */
+ sysfs_notify(&data->client->dev.kobj, NULL, "hostreq");
+}
+
+static irqreturn_t bcm4751_gps_irq(int irq, void *dev_id)
+{
+ struct bcm4751_gps_data *data = dev_id;
+
+ /* If HOST_REQ is 1 - let bottom half to do the rest of the job */
+ if (data->pdata->show_irq(data->client))
+ schedule_work(&data->work);
+
+ return IRQ_HANDLED;
+}
+
+static int bcm4751_gps_probe(struct i2c_client *client,
+ const struct i2c_device_id *device_id)
+{
+ struct bcm4751_gps_data *data;
+ struct bcm4751_gps_platform_data *pdata;
+ int err;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ pdata = client->dev.platform_data;
+ if (!pdata) {
+ dev_err(&client->dev, "no platform data\n");
+ err = -ENODEV;
+ goto clean_data;
+ }
+
+ i2c_set_clientdata(client, data);
+ data->client = client;
+ data->pdata = pdata;
+ data->enable = 1;
+ data->wakeup = 1;
+
+ data->gpio_irq = pdata->gps_gpio_irq;
+ data->gpio_enable = pdata->gps_gpio_enable;
+ data->gpio_wakeup = pdata->gps_gpio_wakeup;
+
+ if (pdata->setup) {
+ err = pdata->setup(client);
+ if (err)
+ goto clean_data;
+ }
+
+ INIT_WORK(&data->work, bcm4751_gps_bottom_half);
+ err = request_irq(client->irq, bcm4751_gps_irq,
+ IRQF_TRIGGER_RISING, "i2c_gps", data);
+ if (err) {
+ dev_err(&client->dev, "could not get GPS_IRQ = %d\n",
+ client->irq);
+ goto clean_setup;
+ }
+
+ err = bcm4751_gps_register_sysfs(client);
+ if (err) {
+ dev_err(&client->dev,
+ "sysfs registration failed, error %d\n", err);
+ goto clean_irq;
+ }
+
+ bcm4751_gps_miscdevice.parent =&client->dev;
+ err = misc_register(&bcm4751_gps_miscdevice);
+ if (err) {
+ dev_err(&client->dev, "Miscdevice register failed\n");
+ goto clean_sysfs;
+ }
+
+ bcm4751_gps_device = data;
+
+ return 0;
+
+clean_sysfs:
+ bcm4751_gps_unregister_sysfs(client);
+
+clean_irq:
+ free_irq(client->irq, data);
+
+clean_setup:
+ if (pdata->cleanup)
+ pdata->cleanup(client);
+
+clean_data:
+ kfree(data);
+ bcm4751_gps_device = NULL;
+
+ return err;
+}
+
+static int bcm4751_gps_remove(struct i2c_client *client)
+{
+ struct bcm4751_gps_data *data = i2c_get_clientdata(client);
+
+ bcm4751_gps_disable(data);
+
+ free_irq(client->irq, data);
+ misc_deregister(&bcm4751_gps_miscdevice);
+ bcm4751_gps_unregister_sysfs(client);
+ if (data->pdata->cleanup)
+ data->pdata->cleanup(client);
+ kfree(data);
+ bcm4751_gps_device = NULL;
+
+ return 0;
+}
+
+static void bcm4751_gps_shutdown(struct i2c_client *client)
+{
+ dev_dbg(&client->dev, "BCM4751 shutdown\n");
+ bcm4751_gps_disable(i2c_get_clientdata(client));
+}
+
+#ifdef CONFIG_PM
+static int bcm4751_gps_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct bcm4751_gps_data *data = i2c_get_clientdata(client);
+ data->pdata->wakeup_ctrl(data->client, 0);
+ dev_dbg(&client->dev, "BCM4751 suspends\n");
+ return 0;
+}
+
+static int bcm4751_gps_resume(struct i2c_client *client)
+{
+ struct bcm4751_gps_data *data = i2c_get_clientdata(client);
+ data->pdata->wakeup_ctrl(data->client, 1);
+ dev_dbg(&client->dev, "BCM4751 resumes\n");
+ return 0;
+}
+#else
+#define bcm4751_gps_suspend NULL
+#define bcm4751_gps_resume NULL
+#endif
+
+/* Address to scan: 0x1FA -i2c slave addr*/
+static const unsigned short bcm4751_normal_i2c[] = {
+ 0x1FA, I2C_CLIENT_END
+};
+
+static const struct i2c_device_id bcm4751_gps_id[] = {
+ { "bcm4751-gps", 0 },
+ { },
+};
+
+static struct i2c_driver bcm4751_gps_i2c_driver = {
+ .driver = {
+ .name = "i2c_gps",
+ },
+ .id_table = bcm4751_gps_id,
+ .probe = bcm4751_gps_probe,
+ .remove = __devexit_p(bcm4751_gps_remove),
+ .shutdown = bcm4751_gps_shutdown,
+ .suspend = bcm4751_gps_suspend,
+ .resume = bcm4751_gps_resume,
+};
+
+MODULE_DEVICE_TABLE(i2c, bcm4751_gps_id);
+
+static int __init bcm4751_gps_init(void)
+{
+ pr_info("Loading BCM4751 GPS driver\n");
+
+ return i2c_add_driver(&bcm4751_gps_i2c_driver);
+}
+
+static void __exit bcm4751_gps_exit(void)
+{
+ i2c_del_driver(&bcm4751_gps_i2c_driver);
+}
+
+module_init(bcm4751_gps_init);
+module_exit(bcm4751_gps_exit);
+
+MODULE_AUTHOR("Andrei Emeltchenko, Yuri Zaporozhets");
+MODULE_DESCRIPTION("BCM4751 GPS driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/i2c/bcm4751-gps.h b/include/linux/i2c/bcm4751-gps.h
new file mode 100644
index 0000000..9ec6162
--- /dev/null
+++ b/include/linux/i2c/bcm4751-gps.h
@@ -0,0 +1,58 @@
+/*
+ * @file include/linux/i2c/bcm4751-gps.h
+ *
+ * Hardware interface to BCM4751 GPS chip.
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Written by Andrei Emeltchenko<[email protected]>
+ * Modified by Yuri Zaporozhets<[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef _LINUX_I2C_BCM4751_GPS_H
+#define _LINUX_I2C_BCM4751_GPS_H
+
+/* Max packet sizes for RX and TX */
+#define BCM4751_MAX_BINPKT_RX_LEN 64
+#define BCM4751_MAX_BINPKT_TX_LEN 64
+
+/* Plaform data, used by the board support file */
+struct bcm4751_gps_platform_data {
+ int gps_gpio_irq;
+ int gps_gpio_enable;
+ int gps_gpio_wakeup;
+ int (*setup)(struct i2c_client *client);
+ void (*cleanup)(struct i2c_client *client);
+ void (*enable)(struct i2c_client *client);
+ void (*disable)(struct i2c_client *client);
+ void (*wakeup_ctrl)(struct i2c_client *client, int value);
+ int (*show_irq)(struct i2c_client *client);
+};
+
+/* Used internally by the driver */
+struct bcm4751_gps_data {
+ struct i2c_client *client;
+ struct work_struct work;
+ struct bcm4751_gps_platform_data *pdata;
+ unsigned int gpio_irq;
+ unsigned int gpio_enable;
+ unsigned int gpio_wakeup;
+ int enable;
+ int wakeup;
+};
+
+#endif