diff options
author | Rob Herring <r.herring@freescale.com> | 2009-01-25 19:43:26 -0500 |
---|---|---|
committer | Rob Herring <r.herring@freescale.com> | 2009-02-17 11:32:54 -0600 |
commit | aa2643ed8f7c03f8dc68b7f6f5b290f490385a43 (patch) | |
tree | de6fe3e0850e5195b3f33e694c6345faabd1754f /drivers/mxc/gps_ioctrl | |
parent | 484ecd8c05117a795d856e57e45be48ecea07eae (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/Kconfig | 14 | ||||
-rw-r--r-- | drivers/mxc/gps_ioctrl/Makefile | 5 | ||||
-rw-r--r-- | drivers/mxc/gps_ioctrl/agpsgpiodev.c | 299 | ||||
-rw-r--r-- | drivers/mxc/gps_ioctrl/agpsgpiodev.h | 46 |
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 |