static int ucb1x00_ts_open(struct input_dev *idev) { struct ucb1x00_ts *ts = input_get_drvdata(idev); int ret = 0; BUG_ON(ts->rtask); init_waitqueue_head(&ts->irq_wait); ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts); if (ret < 0) goto out; /* * If we do this at all, we should allow the user to * measure and read the X and Y resistance at any time. */ ucb1x00_adc_enable(ts->ucb); ts->x_res = ucb1x00_ts_read_xres(ts); ts->y_res = ucb1x00_ts_read_yres(ts); ucb1x00_adc_disable(ts->ucb); ts->rtask = kthread_run(ucb1x00_thread, ts, "ktsd"); if (!IS_ERR(ts->rtask)) { ret = 0; } else { ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); ts->rtask = NULL; ret = -EFAULT; } out: return ret; }
/* * Initialisation. */ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) { struct ucb1x00_ts *ts; struct input_dev *idev; int err; ts = kzalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL); idev = input_allocate_device(); if (!ts || !idev) { err = -ENOMEM; goto fail; } ts->ucb = dev->ucb; ts->idev = idev; ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; idev->name = "Touchscreen panel"; idev->id.product = ts->ucb->id; idev->open = ucb1x00_ts_open; idev->close = ucb1x00_ts_close; idev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); input_set_drvdata(idev, ts); ucb1x00_adc_enable(ts->ucb); ts->x_res = ucb1x00_ts_read_xres(ts); ts->y_res = ucb1x00_ts_read_yres(ts); ucb1x00_adc_disable(ts->ucb); input_set_abs_params(idev, ABS_X, 0, ts->x_res, 0, 0); input_set_abs_params(idev, ABS_Y, 0, ts->y_res, 0, 0); input_set_abs_params(idev, ABS_PRESSURE, 0, 0, 0, 0); err = input_register_device(idev); if (err) goto fail; dev->priv = ts; return 0; fail: input_free_device(idev); kfree(ts); return err; }
int collie_read_backup_battery(void) { int voltage; ucb1x00_adc_enable(ucb); ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_BBAT_ON, 0); voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD1, UCB_SYNC); ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_BBAT_ON); ucb1x00_adc_disable(ucb); printk("Backup battery = %d(%d)\n", ADCtoPower(voltage), voltage); return ADCtoPower(voltage); }
int collie_read_temp(void) { int voltage; /* According to Sharp, temp must be > 973, main battery must be < 465, FIXME: sharpsl_pm.c has both conditions negated? FIXME: values are way out of range? */ ucb1x00_adc_enable(ucb); ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0); /* >1010 = battery removed, 460 = 22C ?, higer = lower temp ? */ voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD0, UCB_SYNC); ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON); ucb1x00_adc_disable(ucb); printk("Battery temp = %d\n", voltage); return voltage; }
static unsigned long collie_read_bat(struct collie_bat *bat) { unsigned long value = 0; if (bat->gpio_bat < 0 || bat->adc_bat < 0) return 0; mutex_lock(&bat_lock); gpio_set_value(bat->gpio_bat, 1); msleep(5); ucb1x00_adc_enable(ucb); value = ucb1x00_adc_read(ucb, bat->adc_bat, UCB_SYNC); ucb1x00_adc_disable(ucb); gpio_set_value(bat->gpio_bat, 0); mutex_unlock(&bat_lock); value = value * 1000000 / bat->adc_bat_divider; return value; }
int collie_read_main_battery(void) { int voltage, voltage_rev, voltage_volts; ucb1x00_adc_enable(ucb); ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_BBAT_ON); ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_MBAT_ON, 0); mdelay(1); voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD1, UCB_SYNC); ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_MBAT_ON); ucb1x00_adc_disable(ucb); voltage_rev = voltage + ((ad_revise * voltage) / 652); voltage_volts = ADCtoPower(voltage_rev); printk("Main battery = %d(%d)\n", voltage_volts, voltage); if (voltage != -1) return voltage_volts; else return voltage; }
/* * This is a RT kernel thread that handles the ADC accesses * (mainly so we can use semaphores in the UCB1200 core code * to serialise accesses to the ADC). */ static int ucb1x00_thread(void *_ts) { struct ucb1x00_ts *ts = _ts; DECLARE_WAITQUEUE(wait, current); int valid = 0; set_freezable(); add_wait_queue(&ts->irq_wait, &wait); while (!kthread_should_stop()) { unsigned int x, y, p; signed long timeout; ts->restart = 0; ucb1x00_adc_enable(ts->ucb); x = ucb1x00_ts_read_xpos(ts); y = ucb1x00_ts_read_ypos(ts); p = ucb1x00_ts_read_pressure(ts); /* * Switch back to interrupt mode. */ ucb1x00_ts_mode_int(ts); ucb1x00_adc_disable(ts->ucb); msleep(10); ucb1x00_enable(ts->ucb); if (ucb1x00_ts_pen_down(ts)) { set_current_state(TASK_INTERRUPTIBLE); ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING); ucb1x00_disable(ts->ucb); /* * If we spat out a valid sample set last time, * spit out a "pen off" sample here. */ if (valid) { ucb1x00_ts_event_release(ts); valid = 0; } timeout = MAX_SCHEDULE_TIMEOUT; } else { ucb1x00_disable(ts->ucb); /* * Filtering is policy. Policy belongs in user * space. We therefore leave it to user space * to do any filtering they please. */ if (!ts->restart) { ucb1x00_ts_evt_add(ts, p, x, y); valid = 1; } set_current_state(TASK_INTERRUPTIBLE); timeout = HZ / 100; } try_to_freeze(); schedule_timeout(timeout); } remove_wait_queue(&ts->irq_wait, &wait); ts->rtask = NULL; return 0; }