Path: blob/master/drivers/media/video/cx18/cx18-gpio.c
17701 views
/*1* cx18 gpio functions2*3* Derived from ivtv-gpio.c4*5* Copyright (C) 2007 Hans Verkuil <[email protected]>6* Copyright (C) 2008 Andy Walls <[email protected]>7*8* This program is free software; you can redistribute it and/or modify9* it under the terms of the GNU General Public License as published by10* the Free Software Foundation; either version 2 of the License, or11* (at your option) any later version.12*13* This program is distributed in the hope that it will be useful,14* but WITHOUT ANY WARRANTY; without even the implied warranty of15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16* GNU General Public License for more details.17*18* You should have received a copy of the GNU General Public License19* along with this program; if not, write to the Free Software20* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA21* 02111-1307 USA22*/2324#include "cx18-driver.h"25#include "cx18-io.h"26#include "cx18-cards.h"27#include "cx18-gpio.h"28#include "tuner-xc2028.h"2930/********************* GPIO stuffs *********************/3132/* GPIO registers */33#define CX18_REG_GPIO_IN 0xc7201034#define CX18_REG_GPIO_OUT1 0xc7810035#define CX18_REG_GPIO_DIR1 0xc7810836#define CX18_REG_GPIO_OUT2 0xc7810437#define CX18_REG_GPIO_DIR2 0xc7810c3839/*40* HVR-1600 GPIO pins, courtesy of Hauppauge:41*42* gpio0: zilog ir process reset pin43* gpio1: zilog programming pin (you should never use this)44* gpio12: cx24227 reset pin45* gpio13: cs5345 reset pin46*/4748/*49* File scope utility functions50*/51static void gpio_write(struct cx18 *cx)52{53u32 dir_lo = cx->gpio_dir & 0xffff;54u32 val_lo = cx->gpio_val & 0xffff;55u32 dir_hi = cx->gpio_dir >> 16;56u32 val_hi = cx->gpio_val >> 16;5758cx18_write_reg_expect(cx, dir_lo << 16,59CX18_REG_GPIO_DIR1, ~dir_lo, dir_lo);60cx18_write_reg_expect(cx, (dir_lo << 16) | val_lo,61CX18_REG_GPIO_OUT1, val_lo, dir_lo);62cx18_write_reg_expect(cx, dir_hi << 16,63CX18_REG_GPIO_DIR2, ~dir_hi, dir_hi);64cx18_write_reg_expect(cx, (dir_hi << 16) | val_hi,65CX18_REG_GPIO_OUT2, val_hi, dir_hi);66}6768static void gpio_update(struct cx18 *cx, u32 mask, u32 data)69{70if (mask == 0)71return;7273mutex_lock(&cx->gpio_lock);74cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask);75gpio_write(cx);76mutex_unlock(&cx->gpio_lock);77}7879static void gpio_reset_seq(struct cx18 *cx, u32 active_lo, u32 active_hi,80unsigned int assert_msecs,81unsigned int recovery_msecs)82{83u32 mask;8485mask = active_lo | active_hi;86if (mask == 0)87return;8889/*90* Assuming that active_hi and active_lo are a subsets of the bits in91* gpio_dir. Also assumes that active_lo and active_hi don't overlap92* in any bit position93*/9495/* Assert */96gpio_update(cx, mask, ~active_lo);97schedule_timeout_uninterruptible(msecs_to_jiffies(assert_msecs));9899/* Deassert */100gpio_update(cx, mask, ~active_hi);101schedule_timeout_uninterruptible(msecs_to_jiffies(recovery_msecs));102}103104/*105* GPIO Multiplexer - logical device106*/107static int gpiomux_log_status(struct v4l2_subdev *sd)108{109struct cx18 *cx = v4l2_get_subdevdata(sd);110111mutex_lock(&cx->gpio_lock);112CX18_INFO_DEV(sd, "GPIO: direction 0x%08x, value 0x%08x\n",113cx->gpio_dir, cx->gpio_val);114mutex_unlock(&cx->gpio_lock);115return 0;116}117118static int gpiomux_s_radio(struct v4l2_subdev *sd)119{120struct cx18 *cx = v4l2_get_subdevdata(sd);121122/*123* FIXME - work out the cx->active/audio_input mess - this is124* intended to handle the switch to radio mode and set the125* audio routing, but we need to update the state in cx126*/127gpio_update(cx, cx->card->gpio_audio_input.mask,128cx->card->gpio_audio_input.radio);129return 0;130}131132static int gpiomux_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)133{134struct cx18 *cx = v4l2_get_subdevdata(sd);135u32 data;136137switch (cx->card->audio_inputs[cx->audio_input].muxer_input) {138case 1:139data = cx->card->gpio_audio_input.linein;140break;141case 0:142data = cx->card->gpio_audio_input.tuner;143break;144default:145/*146* FIXME - work out the cx->active/audio_input mess - this is147* intended to handle the switch from radio mode and set the148* audio routing, but we need to update the state in cx149*/150data = cx->card->gpio_audio_input.tuner;151break;152}153gpio_update(cx, cx->card->gpio_audio_input.mask, data);154return 0;155}156157static int gpiomux_s_audio_routing(struct v4l2_subdev *sd,158u32 input, u32 output, u32 config)159{160struct cx18 *cx = v4l2_get_subdevdata(sd);161u32 data;162163switch (input) {164case 0:165data = cx->card->gpio_audio_input.tuner;166break;167case 1:168data = cx->card->gpio_audio_input.linein;169break;170case 2:171data = cx->card->gpio_audio_input.radio;172break;173default:174return -EINVAL;175}176gpio_update(cx, cx->card->gpio_audio_input.mask, data);177return 0;178}179180static const struct v4l2_subdev_core_ops gpiomux_core_ops = {181.log_status = gpiomux_log_status,182.s_std = gpiomux_s_std,183};184185static const struct v4l2_subdev_tuner_ops gpiomux_tuner_ops = {186.s_radio = gpiomux_s_radio,187};188189static const struct v4l2_subdev_audio_ops gpiomux_audio_ops = {190.s_routing = gpiomux_s_audio_routing,191};192193static const struct v4l2_subdev_ops gpiomux_ops = {194.core = &gpiomux_core_ops,195.tuner = &gpiomux_tuner_ops,196.audio = &gpiomux_audio_ops,197};198199/*200* GPIO Reset Controller - logical device201*/202static int resetctrl_log_status(struct v4l2_subdev *sd)203{204struct cx18 *cx = v4l2_get_subdevdata(sd);205206mutex_lock(&cx->gpio_lock);207CX18_INFO_DEV(sd, "GPIO: direction 0x%08x, value 0x%08x\n",208cx->gpio_dir, cx->gpio_val);209mutex_unlock(&cx->gpio_lock);210return 0;211}212213static int resetctrl_reset(struct v4l2_subdev *sd, u32 val)214{215struct cx18 *cx = v4l2_get_subdevdata(sd);216const struct cx18_gpio_i2c_slave_reset *p;217218p = &cx->card->gpio_i2c_slave_reset;219switch (val) {220case CX18_GPIO_RESET_I2C:221gpio_reset_seq(cx, p->active_lo_mask, p->active_hi_mask,222p->msecs_asserted, p->msecs_recovery);223break;224case CX18_GPIO_RESET_Z8F0811:225/*226* Assert timing for the Z8F0811 on HVR-1600 boards:227* 1. Assert RESET for min of 4 clock cycles at 18.432 MHz to228* initiate229* 2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock230* cycles (6,601,085 nanoseconds ~= 7 milliseconds)231* 3. DBG pin must be high before chip exits reset for normal232* operation. DBG is open drain and hopefully pulled high233* since we don't normally drive it (GPIO 1?) for the234* HVR-1600235* 4. Z8F0811 won't exit reset until RESET is deasserted236* 5. Zilog comes out of reset, loads reset vector address and237* executes from there. Required recovery delay unknown.238*/239gpio_reset_seq(cx, p->ir_reset_mask, 0,240p->msecs_asserted, p->msecs_recovery);241break;242case CX18_GPIO_RESET_XC2028:243if (cx->card->tuners[0].tuner == TUNER_XC2028)244gpio_reset_seq(cx, (1 << cx->card->xceive_pin), 0,2451, 1);246break;247}248return 0;249}250251static const struct v4l2_subdev_core_ops resetctrl_core_ops = {252.log_status = resetctrl_log_status,253.reset = resetctrl_reset,254};255256static const struct v4l2_subdev_ops resetctrl_ops = {257.core = &resetctrl_core_ops,258};259260/*261* External entry points262*/263void cx18_gpio_init(struct cx18 *cx)264{265mutex_lock(&cx->gpio_lock);266cx->gpio_dir = cx->card->gpio_init.direction;267cx->gpio_val = cx->card->gpio_init.initial_value;268269if (cx->card->tuners[0].tuner == TUNER_XC2028) {270cx->gpio_dir |= 1 << cx->card->xceive_pin;271cx->gpio_val |= 1 << cx->card->xceive_pin;272}273274if (cx->gpio_dir == 0) {275mutex_unlock(&cx->gpio_lock);276return;277}278279CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n",280cx18_read_reg(cx, CX18_REG_GPIO_DIR1),281cx18_read_reg(cx, CX18_REG_GPIO_DIR2),282cx18_read_reg(cx, CX18_REG_GPIO_OUT1),283cx18_read_reg(cx, CX18_REG_GPIO_OUT2));284285gpio_write(cx);286mutex_unlock(&cx->gpio_lock);287}288289int cx18_gpio_register(struct cx18 *cx, u32 hw)290{291struct v4l2_subdev *sd;292const struct v4l2_subdev_ops *ops;293char *str;294295switch (hw) {296case CX18_HW_GPIO_MUX:297sd = &cx->sd_gpiomux;298ops = &gpiomux_ops;299str = "gpio-mux";300break;301case CX18_HW_GPIO_RESET_CTRL:302sd = &cx->sd_resetctrl;303ops = &resetctrl_ops;304str = "gpio-reset-ctrl";305break;306default:307return -EINVAL;308}309310v4l2_subdev_init(sd, ops);311v4l2_set_subdevdata(sd, cx);312snprintf(sd->name, sizeof(sd->name), "%s %s", cx->v4l2_dev.name, str);313sd->grp_id = hw;314return v4l2_device_register_subdev(&cx->v4l2_dev, sd);315}316317void cx18_reset_ir_gpio(void *data)318{319struct cx18 *cx = to_cx18((struct v4l2_device *)data);320321if (cx->card->gpio_i2c_slave_reset.ir_reset_mask == 0)322return;323324CX18_DEBUG_INFO("Resetting IR microcontroller\n");325326v4l2_subdev_call(&cx->sd_resetctrl,327core, reset, CX18_GPIO_RESET_Z8F0811);328}329EXPORT_SYMBOL(cx18_reset_ir_gpio);330/* This symbol is exported for use by lirc_pvr150 for the IR-blaster */331332/* Xceive tuner reset function */333int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value)334{335struct i2c_algo_bit_data *algo = dev;336struct cx18_i2c_algo_callback_data *cb_data = algo->data;337struct cx18 *cx = cb_data->cx;338339if (cmd != XC2028_TUNER_RESET ||340cx->card->tuners[0].tuner != TUNER_XC2028)341return 0;342343CX18_DEBUG_INFO("Resetting XCeive tuner\n");344return v4l2_subdev_call(&cx->sd_resetctrl,345core, reset, CX18_GPIO_RESET_XC2028);346}347348349