diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-09-22 19:54:53 (GMT) |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-09-22 20:01:40 (GMT) |
commit | ae19ffbadc1b2100285a5b5b3d0a4e0a11390904 (patch) | |
tree | 3c2086ab67398a019089a47ca3f362a4bc6db74f /drivers/staging/meilhaus/me1600_ao.c | |
parent | 34e84f39a27d059a3e6ec6e8b94aafa702e6f220 (diff) | |
parent | 9173a8ef24a6b1b8031507b35b8ffe5f85a87692 (diff) | |
download | linux-fsl-qoriq-ae19ffbadc1b2100285a5b5b3d0a4e0a11390904.tar.xz |
Merge branch 'master' into for-linus
Diffstat (limited to 'drivers/staging/meilhaus/me1600_ao.c')
-rw-r--r-- | drivers/staging/meilhaus/me1600_ao.c | 1017 |
1 files changed, 0 insertions, 1017 deletions
diff --git a/drivers/staging/meilhaus/me1600_ao.c b/drivers/staging/meilhaus/me1600_ao.c deleted file mode 100644 index 12e3c70..0000000 --- a/drivers/staging/meilhaus/me1600_ao.c +++ /dev/null @@ -1,1017 +0,0 @@ -/** - * @file me1600_ao.c - * - * @brief ME-1600 analog output subdevice instance. - * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) - * @author Guenter Gebhardt - * @author Krzysztof Gantzke (k.gantzke@meilhaus.de) - */ - -/* - * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __KERNEL__ -# define __KERNEL__ -#endif - -/* Includes - */ - -#include <linux/module.h> - -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <linux/io.h> -#include <linux/types.h> -#include <linux/sched.h> - -#include <linux/workqueue.h> - -#include "medefines.h" -#include "meinternal.h" -#include "meerror.h" -#include "medebug.h" - -#include "me1600_ao_reg.h" -#include "me1600_ao.h" - -/* Defines - */ - -static void me1600_ao_destructor(struct me_subdevice *subdevice); - -static void me1600_ao_work_control_task(struct work_struct *work); - -static int me1600_ao_io_reset_subdevice(me_subdevice_t *subdevice, - struct file *filep, int flags); -static int me1600_ao_io_single_config(me_subdevice_t *subdevice, - struct file *filep, int channel, - int single_config, int ref, int trig_chan, - int trig_type, int trig_edge, int flags); -static int me1600_ao_io_single_read(me_subdevice_t *subdevice, - struct file *filep, int channel, int *value, - int time_out, int flags); -static int me1600_ao_io_single_write(me_subdevice_t *subdevice, - struct file *filep, int channel, int value, - int time_out, int flags); -static int me1600_ao_query_number_channels(me_subdevice_t *subdevice, - int *number); -static int me1600_ao_query_subdevice_type(me_subdevice_t *subdevice, int *type, - int *subtype); -static int me1600_ao_query_subdevice_caps(me_subdevice_t *subdevice, - int *caps); -static int me1600_ao_query_range_by_min_max(me_subdevice_t *subdevice, - int unit, int *min, int *max, - int *maxdata, int *range); -static int me1600_ao_query_number_ranges(me_subdevice_t *subdevice, int unit, - int *count); -static int me1600_ao_query_range_info(me_subdevice_t *subdevice, int range, - int *unit, int *min, int *max, - int *maxdata); - -/* Functions - */ - -me1600_ao_subdevice_t *me1600_ao_constructor(uint32_t reg_base, - unsigned int ao_idx, - int curr, - spinlock_t *config_regs_lock, - spinlock_t *ao_shadows_lock, - me1600_ao_shadow_t *ao_regs_shadows, - struct workqueue_struct *me1600_wq) -{ - me1600_ao_subdevice_t *subdevice; - int err; - - PDEBUG("executed. idx=%d\n", ao_idx); - - // Allocate memory for subdevice instance. - subdevice = kmalloc(sizeof(me1600_ao_subdevice_t), GFP_KERNEL); - - if (!subdevice) { - PERROR - ("Cannot get memory for analog output subdevice instance.\n"); - return NULL; - } - - memset(subdevice, 0, sizeof(me1600_ao_subdevice_t)); - - // Initialize subdevice base class. - err = me_subdevice_init(&subdevice->base); - - if (err) { - PERROR("Cannot initialize subdevice base class instance.\n"); - kfree(subdevice); - return NULL; - } - // Initialize spin locks. - spin_lock_init(&subdevice->subdevice_lock); - subdevice->config_regs_lock = config_regs_lock; - subdevice->ao_shadows_lock = ao_shadows_lock; - - // Save the subdevice index. - subdevice->ao_idx = ao_idx; - - // Initialize range lists. - subdevice->u_ranges_count = 2; - - subdevice->u_ranges[0].min = 0; //0V - subdevice->u_ranges[0].max = 9997558; //10V - - subdevice->u_ranges[1].min = -10E6; //-10V - subdevice->u_ranges[1].max = 9995117; //10V - - if (curr) { // This is version with current outputs. - subdevice->i_ranges_count = 2; - - subdevice->i_ranges[0].min = 0; //0mA - subdevice->i_ranges[0].max = 19995117; //20mA - - subdevice->i_ranges[1].min = 4E3; //4mA - subdevice->i_ranges[1].max = 19995118; //20mA - } else { // This is version without current outputs. - subdevice->i_ranges_count = 0; - - subdevice->i_ranges[0].min = 0; //0mA - subdevice->i_ranges[0].max = 0; //0mA - - subdevice->i_ranges[1].min = 0; //0mA - subdevice->i_ranges[1].max = 0; //0mA - } - - // Initialize registers. - subdevice->uni_bi_reg = reg_base + ME1600_UNI_BI_REG; - subdevice->i_range_reg = reg_base + ME1600_020_420_REG; - subdevice->sim_output_reg = reg_base + ME1600_SIM_OUTPUT_REG; - subdevice->current_on_reg = reg_base + ME1600_CURRENT_ON_REG; -#ifdef MEDEBUG_DEBUG_REG - subdevice->reg_base = reg_base; -#endif - - // Initialize shadow structure. - subdevice->ao_regs_shadows = ao_regs_shadows; - - // Override base class methods. - subdevice->base.me_subdevice_destructor = me1600_ao_destructor; - subdevice->base.me_subdevice_io_reset_subdevice = - me1600_ao_io_reset_subdevice; - subdevice->base.me_subdevice_io_single_config = - me1600_ao_io_single_config; - subdevice->base.me_subdevice_io_single_read = me1600_ao_io_single_read; - subdevice->base.me_subdevice_io_single_write = - me1600_ao_io_single_write; - subdevice->base.me_subdevice_query_number_channels = - me1600_ao_query_number_channels; - subdevice->base.me_subdevice_query_subdevice_type = - me1600_ao_query_subdevice_type; - subdevice->base.me_subdevice_query_subdevice_caps = - me1600_ao_query_subdevice_caps; - subdevice->base.me_subdevice_query_range_by_min_max = - me1600_ao_query_range_by_min_max; - subdevice->base.me_subdevice_query_number_ranges = - me1600_ao_query_number_ranges; - subdevice->base.me_subdevice_query_range_info = - me1600_ao_query_range_info; - - // Initialize wait queue. - init_waitqueue_head(&subdevice->wait_queue); - - // Prepare work queue. - subdevice->me1600_workqueue = me1600_wq; - -/* workqueue API changed in kernel 2.6.20 */ - INIT_DELAYED_WORK(&subdevice->ao_control_task, - me1600_ao_work_control_task); - return subdevice; -} - -static void me1600_ao_destructor(struct me_subdevice *subdevice) -{ - me1600_ao_subdevice_t *instance; - - instance = (me1600_ao_subdevice_t *) subdevice; - - PDEBUG("executed. idx=%d\n", instance->ao_idx); - - instance->ao_control_task_flag = 0; - - // Reset subdevice to asure clean exit. - me1600_ao_io_reset_subdevice(subdevice, NULL, - ME_IO_RESET_SUBDEVICE_NO_FLAGS); - - // Remove any tasks from work queue. This is paranoic because it was done allready in reset(). - if (!cancel_delayed_work(&instance->ao_control_task)) { //Wait 2 ticks to be sure that control task is removed from queue. - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(2); - } -} - -static int me1600_ao_io_reset_subdevice(me_subdevice_t *subdevice, - struct file *filep, int flags) -{ - me1600_ao_subdevice_t *instance; - uint16_t tmp; - - instance = (me1600_ao_subdevice_t *) subdevice; - - PDEBUG("executed. idx=%d\n", instance->ao_idx); - - if (flags) { - PERROR("Invalid flag specified.\n"); - return ME_ERRNO_INVALID_FLAGS; - } - - ME_SUBDEVICE_ENTER; - - //Cancel control task - PDEBUG("Cancel control task. idx=%d\n", instance->ao_idx); - instance->ao_control_task_flag = 0; - cancel_delayed_work(&instance->ao_control_task); - (instance->ao_regs_shadows)->trigger &= ~(0x1 << instance->ao_idx); //Cancell waiting for trigger. - - // Reset all settings. - spin_lock(&instance->subdevice_lock); - spin_lock(instance->ao_shadows_lock); - (instance->ao_regs_shadows)->shadow[instance->ao_idx] = 0; - (instance->ao_regs_shadows)->mirror[instance->ao_idx] = 0; - (instance->ao_regs_shadows)->trigger &= ~(0x1 << instance->ao_idx); //Not waiting for triggering. - (instance->ao_regs_shadows)->synchronous &= ~(0x1 << instance->ao_idx); //Individual triggering. - - // Set output to default (safe) state. - spin_lock(instance->config_regs_lock); - tmp = inw(instance->uni_bi_reg); // unipolar - tmp |= (0x1 << instance->ao_idx); - outw(tmp, instance->uni_bi_reg); - PDEBUG_REG("uni_bi_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base, - instance->uni_bi_reg - instance->reg_base, tmp); - - tmp = inw(instance->current_on_reg); // Volts only! - tmp &= ~(0x1 << instance->ao_idx); - tmp &= 0x00FF; - outw(tmp, instance->current_on_reg); - PDEBUG_REG("current_on_reg outl(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->current_on_reg - instance->reg_base, tmp); - - tmp = inw(instance->i_range_reg); // 0..20mA <= If exists. - tmp &= ~(0x1 << instance->ao_idx); - outw(tmp, instance->i_range_reg); - PDEBUG_REG("i_range_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base, - instance->i_range_reg - instance->reg_base, tmp); - - outw(0, (instance->ao_regs_shadows)->registry[instance->ao_idx]); - PDEBUG_REG("channel_reg outw(0x%lX+0x%lX)=0x%x\n", instance->reg_base, - (instance->ao_regs_shadows)->registry[instance->ao_idx] - - instance->reg_base, 0); - - // Trigger output. - outw(0x0000, instance->sim_output_reg); - PDEBUG_REG("sim_output_reg outl(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->sim_output_reg - instance->reg_base, 0x0000); - outw(0xFFFF, instance->sim_output_reg); - PDEBUG_REG("sim_output_reg outl(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->sim_output_reg - instance->reg_base, 0xFFFF); - spin_unlock(instance->config_regs_lock); - spin_unlock(instance->ao_shadows_lock); - - // Set status to 'none' - instance->status = ao_status_none; - spin_unlock(&instance->subdevice_lock); - - //Signal reset if user is on wait. - wake_up_interruptible_all(&instance->wait_queue); - - ME_SUBDEVICE_EXIT; - - return ME_ERRNO_SUCCESS; -} - -static int me1600_ao_io_single_config(me_subdevice_t *subdevice, - struct file *filep, - int channel, - int single_config, - int ref, - int trig_chan, - int trig_type, int trig_edge, int flags) -{ - me1600_ao_subdevice_t *instance; - uint16_t tmp; - - instance = (me1600_ao_subdevice_t *) subdevice; - - PDEBUG("executed. idx=%d\n", instance->ao_idx); - - // Checking parameters. - if (flags) { - PERROR - ("Invalid flag specified. Must be ME_IO_SINGLE_CONFIG_NO_FLAGS.\n"); - return ME_ERRNO_INVALID_FLAGS; - } - - if (trig_edge != ME_TRIG_EDGE_NONE) { - PERROR - ("Invalid trigger edge. Software trigger has not edge. Must be ME_TRIG_EDGE_NONE\n"); - return ME_ERRNO_INVALID_TRIG_EDGE; - } - - if (trig_type != ME_TRIG_TYPE_SW) { - PERROR("Invalid trigger edge. Must be ME_TRIG_TYPE_SW.\n"); - return ME_ERRNO_INVALID_TRIG_TYPE; - } - - if ((trig_chan != ME_TRIG_CHAN_DEFAULT) - && (trig_chan != ME_TRIG_CHAN_SYNCHRONOUS)) { - PERROR("Invalid trigger channel specified.\n"); - return ME_ERRNO_INVALID_TRIG_CHAN; - } - - if (ref != ME_REF_AO_GROUND) { - PERROR - ("Invalid reference. Analog outputs have to have got REF_AO_GROUND.\n"); - return ME_ERRNO_INVALID_REF; - } - - if (((single_config + 1) > - (instance->u_ranges_count + instance->i_ranges_count)) - || (single_config < 0)) { - PERROR("Invalid range specified.\n"); - return ME_ERRNO_INVALID_SINGLE_CONFIG; - } - - if (channel) { - PERROR("Invalid channel specified.\n"); - return ME_ERRNO_INVALID_CHANNEL; - } - // Checking parameters - done. All is fine. Do config. - - ME_SUBDEVICE_ENTER; - - //Cancel control task - PDEBUG("Cancel control task. idx=%d\n", instance->ao_idx); - instance->ao_control_task_flag = 0; - cancel_delayed_work(&instance->ao_control_task); - - spin_lock(&instance->subdevice_lock); - spin_lock(instance->ao_shadows_lock); - (instance->ao_regs_shadows)->trigger &= ~(0x1 << instance->ao_idx); //Cancell waiting for trigger. - (instance->ao_regs_shadows)->shadow[instance->ao_idx] = 0; - (instance->ao_regs_shadows)->mirror[instance->ao_idx] = 0; - - spin_lock(instance->config_regs_lock); - switch (single_config) { - case 0: // 0V 10V - tmp = inw(instance->current_on_reg); // Volts - tmp &= ~(0x1 << instance->ao_idx); - outw(tmp, instance->current_on_reg); - PDEBUG_REG("current_on_reg outw(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->current_on_reg - instance->reg_base, tmp); - - // 0V - outw(0, - (instance->ao_regs_shadows)->registry[instance->ao_idx]); - PDEBUG_REG("channel_reg outw(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - (instance->ao_regs_shadows)->registry[instance-> - ao_idx] - - instance->reg_base, 0); - - tmp = inw(instance->uni_bi_reg); // unipolar - tmp |= (0x1 << instance->ao_idx); - outw(tmp, instance->uni_bi_reg); - PDEBUG_REG("uni_bi_reg outw(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->uni_bi_reg - instance->reg_base, tmp); - - tmp = inw(instance->i_range_reg); // 0..20mA <= If exists. - tmp &= ~(0x1 << instance->ao_idx); - outw(tmp, instance->i_range_reg); - PDEBUG_REG("i_range_reg outl(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->i_range_reg - instance->reg_base, tmp); - break; - - case 1: // -10V 10V - tmp = inw(instance->current_on_reg); // Volts - tmp &= ~(0x1 << instance->ao_idx); - outw(tmp, instance->current_on_reg); - PDEBUG_REG("current_on_reg outw(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->current_on_reg - instance->reg_base, tmp); - - // 0V - outw(0x0800, - (instance->ao_regs_shadows)->registry[instance->ao_idx]); - PDEBUG_REG("channel_reg outw(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - (instance->ao_regs_shadows)->registry[instance-> - ao_idx] - - instance->reg_base, 0x0800); - - tmp = inw(instance->uni_bi_reg); // bipolar - tmp &= ~(0x1 << instance->ao_idx); - outw(tmp, instance->uni_bi_reg); - PDEBUG_REG("uni_bi_reg outw(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->uni_bi_reg - instance->reg_base, tmp); - - tmp = inw(instance->i_range_reg); // 0..20mA <= If exists. - tmp &= ~(0x1 << instance->ao_idx); - outw(tmp, instance->i_range_reg); - PDEBUG_REG("i_range_reg outl(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->i_range_reg - instance->reg_base, tmp); - break; - - case 2: // 0mA 20mA - tmp = inw(instance->current_on_reg); // mAmpers - tmp |= (0x1 << instance->ao_idx); - outw(tmp, instance->current_on_reg); - PDEBUG_REG("current_on_reg outw(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->current_on_reg - instance->reg_base, tmp); - - tmp = inw(instance->i_range_reg); // 0..20mA - tmp &= ~(0x1 << instance->ao_idx); - outw(tmp, instance->i_range_reg); - PDEBUG_REG("i_range_reg outl(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->i_range_reg - instance->reg_base, tmp); - - // 0mA - outw(0, - (instance->ao_regs_shadows)->registry[instance->ao_idx]); - PDEBUG_REG("channel_reg outw(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - (instance->ao_regs_shadows)->registry[instance-> - ao_idx] - - instance->reg_base, 0); - - tmp = inw(instance->uni_bi_reg); // unipolar - tmp |= (0x1 << instance->ao_idx); - outw(tmp, instance->uni_bi_reg); - PDEBUG_REG("uni_bi_reg outw(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->uni_bi_reg - instance->reg_base, tmp); - break; - - case 3: // 4mA 20mA - tmp = inw(instance->current_on_reg); // mAmpers - tmp |= (0x1 << instance->ao_idx); - outw(tmp, instance->current_on_reg); - PDEBUG_REG("current_on_reg outw(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->current_on_reg - instance->reg_base, tmp); - - tmp = inw(instance->i_range_reg); // 4..20mA - tmp |= (0x1 << instance->ao_idx); - outw(tmp, instance->i_range_reg); - PDEBUG_REG("i_range_reg outl(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->i_range_reg - instance->reg_base, tmp); - - // 4mA - outw(0, - (instance->ao_regs_shadows)->registry[instance->ao_idx]); - PDEBUG_REG("channel_reg outw(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - (instance->ao_regs_shadows)->registry[instance-> - ao_idx] - - instance->reg_base, 0); - - tmp = inw(instance->uni_bi_reg); // unipolar - tmp |= (0x1 << instance->ao_idx); - outw(tmp, instance->uni_bi_reg); - PDEBUG_REG("uni_bi_reg outw(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->uni_bi_reg - instance->reg_base, tmp); - break; - } - - // Trigger output. - outw(0x0000, instance->sim_output_reg); - PDEBUG_REG("sim_output_reg outl(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->sim_output_reg - instance->reg_base, 0x0000); - outw(0xFFFF, instance->sim_output_reg); - PDEBUG_REG("sim_output_reg outl(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->sim_output_reg - instance->reg_base, 0xFFFF); - - if (trig_chan == ME_TRIG_CHAN_DEFAULT) { // Individual triggering. - (instance->ao_regs_shadows)->synchronous &= - ~(0x1 << instance->ao_idx); - PDEBUG("Individual triggering.\n"); - } else if (trig_chan == ME_TRIG_CHAN_SYNCHRONOUS) { // Synchronous triggering. - (instance->ao_regs_shadows)->synchronous |= - (0x1 << instance->ao_idx); - PDEBUG("Synchronous triggering.\n"); - } - spin_unlock(instance->config_regs_lock); - spin_unlock(instance->ao_shadows_lock); - - instance->status = ao_status_single_configured; - spin_unlock(&instance->subdevice_lock); - - ME_SUBDEVICE_EXIT; - - return ME_ERRNO_SUCCESS; -} - -static int me1600_ao_io_single_read(me_subdevice_t *subdevice, - struct file *filep, - int channel, - int *value, int time_out, int flags) -{ - me1600_ao_subdevice_t *instance; - unsigned long delay = 0; - unsigned long j = 0; - int err = ME_ERRNO_SUCCESS; - - instance = (me1600_ao_subdevice_t *) subdevice; - - PDEBUG("executed. idx=%d\n", instance->ao_idx); - - if (flags & ~ME_IO_SINGLE_NONBLOCKING) { - PERROR("Invalid flag specified. %d\n", flags); - return ME_ERRNO_INVALID_FLAGS; - } - - if (time_out < 0) { - PERROR("Invalid timeout specified.\n"); - return ME_ERRNO_INVALID_TIMEOUT; - } - - if (channel) { - PERROR("Invalid channel specified.\n"); - return ME_ERRNO_INVALID_CHANNEL; - } - - if ((!flags) && ((instance->ao_regs_shadows)->trigger & instance->ao_idx)) { //Blocking mode. Wait for software trigger. - if (time_out) { - delay = (time_out * HZ) / 1000; - if (delay == 0) - delay = 1; - } - - j = jiffies; - - //Only runing process will interrupt this call. Events are signaled when status change. This procedure has own timeout. - wait_event_interruptible_timeout(instance->wait_queue, - (!((instance-> - ao_regs_shadows)-> - trigger & instance-> - ao_idx)), - (delay) ? delay : LONG_MAX); - - if (instance == ao_status_none) { // Reset was called. - PDEBUG("Single canceled.\n"); - err = ME_ERRNO_CANCELLED; - } - - if (signal_pending(current)) { - PERROR("Wait on start of state machine interrupted.\n"); - err = ME_ERRNO_SIGNAL; - } - - if ((delay) && ((jiffies - j) >= delay)) { - PDEBUG("Timeout reached.\n"); - err = ME_ERRNO_TIMEOUT; - } - } - - *value = (instance->ao_regs_shadows)->mirror[instance->ao_idx]; - - return err; -} - -static int me1600_ao_io_single_write(me_subdevice_t *subdevice, - struct file *filep, - int channel, - int value, int time_out, int flags) -{ - me1600_ao_subdevice_t *instance; - int err = ME_ERRNO_SUCCESS; - unsigned long delay = 0; - int i; - unsigned long j = 0; - - instance = (me1600_ao_subdevice_t *) subdevice; - - PDEBUG("executed. idx=%d\n", instance->ao_idx); - - if (flags & - ~(ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS | - ME_IO_SINGLE_TYPE_WRITE_NONBLOCKING)) { - PERROR("Invalid flag specified.\n"); - return ME_ERRNO_INVALID_FLAGS; - } - - if (time_out < 0) { - PERROR("Invalid timeout specified.\n"); - return ME_ERRNO_INVALID_TIMEOUT; - } - - if (value & ~ME1600_AO_MAX_DATA) { - PERROR("Invalid value provided.\n"); - return ME_ERRNO_VALUE_OUT_OF_RANGE; - } - - if (channel) { - PERROR("Invalid channel specified.\n"); - return ME_ERRNO_INVALID_CHANNEL; - } - - ME_SUBDEVICE_ENTER; - - //Cancel control task - PDEBUG("Cancel control task. idx=%d\n", instance->ao_idx); - instance->ao_control_task_flag = 0; - cancel_delayed_work(&instance->ao_control_task); - (instance->ao_regs_shadows)->trigger &= ~(0x1 << instance->ao_idx); //Cancell waiting for trigger. - - if (time_out) { - delay = (time_out * HZ) / 1000; - - if (delay == 0) - delay = 1; - } - //Write value. - spin_lock(instance->ao_shadows_lock); - (instance->ao_regs_shadows)->shadow[instance->ao_idx] = - (uint16_t) value; - - if (flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS) { // Trigger all outputs from synchronous list. - for (i = 0; i < (instance->ao_regs_shadows)->count; i++) { - if (((instance->ao_regs_shadows)->synchronous & (0x1 << i)) || (i == instance->ao_idx)) { // Set all from synchronous list to correct state. - PDEBUG - ("Synchronous triggering: output %d. idx=%d\n", - i, instance->ao_idx); - (instance->ao_regs_shadows)->mirror[i] = - (instance->ao_regs_shadows)->shadow[i]; - - outw((instance->ao_regs_shadows)->shadow[i], - (instance->ao_regs_shadows)->registry[i]); - PDEBUG_REG - ("channel_reg outw(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - (instance->ao_regs_shadows)->registry[i] - - instance->reg_base, - (instance->ao_regs_shadows)->shadow[i]); - - (instance->ao_regs_shadows)->trigger &= - ~(0x1 << i); - } - } - - // Trigger output. - outw(0x0000, instance->sim_output_reg); - PDEBUG_REG("sim_output_reg outl(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->sim_output_reg - instance->reg_base, 0); - outw(0xFFFF, instance->sim_output_reg); - PDEBUG_REG("sim_output_reg outl(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->sim_output_reg - instance->reg_base, - 0xFFFF); - instance->status = ao_status_single_end; - } else { // Individual mode. - if ((instance->ao_regs_shadows)->synchronous & (0x1 << instance->ao_idx)) { // Put on synchronous start list. Set output as waiting for trigger. - PDEBUG("Add to synchronous list. idx=%d\n", - instance->ao_idx); - (instance->ao_regs_shadows)->trigger |= - (0x1 << instance->ao_idx); - instance->status = ao_status_single_run; - PDEBUG("Synchronous list: 0x%x.\n", - (instance->ao_regs_shadows)->synchronous); - } else { // Fired this one. - PDEBUG("Triggering. idx=%d\n", instance->ao_idx); - (instance->ao_regs_shadows)->mirror[instance->ao_idx] = - (instance->ao_regs_shadows)->shadow[instance-> - ao_idx]; - - outw((instance->ao_regs_shadows)-> - shadow[instance->ao_idx], - (instance->ao_regs_shadows)->registry[instance-> - ao_idx]); - PDEBUG_REG("channel_reg outw(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - (instance->ao_regs_shadows)-> - registry[instance->ao_idx] - - instance->reg_base, - (instance->ao_regs_shadows)-> - shadow[instance->ao_idx]); - - // Set output as triggered. - (instance->ao_regs_shadows)->trigger &= - ~(0x1 << instance->ao_idx); - - // Trigger output. - outw(0x0000, instance->sim_output_reg); - PDEBUG_REG("sim_output_reg outl(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->sim_output_reg - - instance->reg_base, 0); - outw(0xFFFF, instance->sim_output_reg); - PDEBUG_REG("sim_output_reg outl(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - instance->sim_output_reg - - instance->reg_base, 0xFFFF); - instance->status = ao_status_single_end; - } - } - spin_unlock(instance->ao_shadows_lock); - - //Init control task - instance->timeout.delay = delay; - instance->timeout.start_time = jiffies; - instance->ao_control_task_flag = 1; - queue_delayed_work(instance->me1600_workqueue, - &instance->ao_control_task, 1); - - if ((!(flags & ME_IO_SINGLE_TYPE_WRITE_NONBLOCKING)) && - ((instance->ao_regs_shadows)->trigger & instance->ao_idx)) { - /* Blocking mode. Wait for software trigger. */ - if (time_out) { - delay = (time_out * HZ) / 1000; - if (delay == 0) - delay = 1; - } - - j = jiffies; - - //Only runing process will interrupt this call. Events are signaled when status change. This procedure has own timeout. - wait_event_interruptible_timeout(instance->wait_queue, - (!((instance-> - ao_regs_shadows)-> - trigger & instance-> - ao_idx)), - (delay) ? delay : LONG_MAX); - - if (instance == ao_status_none) { - PDEBUG("Single canceled.\n"); - err = ME_ERRNO_CANCELLED; - } - if (signal_pending(current)) { - PERROR("Wait on start of state machine interrupted.\n"); - err = ME_ERRNO_SIGNAL; - } - - if ((delay) && ((jiffies - j) >= delay)) { - PDEBUG("Timeout reached.\n"); - err = ME_ERRNO_TIMEOUT; - } - } - - ME_SUBDEVICE_EXIT; - - return err; -} - -static int me1600_ao_query_number_channels(me_subdevice_t *subdevice, - int *number) -{ - me1600_ao_subdevice_t *instance; - instance = (me1600_ao_subdevice_t *) subdevice; - - PDEBUG("executed. idx=%d\n", instance->ao_idx); - - *number = 1; //Every subdevice has only 1 channel. - return ME_ERRNO_SUCCESS; -} - -static int me1600_ao_query_subdevice_type(me_subdevice_t *subdevice, int *type, - int *subtype) -{ - me1600_ao_subdevice_t *instance; - instance = (me1600_ao_subdevice_t *) subdevice; - - PDEBUG("executed. idx=%d\n", instance->ao_idx); - - *type = ME_TYPE_AO; - *subtype = ME_SUBTYPE_SINGLE; - return ME_ERRNO_SUCCESS; -} - -static int me1600_ao_query_subdevice_caps(me_subdevice_t *subdevice, int *caps) -{ - PDEBUG("executed.\n"); - *caps = ME_CAPS_AO_TRIG_SYNCHRONOUS; - return ME_ERRNO_SUCCESS; -} - -static int me1600_ao_query_range_by_min_max(me_subdevice_t *subdevice, - int unit, - int *min, - int *max, int *maxdata, int *range) -{ - me1600_ao_subdevice_t *instance; - int i; - int r = -1; - int diff = 21E6; - - instance = (me1600_ao_subdevice_t *) subdevice; - - PDEBUG("executed. idx=%d\n", instance->ao_idx); - - if ((*max - *min) < 0) { - PERROR("Invalid minimum and maximum values specified.\n"); - return ME_ERRNO_INVALID_MIN_MAX; - } - // Maximum ranges are slightly less then 10V or 20mA. For convenient we accepted this value as valid one. - if (unit == ME_UNIT_VOLT) { - for (i = 0; i < instance->u_ranges_count; i++) { - if ((instance->u_ranges[i].min <= *min) - && ((instance->u_ranges[i].max + 5000) >= *max)) { - if ((instance->u_ranges[i].max - - instance->u_ranges[i].min) - (*max - - *min) < - diff) { - r = i; - diff = - (instance->u_ranges[i].max - - instance->u_ranges[i].min) - - (*max - *min); - } - } - } - - if (r < 0) { - PERROR("No matching range found.\n"); - return ME_ERRNO_NO_RANGE; - } else { - *min = instance->u_ranges[r].min; - *max = instance->u_ranges[r].max; - *range = r; - } - } else if (unit == ME_UNIT_AMPERE) { - for (i = 0; i < instance->i_ranges_count; i++) { - if ((instance->i_ranges[i].min <= *min) - && (instance->i_ranges[i].max + 5000 >= *max)) { - if ((instance->i_ranges[i].max - - instance->i_ranges[i].min) - (*max - - *min) < - diff) { - r = i; - diff = - (instance->i_ranges[i].max - - instance->i_ranges[i].min) - - (*max - *min); - } - } - } - - if (r < 0) { - PERROR("No matching range found.\n"); - return ME_ERRNO_NO_RANGE; - } else { - *min = instance->i_ranges[r].min; - *max = instance->i_ranges[r].max; - *range = r + instance->u_ranges_count; - } - } else { - PERROR("Invalid physical unit specified.\n"); - return ME_ERRNO_INVALID_UNIT; - } - *maxdata = ME1600_AO_MAX_DATA; - - return ME_ERRNO_SUCCESS; -} - -static int me1600_ao_query_number_ranges(me_subdevice_t *subdevice, - int unit, int *count) -{ - me1600_ao_subdevice_t *instance; - - PDEBUG("executed.\n"); - - instance = (me1600_ao_subdevice_t *) subdevice; - switch (unit) { - case ME_UNIT_VOLT: - *count = instance->u_ranges_count; - break; - case ME_UNIT_AMPERE: - *count = instance->i_ranges_count; - break; - case ME_UNIT_ANY: - *count = instance->u_ranges_count + instance->i_ranges_count; - break; - default: - *count = 0; - } - - return ME_ERRNO_SUCCESS; -} - -static int me1600_ao_query_range_info(me_subdevice_t *subdevice, - int range, - int *unit, - int *min, int *max, int *maxdata) -{ - me1600_ao_subdevice_t *instance; - - PDEBUG("executed.\n"); - - instance = (me1600_ao_subdevice_t *) subdevice; - - if (((range + 1) > - (instance->u_ranges_count + instance->i_ranges_count)) - || (range < 0)) { - PERROR("Invalid range number specified.\n"); - return ME_ERRNO_INVALID_RANGE; - } - - if (range < instance->u_ranges_count) { - *unit = ME_UNIT_VOLT; - *min = instance->u_ranges[range].min; - *max = instance->u_ranges[range].max; - } else if (range < instance->u_ranges_count + instance->i_ranges_count) { - *unit = ME_UNIT_AMPERE; - *min = instance->i_ranges[range - instance->u_ranges_count].min; - *max = instance->i_ranges[range - instance->u_ranges_count].max; - } - *maxdata = ME1600_AO_MAX_DATA; - - return ME_ERRNO_SUCCESS; -} - -static void me1600_ao_work_control_task(struct work_struct *work) -{ - me1600_ao_subdevice_t *instance; - int reschedule = 1; - int signaling = 0; - - instance = - container_of((void *)work, me1600_ao_subdevice_t, ao_control_task); - - PINFO("<%s: %ld> executed. idx=%d\n", __func__, jiffies, - instance->ao_idx); - - if (!((instance->ao_regs_shadows)->trigger & instance->ao_idx)) { // Output was triggerd. - // Signal the end. - signaling = 1; - reschedule = 0; - if (instance->status == ao_status_single_run) { - instance->status = ao_status_single_end; - } - - } else if ((instance->timeout.delay) && ((jiffies - instance->timeout.start_time) >= instance->timeout.delay)) { // Timeout - PDEBUG("Timeout reached.\n"); - spin_lock(instance->ao_shadows_lock); - // Restore old settings. - PDEBUG("Write old value back to register.\n"); - (instance->ao_regs_shadows)->shadow[instance->ao_idx] = - (instance->ao_regs_shadows)->mirror[instance->ao_idx]; - - outw((instance->ao_regs_shadows)->mirror[instance->ao_idx], - (instance->ao_regs_shadows)->registry[instance->ao_idx]); - PDEBUG_REG("channel_reg outw(0x%lX+0x%lX)=0x%x\n", - instance->reg_base, - (instance->ao_regs_shadows)->registry[instance-> - ao_idx] - - instance->reg_base, - (instance->ao_regs_shadows)->mirror[instance-> - ao_idx]); - - //Remove from synchronous strt list. - (instance->ao_regs_shadows)->trigger &= - ~(0x1 << instance->ao_idx); - if (instance->status == ao_status_none) { - instance->status = ao_status_single_end; - } - spin_unlock(instance->ao_shadows_lock); - - // Signal the end. - signaling = 1; - reschedule = 0; - } - - if (signaling) { //Signal it. - wake_up_interruptible_all(&instance->wait_queue); - } - - if (instance->ao_control_task_flag && reschedule) { // Reschedule task - queue_delayed_work(instance->me1600_workqueue, - &instance->ao_control_task, 1); - } else { - PINFO("<%s> Ending control task.\n", __func__); - } - -} |