diff options
Diffstat (limited to 'drivers/staging/camera_flash/flash_common.c')
-rw-r--r-- | drivers/staging/camera_flash/flash_common.c | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/drivers/staging/camera_flash/flash_common.c b/drivers/staging/camera_flash/flash_common.c new file mode 100644 index 00000000000..fc59879a170 --- /dev/null +++ b/drivers/staging/camera_flash/flash_common.c @@ -0,0 +1,460 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * camera flash: Flash driver to export camera flash to user space application. + * It supports two flashes, one for primary and one for secondary camera + * Author: Pankaj Chauhan/pankaj.chauhan@stericsson.com for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/ioctl.h> +#include <linux/uaccess.h> +#include <linux/fs.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/kthread.h> +#include <linux/jiffies.h> +#include <linux/miscdevice.h> +#include "camera_flash.h" +#include "flash_common.h" + +#define DEBUG_LOG(...) printk(KERN_DEBUG "Camera Flash driver: " __VA_ARGS__) + +#define PRIMARY_CAMERA (0) +#define SECONDARY_CAMERA (1) +static struct miscdevice misc_dev; +struct flash_chip *flash_chips[2]; +struct fasync_struct * async_queue; +struct task_struct* ptaskStruct; +wait_queue_head_t waitQueue; +int waitCondition = 0; +struct flash_ioctl_args_t flashArg; + +#define COPY_ARG_FROM_USER(_to,_from_usr) do{ \ + memset((_to),0,sizeof(struct flash_ioctl_args_t)); \ + if (copy_from_user((_to), (struct flash_ioctl_args_t*) (_from_usr), sizeof(struct flash_ioctl_args_t))) { \ + DEBUG_LOG("Could not copy data from userspace successfully\n"); \ + break; \ + } \ +}while(0) + +#define COPY_ARG_TO_USER(_to_usr,_from) do{ \ + if (copy_to_user((struct flash_ioctl_args_t *)(_to_usr), (_from), sizeof(struct flash_ioctl_args_t))) { \ + DEBUG_LOG("Could not copy data from userspace successfully\n"); \ + break; \ + } \ +}while(0) + + +static long flash_ioctl(struct file *file_p, unsigned int cmd, unsigned long arg) +{ + int err=0; + struct flash_chip *flash_p = NULL; + struct flash_chip_ops *ops = NULL; + char *my_name=NULL; + struct flash_ioctl_args_t flash_arg; + + if (_IOC_TYPE(cmd) != FLASH_MAGIC_NUMBER) { + printk(KERN_ALERT "Flash driver: Not an ioctl for this module\n"); + err = -EINVAL; + } + + COPY_ARG_FROM_USER(&flash_arg,arg); + + if(flash_arg.cam == SECONDARY_CAMERA || flash_arg.cam == PRIMARY_CAMERA) + flash_p = flash_chips[flash_arg.cam]; + else{ + DEBUG_LOG("unsupported cam %lu\n",flash_arg.cam); + err = -ENODEV; + goto out; + } + my_name = flash_arg.cam ?"Secondary":"Primary"; + + if (flash_arg.cam == PRIMARY_CAMERA) + { + ops = flash_p->ops; + } + + switch(cmd){ + case FLASH_GET_MODES: + { + if (flash_arg.cam == PRIMARY_CAMERA) + { + err = ops->get_modes(flash_p->priv_data,&flash_arg.flash_mode); + if(!err){ + DEBUG_LOG("Supported flash modes for %s camera: %lx\n", + my_name,flash_arg.flash_mode); + COPY_ARG_TO_USER(arg,&flash_arg); + }else{ + DEBUG_LOG("unable to get supported modes for %s camera\n",my_name); + } + } + else + { + flash_arg.flash_mode = FLASH_MODE_NONE; + COPY_ARG_TO_USER(arg,&flash_arg); + } + } + break; + case FLASH_GET_MODE_DETAILS: + { + err = ops->get_mode_details(flash_p->priv_data,flash_arg.flash_mode, + &flash_arg.mode_arg.details); + if(!err){ + COPY_ARG_TO_USER(arg,&flash_arg); + }else{ + DEBUG_LOG("Unable to get mode details for %s camera, flash mode %lx\n", + my_name,flash_arg.flash_mode); + } + } + break; + case FLASH_ENABLE_MODE: + case FLASH_DISABLE_MODE: + { + int enable=0; + if(cmd == FLASH_ENABLE_MODE){ + enable = 1; + } + err = ops->enable_flash_mode(flash_p->priv_data,flash_arg.flash_mode,enable); + if(err){ + DEBUG_LOG("Unable to %s: %s camera, flash mode %lx\n", + (enable ?"Enable":"Disable"), my_name,flash_arg.flash_mode); + } + } + break; + case FLASH_CONFIGURE_MODE: + err = ops->configure_flash_mode(flash_p->priv_data,flash_arg.flash_mode, + &flash_arg.mode_arg.params); + if(err){ + DEBUG_LOG("Unable to configure %s camera, flash mode %lx\n", + my_name,flash_arg.flash_mode); + } + break; + case FLASH_TRIGGER_STROBE: + err = ops->trigger_strobe(flash_p->priv_data,flash_arg.mode_arg.strobe_enable); + if(err){ + DEBUG_LOG("Unable to %s: %s camera strobe trigger, mode %lx\n", + (arg ?"Enable":"Disable"), my_name,flash_arg.flash_mode); + } + break; + case FLASH_GET_STATUS: + err = ops->get_status(flash_p->priv_data,&flash_arg.status); + if(!err){ + COPY_ARG_TO_USER(arg,&flash_arg); + }else{ + DEBUG_LOG("Unable to get status details for %s camera, flash mode %lx\n", + my_name,flash_arg.flash_mode); + } + break; + case FLASH_GET_LIFE_COUNTER: + DEBUG_LOG("Not Implemented\n"); + break; + case FLASH_SELF_TEST: + flashArg = flash_arg; + if (0 != (flashArg.cam & (FLASH_SELFTEST_FLASH | FLASH_SELFTEST_FLASH_WITH_STROBE))) + { + err = ENODEV; + } + else + { + /* wake up worker thread */ + waitCondition = 1; + wake_up_interruptible(&waitQueue); + } + break; + case FLASH_GET_SELF_TEST_MODES: + { + if (flash_arg.cam == PRIMARY_CAMERA) + { + err = ops->get_selftest_modes(flash_p->priv_data,&flash_arg.flash_mode); + if(!err){ + COPY_ARG_TO_USER(arg,&flash_arg); + }else{ + DEBUG_LOG("unable to get supported modes for %s camera\n",my_name); + } + } + else + { + flash_arg.flash_mode = FLASH_SELFTEST_NONE; + COPY_ARG_TO_USER(arg,&flash_arg); + } + break; + } + case FLASH_GET_FAULT_REGISTERS: + { + err = ops->get_fault_registers(flash_p->priv_data,flash_arg.flash_mode,&flash_arg.status); + if(!err){ + COPY_ARG_TO_USER(arg,&flash_arg); + }else{ + DEBUG_LOG("unable to get supported modes for %s camera\n",my_name); + } + + break; + } + case FLASH_GET_SELF_TEST_RESULT: + { + COPY_ARG_TO_USER(arg,&flashArg); + DEBUG_LOG("FLASH_GET_SELF_TEST_RESULT arg : 0x%lx\n", flashArg.status); + break; + } + default: + DEBUG_LOG("Unknown command %x\n",cmd); + + } +out: + return err; +} + +int worker_thread (void* data) +{ + int err = 0; + struct flash_chip *flash_p=NULL; + struct flash_chip_ops *ops=NULL; + struct flash_mode_params params; + struct flash_mode_details details; + + while (1) + { + /* waiting for some job to do */ + wait_event_interruptible(waitQueue, (waitCondition != 0)); + waitCondition = 0; + + DEBUG_LOG("worker_thread wakes up\n"); + /* do we need to stop ? */ + err = kthread_should_stop(); + if (0 != err) + { + DEBUG_LOG("worker_thread stops\n"); + break; + } + + /* do the job */ + flash_p = flash_chips[flashArg.cam]; + ops = flash_p->ops; + + /* clear fault registers */ + err = ops->get_fault_registers(flash_p->priv_data, FLASH_MODE_INDICATOR, &flashArg.status); + if (0 != err) + { + flashArg.status = flashArg.flash_mode; + flashArg.flash_mode = 0; + } + flashArg.status = 0; + + /* do all selftests */ + while (flashArg.flash_mode != FLASH_SELFTEST_NONE) + { + if (0 != (flashArg.flash_mode & FLASH_SELFTEST_CONNECTION)) + { + err = ops->get_mode_details(flash_p->priv_data, FLASH_MODE_INDICATOR, &details); + if (0 != err) + { + DEBUG_LOG("not able to get mode FLASH_MODE_INDICATOR details\n"); + flashArg.status |= FLASH_SELFTEST_CONNECTION; + } + flashArg.flash_mode &= ~FLASH_SELFTEST_CONNECTION; + } + else if (0 != (flashArg.flash_mode & (FLASH_SELFTEST_FLASH | FLASH_SELFTEST_FLASH_WITH_STROBE))) + { + if (0 != (flashArg.flash_mode & FLASH_SELFTEST_FLASH)) + { + flashArg.status |= FLASH_SELFTEST_FLASH; + flashArg.flash_mode &= ~FLASH_SELFTEST_FLASH; + } + else + { + flashArg.status |= FLASH_SELFTEST_FLASH_WITH_STROBE; + flashArg.flash_mode &= ~FLASH_SELFTEST_FLASH_WITH_STROBE; + } + } + /* FLASH_SELFTEST_VIDEO_LIGHT | FLASH_SELFTEST_AF_LIGHT | FLASH_SELFTEST_INDICATOR | FLASH_SELFTEST_TORCH_LIGHT */ + else + { + unsigned long currentSelftest = FLASH_SELFTEST_NONE; + unsigned long currentFlashMode = FLASH_MODE_NONE; + + if (0 != (flashArg.flash_mode & FLASH_SELFTEST_VIDEO_LIGHT)) + { + currentSelftest = FLASH_SELFTEST_VIDEO_LIGHT; + currentFlashMode = FLASH_MODE_VIDEO_LED; + } + else if (0 != (flashArg.flash_mode & FLASH_SELFTEST_AF_LIGHT)) + { + currentSelftest = FLASH_SELFTEST_AF_LIGHT; + currentFlashMode = FLASH_MODE_AF_ASSISTANT; + } + else if (0 != (flashArg.flash_mode & FLASH_SELFTEST_INDICATOR)) + { + currentSelftest = FLASH_SELFTEST_INDICATOR; + currentFlashMode = FLASH_MODE_INDICATOR; + } + else + { + currentSelftest = FLASH_SELFTEST_TORCH_LIGHT; + currentFlashMode = FLASH_MODE_VIDEO_LED; + } + + err = ops->get_mode_details(flash_p->priv_data, currentFlashMode, &details); + if (0 != err) + { + DEBUG_LOG("not able to get mode 0x%lx details\n",currentFlashMode); + flashArg.status |= currentSelftest; + flashArg.flash_mode &= ~currentSelftest; + continue; + } + + err = ops->enable_flash_mode(flash_p->priv_data, currentFlashMode, 1); + if (0 != err) + { + DEBUG_LOG("not able to enable flash mode 0x%lx\n",currentFlashMode); + flashArg.status |= currentSelftest; + flashArg.flash_mode &= ~currentSelftest; + continue; + } + + params.duration_uSecs = 0; + params.intensity_uAmp = details.max_intensity_uAmp; + params.timeout_uSecs = 0; + err = ops->configure_flash_mode(flash_p->priv_data, currentFlashMode, ¶ms); + if (0 != err) + { + DEBUG_LOG("not able to configure flash mode 0x%lx\n",currentFlashMode); + flashArg.status |= currentSelftest; + flashArg.flash_mode &= ~currentSelftest; + continue; + } + + err = ops->trigger_strobe(flash_p->priv_data,1); + if (0 != err) + { + DEBUG_LOG("not able to strobe, mode : 0x%lx\n",currentFlashMode); + flashArg.status |= currentSelftest; + flashArg.flash_mode &= ~currentSelftest; + continue; + } + + wait_event_timeout(waitQueue, 0, msecs_to_jiffies(1000)); + + err = ops->trigger_strobe(flash_p->priv_data,0); + if (0 != err) + { + DEBUG_LOG("not able to strobe, mode : 0x%lx\n",currentFlashMode); + flashArg.status |= currentSelftest; + flashArg.flash_mode &= ~currentSelftest; + continue; + } + flashArg.flash_mode &= ~currentSelftest; + } + } + + /* job's done ! */ + flash_async_notify(); + } + return 0; +} + +int flash_open(struct inode *node, struct file *file_p) +{ + // init sleep queue + init_waitqueue_head(&waitQueue); + + // start worker thread + ptaskStruct = kthread_run (&worker_thread, NULL, "flashDriverWorker"); + + return 0; +} + +int register_flash_chip(unsigned int cam, struct flash_chip *flash_p) +{ + int err =0; + DEBUG_LOG("Registering cam %d\n", cam); + DEBUG_LOG("flash_p: name=%s\n", flash_p->name); + if(cam > 1 || !flash_p){ + DEBUG_LOG("Registration: something is wrong! cam %d, flash_p %x \n",cam,(int)flash_p); + err = EINVAL; + goto out; + } + if(!flash_chips[cam]){ + flash_chips[cam] = flash_p; + DEBUG_LOG("Registered flash: id %lx, %s for camera %d\n", + flash_p->id,flash_p->name,cam); + }else{ + DEBUG_LOG("%s flash already registered for camera %d, ignore flash %s\n", + flash_chips[cam]->name,cam, flash_p->name); + } +out: + return err; +} + +int flash_async_notify () +{ + kill_fasync(&async_queue, SIGIO, POLL_IN); + return 0; +} + +static int flash_fasync(int fd, struct file *filp, int mode) +{ + DEBUG_LOG("registered async notification on %d fd\n",fd); + return fasync_helper(fd, filp, mode, &async_queue); +} + +static int flash_release(struct inode *node, struct file *file_p) +{ + int err = 0; + + fasync_helper(-1, file_p, 0, &async_queue); + + // stop worker thread + waitCondition = 1; + err = kthread_stop(ptaskStruct); + return err; +} + +static struct file_operations flash_fops = { + owner:THIS_MODULE, + unlocked_ioctl:flash_ioctl, + open:flash_open, + release:flash_release, + fasync:flash_fasync, +}; + +int major_device_number; + +/*Temporary here (adp_init)*/ +extern int adp1653_init(void); +static int __init flash_init(void) +{ + int err = 0; + err = adp1653_init(); + if(err){ + DEBUG_LOG("Unable to initialize adp1653, err %d\n",err); + goto out; + } + /* Register misc device */ + misc_dev.minor = MISC_DYNAMIC_MINOR; + misc_dev.name = "camera_flash"; + misc_dev.fops = &flash_fops; + err = misc_register(&misc_dev); + if (err < 0) { + printk(KERN_INFO "camera_flash driver misc_register failed (%d)\n", err); + return err; + } else { + major_device_number = err; + printk(KERN_INFO "camera_flash driver initialized with minor=%d\n", misc_dev.minor); + } +out: + return err; +} + +static void __exit flash_exit(void) +{ + misc_deregister(&misc_dev); + printk(KERN_INFO"Camera flash driver unregistered\n"); +} + +module_init(flash_init); +module_exit(flash_exit); +MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(register_flash_chip); +EXPORT_SYMBOL(flash_async_notify); |