summaryrefslogtreecommitdiff
path: root/drivers/mxc/gps_ioctrl
diff options
context:
space:
mode:
authorRob Herring <r.herring@freescale.com>2009-01-25 19:43:26 -0500
committerRob Herring <r.herring@freescale.com>2009-02-17 11:32:54 -0600
commitaa2643ed8f7c03f8dc68b7f6f5b290f490385a43 (patch)
treede6fe3e0850e5195b3f33e694c6345faabd1754f /drivers/mxc/gps_ioctrl
parent484ecd8c05117a795d856e57e45be48ecea07eae (diff)
ENGR00107731-2: Port imx 3.3.0 release to 2.6.28
Port rel_imx_2.6.26_3.3.0 to 2.6.28. PMIC Regulator and ASoC drivers are removed and not yet ported. Updated asm/arch headers for move to plat-mxc/include/mach device_create parameters changed. sysdev attribute functions changed. Adopt mainline MX3 timer code and update clock init flow. Signed-off-by: Rob Herring <r.herring@freescale.com>
Diffstat (limited to 'drivers/mxc/gps_ioctrl')
-rw-r--r--drivers/mxc/gps_ioctrl/Kconfig14
-rw-r--r--drivers/mxc/gps_ioctrl/Makefile5
-rw-r--r--drivers/mxc/gps_ioctrl/agpsgpiodev.c299
-rw-r--r--drivers/mxc/gps_ioctrl/agpsgpiodev.h46
4 files changed, 364 insertions, 0 deletions
diff --git a/drivers/mxc/gps_ioctrl/Kconfig b/drivers/mxc/gps_ioctrl/Kconfig
new file mode 100644
index 000000000000..cb2698da9287
--- /dev/null
+++ b/drivers/mxc/gps_ioctrl/Kconfig
@@ -0,0 +1,14 @@
+#
+# BROADCOM GPS configuration
+#
+
+menu "Broadcom GPS ioctrl support"
+
+config GPS_IOCTRL
+ tristate "GPS ioctrl support"
+ depends on MACH_MX31_3DS || MACH_MX35_3DS || MACH_MX37_3DS
+ default m
+ ---help---
+ Say Y to enable Broadcom GPS ioctrl on MXC platform.
+
+endmenu
diff --git a/drivers/mxc/gps_ioctrl/Makefile b/drivers/mxc/gps_ioctrl/Makefile
new file mode 100644
index 000000000000..42a48fe3bd7b
--- /dev/null
+++ b/drivers/mxc/gps_ioctrl/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the GPIO device driver module.
+#
+obj-$(CONFIG_GPS_IOCTRL) += gps_gpiodrv.o
+gps_gpiodrv-objs := agpsgpiodev.o
diff --git a/drivers/mxc/gps_ioctrl/agpsgpiodev.c b/drivers/mxc/gps_ioctrl/agpsgpiodev.c
new file mode 100644
index 000000000000..84d1fc6e8f8c
--- /dev/null
+++ b/drivers/mxc/gps_ioctrl/agpsgpiodev.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file agpsgpiodev.c
+ *
+ * @brief Main file for GPIO kernel module. Contains driver entry/exit
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h> /* Async notification */
+#include <asm/uaccess.h> /* for get_user, put_user, access_ok */
+#include <linux/sched.h> /* jiffies */
+#include <linux/poll.h>
+#include <linux/regulator/regulator.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include "agpsgpiodev.h"
+
+extern void gpio_gps_active(void);
+extern void gpio_gps_inactive(void);
+extern int gpio_gps_access(int para);
+
+struct mxc_gps_platform_data *mxc_gps_ioctrl_data;
+static int Device_Open; /* Only allow a single user of this device */
+
+/* Write GPIO from user space */
+static int ioctl_writegpio(int arg)
+{
+
+ /* Bit 0 of arg identifies the GPIO pin to write:
+ 0 = GPS_RESET_GPIO, 1 = GPS_POWER_GPIO.
+ Bit 1 of arg identifies the value to write (0 or 1). */
+
+ /* Bit 2 should be 0 to show this access is write */
+ return gpio_gps_access(arg & (~0x4));
+}
+
+/* Read GPIO from user space */
+static int ioctl_readgpio(int arg)
+{
+ /* Bit 0 of arg identifies the GPIO pin to read:
+ 0 = GPS_RESET_GPIO. 1 = GPS_POWER_GPIO
+ Bit 2 should be 1 to show this access is read */
+ return gpio_gps_access(arg | 0x4);
+}
+
+static int device_open(struct inode *inode, struct file *fp)
+{
+ /* We don't want to talk to two processes at the same time. */
+ if (Device_Open) {
+ printk(KERN_DEBUG "device_open() - Returning EBUSY. \
+ Device already open... \n");
+ return -EBUSY;
+ }
+ Device_Open++; /* BUGBUG : Not protected! */
+ try_module_get(THIS_MODULE);
+
+ return 0;
+}
+
+static int device_release(struct inode *inode, struct file *fp)
+{
+ /* We're now ready for our next caller */
+ Device_Open--;
+ module_put(THIS_MODULE);
+
+ return 0;
+}
+
+static int device_ioctl(struct inode *inode, struct file *fp,
+ unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+
+ /* Extract the type and number bitfields, and don't decode wrong cmds.
+ Return ENOTTY (inappropriate ioctl) before access_ok() */
+ if (_IOC_TYPE(cmd) != MAJOR_NUM) {
+ printk(KERN_ERR
+ "device_ioctl() - Error! IOC_TYPE = %d. Expected %d\n",
+ _IOC_TYPE(cmd), MAJOR_NUM);
+ return -ENOTTY;
+ }
+ if (_IOC_NR(cmd) > IOCTL_MAXNUMBER) {
+ printk(KERN_ERR
+ "device_ioctl() - Error!"
+ "IOC_NR = %d greater than max supported(%d)\n",
+ _IOC_NR(cmd), IOCTL_MAXNUMBER);
+ return -ENOTTY;
+ }
+
+ /* The direction is a bitmask, and VERIFY_WRITE catches R/W transfers.
+ `Type' is user-oriented, while access_ok is kernel-oriented, so the
+ concept of "read" and "write" is reversed. I think this is primarily
+ for good coding practice. You can easily do any kind of R/W access
+ without these checks and IOCTL code can be implemented "randomly"! */
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err =
+ !access_ok(VERIFY_WRITE, (void __user *)arg,
+ _IOC_SIZE(cmd));
+
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ err =
+ !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
+ if (err) {
+ printk(KERN_ERR
+ "device_ioctl() - Error! User arg not valid"
+ "for selected access (R/W/RW). Cmd %d\n",
+ _IOC_TYPE(cmd));
+ return -EFAULT;
+ }
+
+ /* Note: Read and writing data to user buffer can be done using regular
+ pointer stuff but we may also use get_user() or put_user() */
+
+ /* Cmd and arg has been verified... */
+ switch (cmd) {
+ case IOCTL_WRITEGPIO:
+ return ioctl_writegpio((int)arg);
+ case IOCTL_READGPIO:
+ return ioctl_readgpio((int)arg);
+ default:
+ printk(KERN_ERR "device_ioctl() - Invalid IOCTL (0x%x)\n", cmd);
+ return EINVAL;
+ }
+ return 0;
+}
+
+struct file_operations Fops = {
+ .ioctl = device_ioctl,
+ .open = device_open,
+ .release = device_release,
+};
+
+/* Initialize the module - Register the character device */
+int init_chrdev(void)
+{
+ /* NOTE : THIS IS THE OLD-SCHOOL WAY TO REGISTER A CHAR DEVICE.
+ THE RECOMMENDED APPROACH IS TO USE cdev_alloc, cdev_init, cdev_add,
+ cdev_del. REFER TO CHAPTER 3 IN THE DEVICE DRIVER BOOK! */
+
+ /* Register the character device (at least try) */
+ int ret_val =
+ register_chrdev(MAJOR_NUM, AGPSGPIO_DEVICE_FILE_NAME, &Fops);
+
+ /* Negative values signify an error */
+ if (ret_val < 0) {
+ printk(KERN_ERR
+ "init_chrdev() - Failed to register"
+ "char device (error %d)\n", ret_val);
+ return ret_val;
+ }
+
+ return 0;
+}
+
+/* Cleanup - unregister the appropriate file from /proc. */
+void cleanup_chrdev(void)
+{
+ /* Unregister the device
+ int ret = unregister_chrdev(MAJOR_NUM, AGPSGPIO_DEVICE_FILE_NAME);
+ change for 2.6.24 since its declarationis as below:
+ extern void unregister_chrdev(unsigned int, const char *); */
+ unregister_chrdev(MAJOR_NUM, AGPSGPIO_DEVICE_FILE_NAME);
+}
+
+/*!
+ * This function initializes the driver in terms of memory of the soundcard
+ * and some basic HW clock settings.
+ *
+ * @return 0 on success, -1 otherwise.
+ */
+static int __init gps_ioctrl_probe(struct platform_device *pdev)
+{
+ struct regulator *gps_regu;
+
+ mxc_gps_ioctrl_data =
+ (struct mxc_gps_platform_data *)pdev->dev.platform_data;
+
+ /* open GPS GPO3 1v8 for GL gps support */
+ if (mxc_gps_ioctrl_data->core_reg != NULL) {
+ gps_regu =
+ regulator_get(&(pdev->dev), mxc_gps_ioctrl_data->core_reg);
+ if (!IS_ERR_VALUE((u32)gps_regu)) {
+ regulator_set_voltage(gps_regu, 1800000);
+ regulator_enable(gps_regu);
+ regulator_put(gps_regu, &(pdev->dev));
+ } else {
+ return -1;
+ }
+ }
+ /* open GPS GPO1 2v8 for GL gps support */
+ if (mxc_gps_ioctrl_data->analog_reg != NULL) {
+ gps_regu =
+ regulator_get(&(pdev->dev),
+ mxc_gps_ioctrl_data->analog_reg);
+ if (!IS_ERR_VALUE((u32)gps_regu)) {
+ regulator_set_voltage(gps_regu, 2800000);
+ regulator_enable(gps_regu);
+ regulator_put(gps_regu, &(pdev->dev));
+ } else {
+ return -1;
+ }
+ }
+ gpio_gps_active();
+
+ /* Register character device */
+ init_chrdev();
+ return 0;
+}
+
+static int gps_ioctrl_remove(struct platform_device *pdev)
+{
+ struct regulator *gps_regu;
+
+ mxc_gps_ioctrl_data =
+ (struct mxc_gps_platform_data *)pdev->dev.platform_data;
+
+ /* Character device cleanup.. */
+ cleanup_chrdev();
+ gpio_gps_inactive();
+
+ /* close GPS GPO3 1v8 for GL gps */
+ if (mxc_gps_ioctrl_data->core_reg != NULL) {
+ gps_regu =
+ regulator_get(&(pdev->dev), mxc_gps_ioctrl_data->core_reg);
+ regulator_disable(gps_regu);
+ regulator_put(gps_regu, &(pdev->dev));
+ }
+ /* close GPS GPO1 2v8 for GL gps */
+ if (mxc_gps_ioctrl_data->analog_reg != NULL) {
+ gps_regu =
+ regulator_get(&(pdev->dev),
+ mxc_gps_ioctrl_data->analog_reg);
+ regulator_disable(gps_regu);
+ regulator_put(gps_regu, &(pdev->dev));
+ }
+
+ return 0;
+}
+
+static int gps_ioctrl_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ /* PowerEn toggle off */
+ ioctl_writegpio(0x1);
+ return 0;
+}
+
+static int gps_ioctrl_resume(struct platform_device *pdev)
+{
+ /* PowerEn pull up */
+ ioctl_writegpio(0x3);
+ return 0;
+}
+
+static struct platform_driver gps_ioctrl_driver = {
+ .probe = gps_ioctrl_probe,
+ .remove = gps_ioctrl_remove,
+ .suspend = gps_ioctrl_suspend,
+ .resume = gps_ioctrl_resume,
+ .driver = {
+ .name = "gps_ioctrl",
+ },
+};
+
+/*!
+ * Entry point for GPS ioctrl module.
+ *
+ */
+static int __init gps_ioctrl_init(void)
+{
+ return platform_driver_register(&gps_ioctrl_driver);
+}
+
+/*!
+ * unloading module.
+ *
+ */
+static void __exit gps_ioctrl_exit(void)
+{
+ platform_driver_unregister(&gps_ioctrl_driver);
+}
+
+module_init(gps_ioctrl_init);
+module_exit(gps_ioctrl_exit);
+MODULE_DESCRIPTION("GPIO DEVICE DRIVER");
+MODULE_AUTHOR("Freescale Semiconductor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mxc/gps_ioctrl/agpsgpiodev.h b/drivers/mxc/gps_ioctrl/agpsgpiodev.h
new file mode 100644
index 000000000000..f0d0d01938d9
--- /dev/null
+++ b/drivers/mxc/gps_ioctrl/agpsgpiodev.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file agpsgpiodev.h
+ *
+ * @brief head file of Simple character device interface for AGPS kernel module.
+ *
+ * @ingroup
+ */
+
+#ifndef AGPSGPIODEV_H
+#define AGPSGPIODEV_H
+
+#include <linux/ioctl.h>
+
+#define USE_BLOCKING /* Test driver with blocking calls */
+#undef USE_FASYNC /* Test driver with async notification */
+
+/* The major device number. We can't rely on dynamic registration any more
+ because ioctls need to know it */
+#define MAJOR_NUM 100
+
+#define IOCTL_WRITEGPIO _IOWR(MAJOR_NUM, 1, char *)
+#define IOCTL_READGPIO _IOR(MAJOR_NUM, 2, char *)
+#define IOCTL_MAXNUMBER 2
+
+/* The name of the device file */
+#define AGPSGPIO_DEVICE_FILE_NAME "agpsgpio"
+
+/* Exported prototypes */
+int init_chrdev(void);
+void cleanup_chrdev(void);
+void wakeup(void);
+
+#endif