123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887 |
- /*
- * Copyright (C) 2010 Texas Instruments Inc
- *
- * This program 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 version 2.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/errno.h>
- #include <linux/fs.h>
- #include <linux/string.h>
- #include <linux/wait.h>
- #include <linux/time.h>
- #include <linux/platform_device.h>
- #include <linux/io.h>
- #include <linux/slab.h>
- #include <linux/clk.h>
- #include <linux/err.h>
- #include <media/v4l2-device.h>
- #include <media/davinci/vpbe_types.h>
- #include <media/davinci/vpbe.h>
- #include <media/davinci/vpss.h>
- #include <media/davinci/vpbe_venc.h>
- #define VPBE_DEFAULT_OUTPUT "Composite"
- #define VPBE_DEFAULT_MODE "ntsc"
- static char *def_output = VPBE_DEFAULT_OUTPUT;
- static char *def_mode = VPBE_DEFAULT_MODE;
- static int debug;
- module_param(def_output, charp, S_IRUGO);
- module_param(def_mode, charp, S_IRUGO);
- module_param(debug, int, 0644);
- MODULE_PARM_DESC(def_output, "vpbe output name (default:Composite)");
- MODULE_PARM_DESC(def_mode, "vpbe output mode name (default:ntsc");
- MODULE_PARM_DESC(debug, "Debug level 0-1");
- MODULE_DESCRIPTION("TI DMXXX VPBE Display controller");
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Texas Instruments");
- /**
- * vpbe_current_encoder_info - Get config info for current encoder
- * @vpbe_dev - vpbe device ptr
- *
- * Return ptr to current encoder config info
- */
- static struct encoder_config_info*
- vpbe_current_encoder_info(struct vpbe_device *vpbe_dev)
- {
- struct vpbe_config *cfg = vpbe_dev->cfg;
- int index = vpbe_dev->current_sd_index;
- return ((index == 0) ? &cfg->venc :
- &cfg->ext_encoders[index-1]);
- }
- /**
- * vpbe_find_encoder_sd_index - Given a name find encoder sd index
- *
- * @vpbe_config - ptr to vpbe cfg
- * @output_index - index used by application
- *
- * Return sd index of the encoder
- */
- static int vpbe_find_encoder_sd_index(struct vpbe_config *cfg,
- int index)
- {
- char *encoder_name = cfg->outputs[index].subdev_name;
- int i;
- /* Venc is always first */
- if (!strcmp(encoder_name, cfg->venc.module_name))
- return 0;
- for (i = 0; i < cfg->num_ext_encoders; i++) {
- if (!strcmp(encoder_name,
- cfg->ext_encoders[i].module_name))
- return i+1;
- }
- return -EINVAL;
- }
- /**
- * vpbe_g_cropcap - Get crop capabilities of the display
- * @vpbe_dev - vpbe device ptr
- * @cropcap - cropcap is a ptr to struct v4l2_cropcap
- *
- * Update the crop capabilities in crop cap for current
- * mode
- */
- static int vpbe_g_cropcap(struct vpbe_device *vpbe_dev,
- struct v4l2_cropcap *cropcap)
- {
- if (NULL == cropcap)
- return -EINVAL;
- cropcap->bounds.left = 0;
- cropcap->bounds.top = 0;
- cropcap->bounds.width = vpbe_dev->current_timings.xres;
- cropcap->bounds.height = vpbe_dev->current_timings.yres;
- cropcap->defrect = cropcap->bounds;
- return 0;
- }
- /**
- * vpbe_enum_outputs - enumerate outputs
- * @vpbe_dev - vpbe device ptr
- * @output - ptr to v4l2_output structure
- *
- * Enumerates the outputs available at the vpbe display
- * returns the status, -EINVAL if end of output list
- */
- static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev,
- struct v4l2_output *output)
- {
- struct vpbe_config *cfg = vpbe_dev->cfg;
- int temp_index = output->index;
- if (temp_index >= cfg->num_outputs)
- return -EINVAL;
- *output = cfg->outputs[temp_index].output;
- output->index = temp_index;
- return 0;
- }
- static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode,
- int output_index)
- {
- struct vpbe_config *cfg = vpbe_dev->cfg;
- struct vpbe_enc_mode_info var;
- int curr_output = output_index;
- int i;
- if (NULL == mode)
- return -EINVAL;
- for (i = 0; i < cfg->outputs[curr_output].num_modes; i++) {
- var = cfg->outputs[curr_output].modes[i];
- if (!strcmp(mode, var.name)) {
- vpbe_dev->current_timings = var;
- return 0;
- }
- }
- return -EINVAL;
- }
- static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev,
- struct vpbe_enc_mode_info *mode_info)
- {
- if (NULL == mode_info)
- return -EINVAL;
- *mode_info = vpbe_dev->current_timings;
- return 0;
- }
- /* Get std by std id */
- static int vpbe_get_std_info(struct vpbe_device *vpbe_dev,
- v4l2_std_id std_id)
- {
- struct vpbe_config *cfg = vpbe_dev->cfg;
- struct vpbe_enc_mode_info var;
- int curr_output = vpbe_dev->current_out_index;
- int i;
- for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) {
- var = cfg->outputs[curr_output].modes[i];
- if ((var.timings_type & VPBE_ENC_STD) &&
- (var.std_id & std_id)) {
- vpbe_dev->current_timings = var;
- return 0;
- }
- }
- return -EINVAL;
- }
- static int vpbe_get_std_info_by_name(struct vpbe_device *vpbe_dev,
- char *std_name)
- {
- struct vpbe_config *cfg = vpbe_dev->cfg;
- struct vpbe_enc_mode_info var;
- int curr_output = vpbe_dev->current_out_index;
- int i;
- for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) {
- var = cfg->outputs[curr_output].modes[i];
- if (!strcmp(var.name, std_name)) {
- vpbe_dev->current_timings = var;
- return 0;
- }
- }
- return -EINVAL;
- }
- /**
- * vpbe_set_output - Set output
- * @vpbe_dev - vpbe device ptr
- * @index - index of output
- *
- * Set vpbe output to the output specified by the index
- */
- static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index)
- {
- struct encoder_config_info *curr_enc_info =
- vpbe_current_encoder_info(vpbe_dev);
- struct vpbe_config *cfg = vpbe_dev->cfg;
- struct venc_platform_data *venc_device = vpbe_dev->venc_device;
- u32 if_params;
- int enc_out_index;
- int sd_index;
- int ret = 0;
- if (index >= cfg->num_outputs)
- return -EINVAL;
- mutex_lock(&vpbe_dev->lock);
- sd_index = vpbe_dev->current_sd_index;
- enc_out_index = cfg->outputs[index].output.index;
- /*
- * Currently we switch the encoder based on output selected
- * by the application. If media controller is implemented later
- * there is will be an API added to setup_link between venc
- * and external encoder. So in that case below comparison always
- * match and encoder will not be switched. But if application
- * chose not to use media controller, then this provides current
- * way of switching encoder at the venc output.
- */
- if (strcmp(curr_enc_info->module_name,
- cfg->outputs[index].subdev_name)) {
- /* Need to switch the encoder at the output */
- sd_index = vpbe_find_encoder_sd_index(cfg, index);
- if (sd_index < 0) {
- ret = -EINVAL;
- goto out;
- }
- if_params = cfg->outputs[index].if_params;
- venc_device->setup_if_config(if_params);
- if (ret)
- goto out;
- }
- /* Set output at the encoder */
- ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video,
- s_routing, 0, enc_out_index, 0);
- if (ret)
- goto out;
- /*
- * It is assumed that venc or extenal encoder will set a default
- * mode in the sub device. For external encoder or LCD pannel output,
- * we also need to set up the lcd port for the required mode. So setup
- * the lcd port for the default mode that is configured in the board
- * arch/arm/mach-davinci/board-dm355-evm.setup file for the external
- * encoder.
- */
- ret = vpbe_get_mode_info(vpbe_dev,
- cfg->outputs[index].default_mode, index);
- if (!ret) {
- struct osd_state *osd_device = vpbe_dev->osd_device;
- osd_device->ops.set_left_margin(osd_device,
- vpbe_dev->current_timings.left_margin);
- osd_device->ops.set_top_margin(osd_device,
- vpbe_dev->current_timings.upper_margin);
- vpbe_dev->current_sd_index = sd_index;
- vpbe_dev->current_out_index = index;
- }
- out:
- mutex_unlock(&vpbe_dev->lock);
- return ret;
- }
- static int vpbe_set_default_output(struct vpbe_device *vpbe_dev)
- {
- struct vpbe_config *cfg = vpbe_dev->cfg;
- int ret = 0;
- int i;
- for (i = 0; i < cfg->num_outputs; i++) {
- if (!strcmp(def_output,
- cfg->outputs[i].output.name)) {
- ret = vpbe_set_output(vpbe_dev, i);
- if (!ret)
- vpbe_dev->current_out_index = i;
- return ret;
- }
- }
- return ret;
- }
- /**
- * vpbe_get_output - Get output
- * @vpbe_dev - vpbe device ptr
- *
- * return current vpbe output to the the index
- */
- static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev)
- {
- return vpbe_dev->current_out_index;
- }
- /**
- * vpbe_s_dv_timings - Set the given preset timings in the encoder
- *
- * Sets the timings if supported by the current encoder. Return the status.
- * 0 - success & -EINVAL on error
- */
- static int vpbe_s_dv_timings(struct vpbe_device *vpbe_dev,
- struct v4l2_dv_timings *dv_timings)
- {
- struct vpbe_config *cfg = vpbe_dev->cfg;
- int out_index = vpbe_dev->current_out_index;
- struct vpbe_output *output = &cfg->outputs[out_index];
- int sd_index = vpbe_dev->current_sd_index;
- int ret, i;
- if (!(cfg->outputs[out_index].output.capabilities &
- V4L2_OUT_CAP_DV_TIMINGS))
- return -ENODATA;
- for (i = 0; i < output->num_modes; i++) {
- if (output->modes[i].timings_type == VPBE_ENC_DV_TIMINGS &&
- !memcmp(&output->modes[i].dv_timings,
- dv_timings, sizeof(*dv_timings)))
- break;
- }
- if (i >= output->num_modes)
- return -EINVAL;
- vpbe_dev->current_timings = output->modes[i];
- mutex_lock(&vpbe_dev->lock);
- ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video,
- s_dv_timings, dv_timings);
- if (!ret && (vpbe_dev->amp != NULL)) {
- /* Call amplifier subdevice */
- ret = v4l2_subdev_call(vpbe_dev->amp, video,
- s_dv_timings, dv_timings);
- }
- /* set the lcd controller output for the given mode */
- if (!ret) {
- struct osd_state *osd_device = vpbe_dev->osd_device;
- osd_device->ops.set_left_margin(osd_device,
- vpbe_dev->current_timings.left_margin);
- osd_device->ops.set_top_margin(osd_device,
- vpbe_dev->current_timings.upper_margin);
- }
- mutex_unlock(&vpbe_dev->lock);
- return ret;
- }
- /**
- * vpbe_g_dv_timings - Get the timings in the current encoder
- *
- * Get the timings in the current encoder. Return the status. 0 - success
- * -EINVAL on error
- */
- static int vpbe_g_dv_timings(struct vpbe_device *vpbe_dev,
- struct v4l2_dv_timings *dv_timings)
- {
- struct vpbe_config *cfg = vpbe_dev->cfg;
- int out_index = vpbe_dev->current_out_index;
- if (!(cfg->outputs[out_index].output.capabilities &
- V4L2_OUT_CAP_DV_TIMINGS))
- return -ENODATA;
- if (vpbe_dev->current_timings.timings_type &
- VPBE_ENC_DV_TIMINGS) {
- *dv_timings = vpbe_dev->current_timings.dv_timings;
- return 0;
- }
- return -EINVAL;
- }
- /**
- * vpbe_enum_dv_timings - Enumerate the dv timings in the current encoder
- *
- * Get the timings in the current encoder. Return the status. 0 - success
- * -EINVAL on error
- */
- static int vpbe_enum_dv_timings(struct vpbe_device *vpbe_dev,
- struct v4l2_enum_dv_timings *timings)
- {
- struct vpbe_config *cfg = vpbe_dev->cfg;
- int out_index = vpbe_dev->current_out_index;
- struct vpbe_output *output = &cfg->outputs[out_index];
- int j = 0;
- int i;
- if (!(output->output.capabilities & V4L2_OUT_CAP_DV_TIMINGS))
- return -ENODATA;
- for (i = 0; i < output->num_modes; i++) {
- if (output->modes[i].timings_type == VPBE_ENC_DV_TIMINGS) {
- if (j == timings->index)
- break;
- j++;
- }
- }
- if (i == output->num_modes)
- return -EINVAL;
- timings->timings = output->modes[i].dv_timings;
- return 0;
- }
- /**
- * vpbe_s_std - Set the given standard in the encoder
- *
- * Sets the standard if supported by the current encoder. Return the status.
- * 0 - success & -EINVAL on error
- */
- static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id std_id)
- {
- struct vpbe_config *cfg = vpbe_dev->cfg;
- int out_index = vpbe_dev->current_out_index;
- int sd_index = vpbe_dev->current_sd_index;
- int ret;
- if (!(cfg->outputs[out_index].output.capabilities &
- V4L2_OUT_CAP_STD))
- return -ENODATA;
- ret = vpbe_get_std_info(vpbe_dev, std_id);
- if (ret)
- return ret;
- mutex_lock(&vpbe_dev->lock);
- ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video,
- s_std_output, std_id);
- /* set the lcd controller output for the given mode */
- if (!ret) {
- struct osd_state *osd_device = vpbe_dev->osd_device;
- osd_device->ops.set_left_margin(osd_device,
- vpbe_dev->current_timings.left_margin);
- osd_device->ops.set_top_margin(osd_device,
- vpbe_dev->current_timings.upper_margin);
- }
- mutex_unlock(&vpbe_dev->lock);
- return ret;
- }
- /**
- * vpbe_g_std - Get the standard in the current encoder
- *
- * Get the standard in the current encoder. Return the status. 0 - success
- * -EINVAL on error
- */
- static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id)
- {
- struct vpbe_enc_mode_info *cur_timings = &vpbe_dev->current_timings;
- struct vpbe_config *cfg = vpbe_dev->cfg;
- int out_index = vpbe_dev->current_out_index;
- if (!(cfg->outputs[out_index].output.capabilities & V4L2_OUT_CAP_STD))
- return -ENODATA;
- if (cur_timings->timings_type & VPBE_ENC_STD) {
- *std_id = cur_timings->std_id;
- return 0;
- }
- return -EINVAL;
- }
- /**
- * vpbe_set_mode - Set mode in the current encoder using mode info
- *
- * Use the mode string to decide what timings to set in the encoder
- * This is typically useful when fbset command is used to change the current
- * timings by specifying a string to indicate the timings.
- */
- static int vpbe_set_mode(struct vpbe_device *vpbe_dev,
- struct vpbe_enc_mode_info *mode_info)
- {
- struct vpbe_enc_mode_info *preset_mode = NULL;
- struct vpbe_config *cfg = vpbe_dev->cfg;
- struct v4l2_dv_timings dv_timings;
- struct osd_state *osd_device;
- int out_index = vpbe_dev->current_out_index;
- int ret = 0;
- int i;
- if ((NULL == mode_info) || (NULL == mode_info->name))
- return -EINVAL;
- for (i = 0; i < cfg->outputs[out_index].num_modes; i++) {
- if (!strcmp(mode_info->name,
- cfg->outputs[out_index].modes[i].name)) {
- preset_mode = &cfg->outputs[out_index].modes[i];
- /*
- * it may be one of the 3 timings type. Check and
- * invoke right API
- */
- if (preset_mode->timings_type & VPBE_ENC_STD)
- return vpbe_s_std(vpbe_dev,
- preset_mode->std_id);
- if (preset_mode->timings_type &
- VPBE_ENC_DV_TIMINGS) {
- dv_timings =
- preset_mode->dv_timings;
- return vpbe_s_dv_timings(vpbe_dev, &dv_timings);
- }
- }
- }
- /* Only custom timing should reach here */
- if (preset_mode == NULL)
- return -EINVAL;
- mutex_lock(&vpbe_dev->lock);
- osd_device = vpbe_dev->osd_device;
- vpbe_dev->current_timings = *preset_mode;
- osd_device->ops.set_left_margin(osd_device,
- vpbe_dev->current_timings.left_margin);
- osd_device->ops.set_top_margin(osd_device,
- vpbe_dev->current_timings.upper_margin);
- mutex_unlock(&vpbe_dev->lock);
- return ret;
- }
- static int vpbe_set_default_mode(struct vpbe_device *vpbe_dev)
- {
- int ret;
- ret = vpbe_get_std_info_by_name(vpbe_dev, def_mode);
- if (ret)
- return ret;
- /* set the default mode in the encoder */
- return vpbe_set_mode(vpbe_dev, &vpbe_dev->current_timings);
- }
- static int platform_device_get(struct device *dev, void *data)
- {
- struct platform_device *pdev = to_platform_device(dev);
- struct vpbe_device *vpbe_dev = data;
- if (strstr(pdev->name, "vpbe-osd") != NULL)
- vpbe_dev->osd_device = platform_get_drvdata(pdev);
- if (strstr(pdev->name, "vpbe-venc") != NULL)
- vpbe_dev->venc_device = dev_get_platdata(&pdev->dev);
- return 0;
- }
- /**
- * vpbe_initialize() - Initialize the vpbe display controller
- * @vpbe_dev - vpbe device ptr
- *
- * Master frame buffer device drivers calls this to initialize vpbe
- * display controller. This will then registers v4l2 device and the sub
- * devices and sets a current encoder sub device for display. v4l2 display
- * device driver is the master and frame buffer display device driver is
- * the slave. Frame buffer display driver checks the initialized during
- * probe and exit if not initialized. Returns status.
- */
- static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
- {
- struct encoder_config_info *enc_info;
- struct amp_config_info *amp_info;
- struct v4l2_subdev **enc_subdev;
- struct osd_state *osd_device;
- struct i2c_adapter *i2c_adap;
- int num_encoders;
- int ret = 0;
- int err;
- int i;
- /*
- * v4l2 abd FBDev frame buffer devices will get the vpbe_dev pointer
- * from the platform device by iteration of platform drivers and
- * matching with device name
- */
- if (NULL == vpbe_dev || NULL == dev) {
- printk(KERN_ERR "Null device pointers.\n");
- return -ENODEV;
- }
- if (vpbe_dev->initialized)
- return 0;
- mutex_lock(&vpbe_dev->lock);
- if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) {
- /* We have dac clock available for platform */
- vpbe_dev->dac_clk = clk_get(vpbe_dev->pdev, "vpss_dac");
- if (IS_ERR(vpbe_dev->dac_clk)) {
- ret = PTR_ERR(vpbe_dev->dac_clk);
- goto fail_mutex_unlock;
- }
- if (clk_prepare_enable(vpbe_dev->dac_clk)) {
- ret = -ENODEV;
- clk_put(vpbe_dev->dac_clk);
- goto fail_mutex_unlock;
- }
- }
- /* first enable vpss clocks */
- vpss_enable_clock(VPSS_VPBE_CLOCK, 1);
- /* First register a v4l2 device */
- ret = v4l2_device_register(dev, &vpbe_dev->v4l2_dev);
- if (ret) {
- v4l2_err(dev->driver,
- "Unable to register v4l2 device.\n");
- goto fail_clk_put;
- }
- v4l2_info(&vpbe_dev->v4l2_dev, "vpbe v4l2 device registered\n");
- err = bus_for_each_dev(&platform_bus_type, NULL, vpbe_dev,
- platform_device_get);
- if (err < 0) {
- ret = err;
- goto fail_dev_unregister;
- }
- vpbe_dev->venc = venc_sub_dev_init(&vpbe_dev->v4l2_dev,
- vpbe_dev->cfg->venc.module_name);
- /* register venc sub device */
- if (vpbe_dev->venc == NULL) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "vpbe unable to init venc sub device\n");
- ret = -ENODEV;
- goto fail_dev_unregister;
- }
- /* initialize osd device */
- osd_device = vpbe_dev->osd_device;
- if (NULL != osd_device->ops.initialize) {
- err = osd_device->ops.initialize(osd_device);
- if (err) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "unable to initialize the OSD device");
- err = -ENOMEM;
- goto fail_dev_unregister;
- }
- }
- /*
- * Register any external encoders that are configured. At index 0 we
- * store venc sd index.
- */
- num_encoders = vpbe_dev->cfg->num_ext_encoders + 1;
- vpbe_dev->encoders = kmalloc(
- sizeof(struct v4l2_subdev *)*num_encoders,
- GFP_KERNEL);
- if (NULL == vpbe_dev->encoders) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "unable to allocate memory for encoders sub devices");
- ret = -ENOMEM;
- goto fail_dev_unregister;
- }
- i2c_adap = i2c_get_adapter(vpbe_dev->cfg->i2c_adapter_id);
- for (i = 0; i < (vpbe_dev->cfg->num_ext_encoders + 1); i++) {
- if (i == 0) {
- /* venc is at index 0 */
- enc_subdev = &vpbe_dev->encoders[i];
- *enc_subdev = vpbe_dev->venc;
- continue;
- }
- enc_info = &vpbe_dev->cfg->ext_encoders[i];
- if (enc_info->is_i2c) {
- enc_subdev = &vpbe_dev->encoders[i];
- *enc_subdev = v4l2_i2c_new_subdev_board(
- &vpbe_dev->v4l2_dev, i2c_adap,
- &enc_info->board_info, NULL);
- if (*enc_subdev)
- v4l2_info(&vpbe_dev->v4l2_dev,
- "v4l2 sub device %s registered\n",
- enc_info->module_name);
- else {
- v4l2_err(&vpbe_dev->v4l2_dev, "encoder %s"
- " failed to register",
- enc_info->module_name);
- ret = -ENODEV;
- goto fail_kfree_encoders;
- }
- } else
- v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders"
- " currently not supported");
- }
- /* Add amplifier subdevice for dm365 */
- if ((strcmp(vpbe_dev->cfg->module_name, "dm365-vpbe-display") == 0) &&
- vpbe_dev->cfg->amp != NULL) {
- amp_info = vpbe_dev->cfg->amp;
- if (amp_info->is_i2c) {
- vpbe_dev->amp = v4l2_i2c_new_subdev_board(
- &vpbe_dev->v4l2_dev, i2c_adap,
- &_info->board_info, NULL);
- if (!vpbe_dev->amp) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "amplifier %s failed to register",
- amp_info->module_name);
- ret = -ENODEV;
- goto fail_kfree_encoders;
- }
- v4l2_info(&vpbe_dev->v4l2_dev,
- "v4l2 sub device %s registered\n",
- amp_info->module_name);
- } else {
- vpbe_dev->amp = NULL;
- v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c amplifiers"
- " currently not supported");
- }
- } else {
- vpbe_dev->amp = NULL;
- }
- /* set the current encoder and output to that of venc by default */
- vpbe_dev->current_sd_index = 0;
- vpbe_dev->current_out_index = 0;
- mutex_unlock(&vpbe_dev->lock);
- printk(KERN_NOTICE "Setting default output to %s\n", def_output);
- ret = vpbe_set_default_output(vpbe_dev);
- if (ret) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s",
- def_output);
- goto fail_kfree_amp;
- }
- printk(KERN_NOTICE "Setting default mode to %s\n", def_mode);
- ret = vpbe_set_default_mode(vpbe_dev);
- if (ret) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s",
- def_mode);
- goto fail_kfree_amp;
- }
- vpbe_dev->initialized = 1;
- /* TBD handling of bootargs for default output and mode */
- return 0;
- fail_kfree_amp:
- mutex_lock(&vpbe_dev->lock);
- kfree(vpbe_dev->amp);
- fail_kfree_encoders:
- kfree(vpbe_dev->encoders);
- fail_dev_unregister:
- v4l2_device_unregister(&vpbe_dev->v4l2_dev);
- fail_clk_put:
- if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) {
- clk_disable_unprepare(vpbe_dev->dac_clk);
- clk_put(vpbe_dev->dac_clk);
- }
- fail_mutex_unlock:
- mutex_unlock(&vpbe_dev->lock);
- return ret;
- }
- /**
- * vpbe_deinitialize() - de-initialize the vpbe display controller
- * @dev - Master and slave device ptr
- *
- * vpbe_master and slave frame buffer devices calls this to de-initialize
- * the display controller. It is called when master and slave device
- * driver modules are removed and no longer requires the display controller.
- */
- static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev)
- {
- v4l2_device_unregister(&vpbe_dev->v4l2_dev);
- if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) {
- clk_disable_unprepare(vpbe_dev->dac_clk);
- clk_put(vpbe_dev->dac_clk);
- }
- kfree(vpbe_dev->amp);
- kfree(vpbe_dev->encoders);
- vpbe_dev->initialized = 0;
- /* disable vpss clocks */
- vpss_enable_clock(VPSS_VPBE_CLOCK, 0);
- }
- static struct vpbe_device_ops vpbe_dev_ops = {
- .g_cropcap = vpbe_g_cropcap,
- .enum_outputs = vpbe_enum_outputs,
- .set_output = vpbe_set_output,
- .get_output = vpbe_get_output,
- .s_dv_timings = vpbe_s_dv_timings,
- .g_dv_timings = vpbe_g_dv_timings,
- .enum_dv_timings = vpbe_enum_dv_timings,
- .s_std = vpbe_s_std,
- .g_std = vpbe_g_std,
- .initialize = vpbe_initialize,
- .deinitialize = vpbe_deinitialize,
- .get_mode_info = vpbe_get_current_mode_info,
- .set_mode = vpbe_set_mode,
- };
- static int vpbe_probe(struct platform_device *pdev)
- {
- struct vpbe_device *vpbe_dev;
- struct vpbe_config *cfg;
- int ret = -EINVAL;
- if (pdev->dev.platform_data == NULL) {
- v4l2_err(pdev->dev.driver, "No platform data\n");
- return -ENODEV;
- }
- cfg = pdev->dev.platform_data;
- if (!cfg->module_name[0] ||
- !cfg->osd.module_name[0] ||
- !cfg->venc.module_name[0]) {
- v4l2_err(pdev->dev.driver, "vpbe display module names not"
- " defined\n");
- return ret;
- }
- vpbe_dev = kzalloc(sizeof(*vpbe_dev), GFP_KERNEL);
- if (vpbe_dev == NULL) {
- v4l2_err(pdev->dev.driver, "Unable to allocate memory"
- " for vpbe_device\n");
- return -ENOMEM;
- }
- vpbe_dev->cfg = cfg;
- vpbe_dev->ops = vpbe_dev_ops;
- vpbe_dev->pdev = &pdev->dev;
- if (cfg->outputs->num_modes > 0)
- vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0];
- else {
- kfree(vpbe_dev);
- return -ENODEV;
- }
- /* set the driver data in platform device */
- platform_set_drvdata(pdev, vpbe_dev);
- mutex_init(&vpbe_dev->lock);
- return 0;
- }
- static int vpbe_remove(struct platform_device *device)
- {
- struct vpbe_device *vpbe_dev = platform_get_drvdata(device);
- kfree(vpbe_dev);
- return 0;
- }
- static struct platform_driver vpbe_driver = {
- .driver = {
- .name = "vpbe_controller",
- },
- .probe = vpbe_probe,
- .remove = vpbe_remove,
- };
- module_platform_driver(vpbe_driver);
|