From 670027c507e99521d416994a18a498def9ef2ea3 Mon Sep 17 00:00:00 2001 From: AndrĂ© Fabian Silva Delgado Date: Sat, 22 Oct 2016 19:31:08 -0300 Subject: Linux-libre 4.8.3-gnu --- drivers/staging/media/mn88472/Kconfig | 7 - drivers/staging/media/mn88472/Makefile | 5 - drivers/staging/media/mn88472/TODO | 21 - drivers/staging/media/mn88472/mn88472.c | 576 --------- drivers/staging/media/mn88472/mn88472_priv.h | 39 - drivers/staging/media/mx2/Kconfig | 15 - drivers/staging/media/mx2/Makefile | 3 - drivers/staging/media/mx2/TODO | 10 - drivers/staging/media/mx2/mx2_camera.c | 1636 ------------------------- drivers/staging/media/mx3/Kconfig | 15 - drivers/staging/media/mx3/Makefile | 3 - drivers/staging/media/mx3/TODO | 10 - drivers/staging/media/mx3/mx3_camera.c | 1264 ------------------- drivers/staging/media/omap1/Kconfig | 13 - drivers/staging/media/omap1/Makefile | 3 - drivers/staging/media/omap1/TODO | 8 - drivers/staging/media/omap1/omap1_camera.c | 1702 -------------------------- drivers/staging/media/timb/Kconfig | 11 - drivers/staging/media/timb/Makefile | 1 - drivers/staging/media/timb/timblogiw.c | 870 ------------- 20 files changed, 6212 deletions(-) delete mode 100644 drivers/staging/media/mn88472/Kconfig delete mode 100644 drivers/staging/media/mn88472/Makefile delete mode 100644 drivers/staging/media/mn88472/TODO delete mode 100644 drivers/staging/media/mn88472/mn88472.c delete mode 100644 drivers/staging/media/mn88472/mn88472_priv.h delete mode 100644 drivers/staging/media/mx2/Kconfig delete mode 100644 drivers/staging/media/mx2/Makefile delete mode 100644 drivers/staging/media/mx2/TODO delete mode 100644 drivers/staging/media/mx2/mx2_camera.c delete mode 100644 drivers/staging/media/mx3/Kconfig delete mode 100644 drivers/staging/media/mx3/Makefile delete mode 100644 drivers/staging/media/mx3/TODO delete mode 100644 drivers/staging/media/mx3/mx3_camera.c delete mode 100644 drivers/staging/media/omap1/Kconfig delete mode 100644 drivers/staging/media/omap1/Makefile delete mode 100644 drivers/staging/media/omap1/TODO delete mode 100644 drivers/staging/media/omap1/omap1_camera.c delete mode 100644 drivers/staging/media/timb/Kconfig delete mode 100644 drivers/staging/media/timb/Makefile delete mode 100644 drivers/staging/media/timb/timblogiw.c (limited to 'drivers/staging/media') diff --git a/drivers/staging/media/mn88472/Kconfig b/drivers/staging/media/mn88472/Kconfig deleted file mode 100644 index a85c90a60..000000000 --- a/drivers/staging/media/mn88472/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config DVB_MN88472 - tristate "Panasonic MN88472" - depends on DVB_CORE && I2C - select REGMAP_I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this frontend. diff --git a/drivers/staging/media/mn88472/Makefile b/drivers/staging/media/mn88472/Makefile deleted file mode 100644 index 5987b7e6d..000000000 --- a/drivers/staging/media/mn88472/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -obj-$(CONFIG_DVB_MN88472) += mn88472.o - -ccflags-y += -Idrivers/media/dvb-core/ -ccflags-y += -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/tuners/ diff --git a/drivers/staging/media/mn88472/TODO b/drivers/staging/media/mn88472/TODO deleted file mode 100644 index b90a14be3..000000000 --- a/drivers/staging/media/mn88472/TODO +++ /dev/null @@ -1,21 +0,0 @@ -Driver general quality is not good enough for mainline. Also, other -device drivers (USB-bridge, tuner) needed for Astrometa receiver in -question could need some changes. However, if that driver is mainlined -due to some other device than Astrometa, unrelated TODOs could be -skipped. In that case rtl28xxu driver needs module parameter to prevent -driver loading. - -Required TODOs: -* missing lock flags -* I2C errors -* tuner sensitivity - -*Do not* send any patch fixing checkpatch.pl issues. Currently it passes -checkpatch.pl tests. I don't want waste my time to review this kind of -trivial stuff. *Do not* add missing register I/O error checks. Those are -missing for the reason it is much easier to compare I2C data sniffs when -there is less lines. Those error checks are about the last thing to be added. - -Patches should be submitted to: -linux-media@vger.kernel.org and Antti Palosaari - diff --git a/drivers/staging/media/mn88472/mn88472.c b/drivers/staging/media/mn88472/mn88472.c deleted file mode 100644 index c7a76f0fc..000000000 --- a/drivers/staging/media/mn88472/mn88472.c +++ /dev/null @@ -1,576 +0,0 @@ -/* - * Panasonic MN88472 DVB-T/T2/C demodulator driver - * - * Copyright (C) 2013 Antti Palosaari - * - * 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; 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. - */ - -#include "mn88472_priv.h" - -static int mn88472_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *s) -{ - s->min_delay_ms = 800; - return 0; -} - -static int mn88472_set_frontend(struct dvb_frontend *fe) -{ - struct i2c_client *client = fe->demodulator_priv; - struct mn88472_dev *dev = i2c_get_clientdata(client); - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret, i; - u32 if_frequency = 0; - u64 tmp; - u8 delivery_system_val, if_val[3], bw_val[7], bw_val2; - - dev_dbg(&client->dev, - "delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d\n", - c->delivery_system, c->modulation, - c->frequency, c->symbol_rate, c->inversion); - - if (!dev->warm) { - ret = -EAGAIN; - goto err; - } - - switch (c->delivery_system) { - case SYS_DVBT: - delivery_system_val = 0x02; - break; - case SYS_DVBT2: - delivery_system_val = 0x03; - break; - case SYS_DVBC_ANNEX_A: - delivery_system_val = 0x04; - break; - default: - ret = -EINVAL; - goto err; - } - - if (c->bandwidth_hz <= 5000000) { - memcpy(bw_val, "\xe5\x99\x9a\x1b\xa9\x1b\xa9", 7); - bw_val2 = 0x03; - } else if (c->bandwidth_hz <= 6000000) { - /* IF 3570000 Hz, BW 6000000 Hz */ - memcpy(bw_val, "\xbf\x55\x55\x15\x6b\x15\x6b", 7); - bw_val2 = 0x02; - } else if (c->bandwidth_hz <= 7000000) { - /* IF 4570000 Hz, BW 7000000 Hz */ - memcpy(bw_val, "\xa4\x00\x00\x0f\x2c\x0f\x2c", 7); - bw_val2 = 0x01; - } else if (c->bandwidth_hz <= 8000000) { - /* IF 4570000 Hz, BW 8000000 Hz */ - memcpy(bw_val, "\x8f\x80\x00\x08\xee\x08\xee", 7); - bw_val2 = 0x00; - } else { - ret = -EINVAL; - goto err; - } - - /* program tuner */ - if (fe->ops.tuner_ops.set_params) { - ret = fe->ops.tuner_ops.set_params(fe); - if (ret) - goto err; - } - - if (fe->ops.tuner_ops.get_if_frequency) { - ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); - if (ret) - goto err; - - dev_dbg(&client->dev, "get_if_frequency=%d\n", if_frequency); - } - - /* Calculate IF registers ( (1<<24)*IF / Xtal ) */ - tmp = div_u64(if_frequency * (u64)(1<<24) + (dev->xtal / 2), - dev->xtal); - if_val[0] = (tmp >> 16) & 0xff; - if_val[1] = (tmp >> 8) & 0xff; - if_val[2] = (tmp >> 0) & 0xff; - - ret = regmap_write(dev->regmap[2], 0xfb, 0x13); - ret = regmap_write(dev->regmap[2], 0xef, 0x13); - ret = regmap_write(dev->regmap[2], 0xf9, 0x13); - if (ret) - goto err; - - ret = regmap_write(dev->regmap[2], 0x00, 0x66); - if (ret) - goto err; - ret = regmap_write(dev->regmap[2], 0x01, 0x00); - if (ret) - goto err; - ret = regmap_write(dev->regmap[2], 0x02, 0x01); - if (ret) - goto err; - ret = regmap_write(dev->regmap[2], 0x03, delivery_system_val); - if (ret) - goto err; - ret = regmap_write(dev->regmap[2], 0x04, bw_val2); - if (ret) - goto err; - - for (i = 0; i < sizeof(if_val); i++) { - ret = regmap_write(dev->regmap[2], 0x10 + i, if_val[i]); - if (ret) - goto err; - } - - for (i = 0; i < sizeof(bw_val); i++) { - ret = regmap_write(dev->regmap[2], 0x13 + i, bw_val[i]); - if (ret) - goto err; - } - - switch (c->delivery_system) { - case SYS_DVBT: - ret = regmap_write(dev->regmap[0], 0x07, 0x26); - ret = regmap_write(dev->regmap[0], 0xb0, 0x0a); - ret = regmap_write(dev->regmap[0], 0xb4, 0x00); - ret = regmap_write(dev->regmap[0], 0xcd, 0x1f); - ret = regmap_write(dev->regmap[0], 0xd4, 0x0a); - ret = regmap_write(dev->regmap[0], 0xd6, 0x48); - ret = regmap_write(dev->regmap[0], 0x00, 0xba); - ret = regmap_write(dev->regmap[0], 0x01, 0x13); - if (ret) - goto err; - break; - case SYS_DVBT2: - ret = regmap_write(dev->regmap[2], 0x2b, 0x13); - ret = regmap_write(dev->regmap[2], 0x4f, 0x05); - ret = regmap_write(dev->regmap[1], 0xf6, 0x05); - ret = regmap_write(dev->regmap[0], 0xb0, 0x0a); - ret = regmap_write(dev->regmap[0], 0xb4, 0xf6); - ret = regmap_write(dev->regmap[0], 0xcd, 0x01); - ret = regmap_write(dev->regmap[0], 0xd4, 0x09); - ret = regmap_write(dev->regmap[0], 0xd6, 0x46); - ret = regmap_write(dev->regmap[2], 0x30, 0x80); - ret = regmap_write(dev->regmap[2], 0x32, 0x00); - if (ret) - goto err; - break; - case SYS_DVBC_ANNEX_A: - ret = regmap_write(dev->regmap[0], 0xb0, 0x0b); - ret = regmap_write(dev->regmap[0], 0xb4, 0x00); - ret = regmap_write(dev->regmap[0], 0xcd, 0x17); - ret = regmap_write(dev->regmap[0], 0xd4, 0x09); - ret = regmap_write(dev->regmap[0], 0xd6, 0x48); - ret = regmap_write(dev->regmap[1], 0x00, 0xb0); - if (ret) - goto err; - break; - default: - ret = -EINVAL; - goto err; - } - - ret = regmap_write(dev->regmap[0], 0x46, 0x00); - ret = regmap_write(dev->regmap[0], 0xae, 0x00); - - switch (dev->ts_mode) { - case SERIAL_TS_MODE: - ret = regmap_write(dev->regmap[2], 0x08, 0x1d); - break; - case PARALLEL_TS_MODE: - ret = regmap_write(dev->regmap[2], 0x08, 0x00); - break; - default: - dev_dbg(&client->dev, "ts_mode error: %d\n", dev->ts_mode); - ret = -EINVAL; - goto err; - } - - switch (dev->ts_clock) { - case VARIABLE_TS_CLOCK: - ret = regmap_write(dev->regmap[0], 0xd9, 0xe3); - break; - case FIXED_TS_CLOCK: - ret = regmap_write(dev->regmap[0], 0xd9, 0xe1); - break; - default: - dev_dbg(&client->dev, "ts_clock error: %d\n", dev->ts_clock); - ret = -EINVAL; - goto err; - } - - /* Reset demod */ - ret = regmap_write(dev->regmap[2], 0xf8, 0x9f); - if (ret) - goto err; - - dev->delivery_system = c->delivery_system; - - return 0; -err: - dev_dbg(&client->dev, "failed=%d\n", ret); - return ret; -} - -static int mn88472_read_status(struct dvb_frontend *fe, enum fe_status *status) -{ - struct i2c_client *client = fe->demodulator_priv; - struct mn88472_dev *dev = i2c_get_clientdata(client); - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret; - unsigned int utmp; - int lock = 0; - - *status = 0; - - if (!dev->warm) { - ret = -EAGAIN; - goto err; - } - - switch (c->delivery_system) { - case SYS_DVBT: - ret = regmap_read(dev->regmap[0], 0x7F, &utmp); - if (ret) - goto err; - if ((utmp & 0xF) >= 0x09) - lock = 1; - break; - case SYS_DVBT2: - ret = regmap_read(dev->regmap[2], 0x92, &utmp); - if (ret) - goto err; - if ((utmp & 0xF) >= 0x07) - *status |= FE_HAS_SIGNAL; - if ((utmp & 0xF) >= 0x0a) - *status |= FE_HAS_CARRIER; - if ((utmp & 0xF) >= 0x0d) - *status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - break; - case SYS_DVBC_ANNEX_A: - ret = regmap_read(dev->regmap[1], 0x84, &utmp); - if (ret) - goto err; - if ((utmp & 0xF) >= 0x08) - lock = 1; - break; - default: - ret = -EINVAL; - goto err; - } - - if (lock) - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_LOCK; - - return 0; -err: - dev_dbg(&client->dev, "failed=%d\n", ret); - return ret; -} - -static int mn88472_init(struct dvb_frontend *fe) -{ - struct i2c_client *client = fe->demodulator_priv; - struct mn88472_dev *dev = i2c_get_clientdata(client); - int ret, len, remaining; - const struct firmware *fw = NULL; - u8 *fw_file = MN88472_FIRMWARE; - unsigned int tmp; - - dev_dbg(&client->dev, "\n"); - - /* set cold state by default */ - dev->warm = false; - - /* power on */ - ret = regmap_write(dev->regmap[2], 0x05, 0x00); - if (ret) - goto err; - - ret = regmap_bulk_write(dev->regmap[2], 0x0b, "\x00\x00", 2); - if (ret) - goto err; - - /* check if firmware is already running */ - ret = regmap_read(dev->regmap[0], 0xf5, &tmp); - if (ret) - goto err; - - if (!(tmp & 0x1)) { - dev_info(&client->dev, "firmware already running\n"); - dev->warm = true; - return 0; - } - - /* request the firmware, this will block and timeout */ - ret = reject_firmware(&fw, fw_file, &client->dev); - if (ret) { - dev_err(&client->dev, "firmare file '%s' not found\n", - fw_file); - goto err; - } - - dev_info(&client->dev, "downloading firmware from file '%s'\n", - fw_file); - - ret = regmap_write(dev->regmap[0], 0xf5, 0x03); - if (ret) - goto firmware_release; - - for (remaining = fw->size; remaining > 0; - remaining -= (dev->i2c_wr_max - 1)) { - len = remaining; - if (len > (dev->i2c_wr_max - 1)) - len = dev->i2c_wr_max - 1; - - ret = regmap_bulk_write(dev->regmap[0], 0xf6, - &fw->data[fw->size - remaining], len); - if (ret) { - dev_err(&client->dev, - "firmware download failed=%d\n", ret); - goto firmware_release; - } - } - - /* parity check of firmware */ - ret = regmap_read(dev->regmap[0], 0xf8, &tmp); - if (ret) { - dev_err(&client->dev, - "parity reg read failed=%d\n", ret); - goto firmware_release; - } - if (tmp & 0x10) { - dev_err(&client->dev, - "firmware parity check failed=0x%x\n", tmp); - goto firmware_release; - } - dev_err(&client->dev, "firmware parity check succeeded=0x%x\n", tmp); - - ret = regmap_write(dev->regmap[0], 0xf5, 0x00); - if (ret) - goto firmware_release; - - release_firmware(fw); - fw = NULL; - - /* warm state */ - dev->warm = true; - - return 0; -firmware_release: - release_firmware(fw); -err: - dev_dbg(&client->dev, "failed=%d\n", ret); - return ret; -} - -static int mn88472_sleep(struct dvb_frontend *fe) -{ - struct i2c_client *client = fe->demodulator_priv; - struct mn88472_dev *dev = i2c_get_clientdata(client); - int ret; - - dev_dbg(&client->dev, "\n"); - - /* power off */ - ret = regmap_write(dev->regmap[2], 0x0b, 0x30); - - if (ret) - goto err; - - ret = regmap_write(dev->regmap[2], 0x05, 0x3e); - if (ret) - goto err; - - dev->delivery_system = SYS_UNDEFINED; - - return 0; -err: - dev_dbg(&client->dev, "failed=%d\n", ret); - return ret; -} - -static struct dvb_frontend_ops mn88472_ops = { - .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A}, - .info = { - .name = "Panasonic MN88472", - .symbol_rate_min = 1000000, - .symbol_rate_max = 7200000, - .caps = FE_CAN_FEC_1_2 | - FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | - FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK | - FE_CAN_QAM_16 | - FE_CAN_QAM_32 | - FE_CAN_QAM_64 | - FE_CAN_QAM_128 | - FE_CAN_QAM_256 | - FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO | - FE_CAN_MUTE_TS | - FE_CAN_2G_MODULATION | - FE_CAN_MULTISTREAM - }, - - .get_tune_settings = mn88472_get_tune_settings, - - .init = mn88472_init, - .sleep = mn88472_sleep, - - .set_frontend = mn88472_set_frontend, - - .read_status = mn88472_read_status, -}; - -static int mn88472_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct mn88472_config *config = client->dev.platform_data; - struct mn88472_dev *dev; - int ret; - unsigned int utmp; - static const struct regmap_config regmap_config = { - .reg_bits = 8, - .val_bits = 8, - }; - - dev_dbg(&client->dev, "\n"); - - /* Caller really need to provide pointer for frontend we create. */ - if (config->fe == NULL) { - dev_err(&client->dev, "frontend pointer not defined\n"); - ret = -EINVAL; - goto err; - } - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - ret = -ENOMEM; - goto err; - } - - dev->i2c_wr_max = config->i2c_wr_max; - dev->xtal = config->xtal; - dev->ts_mode = config->ts_mode; - dev->ts_clock = config->ts_clock; - dev->client[0] = client; - dev->regmap[0] = regmap_init_i2c(dev->client[0], ®map_config); - if (IS_ERR(dev->regmap[0])) { - ret = PTR_ERR(dev->regmap[0]); - goto err_kfree; - } - - /* check demod answers to I2C */ - ret = regmap_read(dev->regmap[0], 0x00, &utmp); - if (ret) - goto err_regmap_0_regmap_exit; - - /* - * Chip has three I2C addresses for different register pages. Used - * addresses are 0x18, 0x1a and 0x1c. We register two dummy clients, - * 0x1a and 0x1c, in order to get own I2C client for each register page. - */ - dev->client[1] = i2c_new_dummy(client->adapter, 0x1a); - if (!dev->client[1]) { - ret = -ENODEV; - dev_err(&client->dev, "I2C registration failed\n"); - if (ret) - goto err_regmap_0_regmap_exit; - } - dev->regmap[1] = regmap_init_i2c(dev->client[1], ®map_config); - if (IS_ERR(dev->regmap[1])) { - ret = PTR_ERR(dev->regmap[1]); - goto err_client_1_i2c_unregister_device; - } - i2c_set_clientdata(dev->client[1], dev); - - dev->client[2] = i2c_new_dummy(client->adapter, 0x1c); - if (!dev->client[2]) { - ret = -ENODEV; - dev_err(&client->dev, "2nd I2C registration failed\n"); - if (ret) - goto err_regmap_1_regmap_exit; - } - dev->regmap[2] = regmap_init_i2c(dev->client[2], ®map_config); - if (IS_ERR(dev->regmap[2])) { - ret = PTR_ERR(dev->regmap[2]); - goto err_client_2_i2c_unregister_device; - } - i2c_set_clientdata(dev->client[2], dev); - - /* create dvb_frontend */ - memcpy(&dev->fe.ops, &mn88472_ops, sizeof(struct dvb_frontend_ops)); - dev->fe.demodulator_priv = client; - *config->fe = &dev->fe; - i2c_set_clientdata(client, dev); - - dev_info(&client->dev, "Panasonic MN88472 successfully attached\n"); - return 0; - -err_client_2_i2c_unregister_device: - i2c_unregister_device(dev->client[2]); -err_regmap_1_regmap_exit: - regmap_exit(dev->regmap[1]); -err_client_1_i2c_unregister_device: - i2c_unregister_device(dev->client[1]); -err_regmap_0_regmap_exit: - regmap_exit(dev->regmap[0]); -err_kfree: - kfree(dev); -err: - dev_dbg(&client->dev, "failed=%d\n", ret); - return ret; -} - -static int mn88472_remove(struct i2c_client *client) -{ - struct mn88472_dev *dev = i2c_get_clientdata(client); - - dev_dbg(&client->dev, "\n"); - - regmap_exit(dev->regmap[2]); - i2c_unregister_device(dev->client[2]); - - regmap_exit(dev->regmap[1]); - i2c_unregister_device(dev->client[1]); - - regmap_exit(dev->regmap[0]); - - kfree(dev); - - return 0; -} - -static const struct i2c_device_id mn88472_id_table[] = { - {"mn88472", 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, mn88472_id_table); - -static struct i2c_driver mn88472_driver = { - .driver = { - .name = "mn88472", - }, - .probe = mn88472_probe, - .remove = mn88472_remove, - .id_table = mn88472_id_table, -}; - -module_i2c_driver(mn88472_driver); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Panasonic MN88472 DVB-T/T2/C demodulator driver"); -MODULE_LICENSE("GPL"); -/*(DEBLOBBED)*/ diff --git a/drivers/staging/media/mn88472/mn88472_priv.h b/drivers/staging/media/mn88472/mn88472_priv.h deleted file mode 100644 index da6531d1e..000000000 --- a/drivers/staging/media/mn88472/mn88472_priv.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Panasonic MN88472 DVB-T/T2/C demodulator driver - * - * Copyright (C) 2013 Antti Palosaari - * - * 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; 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. - */ - -#ifndef MN88472_PRIV_H -#define MN88472_PRIV_H - -#include "dvb_frontend.h" -#include "mn88472.h" -#include -#include - -#define MN88472_FIRMWARE "/*(DEBLOBBED)*/" - -struct mn88472_dev { - struct i2c_client *client[3]; - struct regmap *regmap[3]; - struct dvb_frontend fe; - u16 i2c_wr_max; - enum fe_delivery_system delivery_system; - bool warm; /* FW running */ - u32 xtal; - int ts_mode; - int ts_clock; -}; - -#endif diff --git a/drivers/staging/media/mx2/Kconfig b/drivers/staging/media/mx2/Kconfig deleted file mode 100644 index beaa885cf..000000000 --- a/drivers/staging/media/mx2/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config VIDEO_MX2 - tristate "i.MX27 Camera Sensor Interface driver" - depends on VIDEO_DEV && SOC_CAMERA - depends on SOC_IMX27 || COMPILE_TEST - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - ---help--- - This is a v4l2 driver for the i.MX27 Camera Sensor Interface - - This driver is deprecated: it should become a stand-alone driver - instead of using the soc-camera framework. - - Unless someone is willing to take this on (unlikely with such - ancient hardware) it is going to be removed from the kernel - soon. diff --git a/drivers/staging/media/mx2/Makefile b/drivers/staging/media/mx2/Makefile deleted file mode 100644 index fc5b2826a..000000000 --- a/drivers/staging/media/mx2/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# Makefile for i.MX27 Camera Sensor driver - -obj-$(CONFIG_VIDEO_MX2) += mx2_camera.o diff --git a/drivers/staging/media/mx2/TODO b/drivers/staging/media/mx2/TODO deleted file mode 100644 index bc68fa443..000000000 --- a/drivers/staging/media/mx2/TODO +++ /dev/null @@ -1,10 +0,0 @@ -This driver is deprecated: it should become a stand-alone driver instead of -using the soc-camera framework. - -Unless someone is willing to take this on (unlikely with such ancient -hardware) it is going to be removed from the kernel soon. - -Note that trivial patches will not be accepted anymore, only a full conversion. - -If you want to convert this driver, please contact the linux-media mailinglist -(see http://linuxtv.org/lists.php). diff --git a/drivers/staging/media/mx2/mx2_camera.c b/drivers/staging/media/mx2/mx2_camera.c deleted file mode 100644 index 48dd5b785..000000000 --- a/drivers/staging/media/mx2/mx2_camera.c +++ /dev/null @@ -1,1636 +0,0 @@ -/* - * V4L2 Driver for i.MX27 camera host - * - * Copyright (C) 2008, Sascha Hauer, Pengutronix - * Copyright (C) 2010, Baruch Siach, Orex Computed Radiography - * Copyright (C) 2012, Javier Martin, Vista Silicon S.L. - * - * 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; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include - -#define MX2_CAM_DRV_NAME "mx2-camera" -#define MX2_CAM_VERSION "0.0.6" -#define MX2_CAM_DRIVER_DESCRIPTION "i.MX2x_Camera" - -/* reset values */ -#define CSICR1_RESET_VAL 0x40000800 -#define CSICR2_RESET_VAL 0x0 -#define CSICR3_RESET_VAL 0x0 - -/* csi control reg 1 */ -#define CSICR1_SWAP16_EN (1 << 31) -#define CSICR1_EXT_VSYNC (1 << 30) -#define CSICR1_EOF_INTEN (1 << 29) -#define CSICR1_PRP_IF_EN (1 << 28) -#define CSICR1_CCIR_MODE (1 << 27) -#define CSICR1_COF_INTEN (1 << 26) -#define CSICR1_SF_OR_INTEN (1 << 25) -#define CSICR1_RF_OR_INTEN (1 << 24) -#define CSICR1_STATFF_LEVEL (3 << 22) -#define CSICR1_STATFF_INTEN (1 << 21) -#define CSICR1_RXFF_LEVEL(l) (((l) & 3) << 19) -#define CSICR1_RXFF_INTEN (1 << 18) -#define CSICR1_SOF_POL (1 << 17) -#define CSICR1_SOF_INTEN (1 << 16) -#define CSICR1_MCLKDIV(d) (((d) & 0xF) << 12) -#define CSICR1_HSYNC_POL (1 << 11) -#define CSICR1_CCIR_EN (1 << 10) -#define CSICR1_MCLKEN (1 << 9) -#define CSICR1_FCC (1 << 8) -#define CSICR1_PACK_DIR (1 << 7) -#define CSICR1_CLR_STATFIFO (1 << 6) -#define CSICR1_CLR_RXFIFO (1 << 5) -#define CSICR1_GCLK_MODE (1 << 4) -#define CSICR1_INV_DATA (1 << 3) -#define CSICR1_INV_PCLK (1 << 2) -#define CSICR1_REDGE (1 << 1) -#define CSICR1_FMT_MASK (CSICR1_PACK_DIR | CSICR1_SWAP16_EN) - -#define SHIFT_STATFF_LEVEL 22 -#define SHIFT_RXFF_LEVEL 19 -#define SHIFT_MCLKDIV 12 - -#define SHIFT_FRMCNT 16 - -#define CSICR1 0x00 -#define CSICR2 0x04 -#define CSISR 0x08 -#define CSISTATFIFO 0x0c -#define CSIRFIFO 0x10 -#define CSIRXCNT 0x14 -#define CSICR3 0x1c -#define CSIDMASA_STATFIFO 0x20 -#define CSIDMATA_STATFIFO 0x24 -#define CSIDMASA_FB1 0x28 -#define CSIDMASA_FB2 0x2c -#define CSIFBUF_PARA 0x30 -#define CSIIMAG_PARA 0x34 - -/* EMMA PrP */ -#define PRP_CNTL 0x00 -#define PRP_INTR_CNTL 0x04 -#define PRP_INTRSTATUS 0x08 -#define PRP_SOURCE_Y_PTR 0x0c -#define PRP_SOURCE_CB_PTR 0x10 -#define PRP_SOURCE_CR_PTR 0x14 -#define PRP_DEST_RGB1_PTR 0x18 -#define PRP_DEST_RGB2_PTR 0x1c -#define PRP_DEST_Y_PTR 0x20 -#define PRP_DEST_CB_PTR 0x24 -#define PRP_DEST_CR_PTR 0x28 -#define PRP_SRC_FRAME_SIZE 0x2c -#define PRP_DEST_CH1_LINE_STRIDE 0x30 -#define PRP_SRC_PIXEL_FORMAT_CNTL 0x34 -#define PRP_CH1_PIXEL_FORMAT_CNTL 0x38 -#define PRP_CH1_OUT_IMAGE_SIZE 0x3c -#define PRP_CH2_OUT_IMAGE_SIZE 0x40 -#define PRP_SRC_LINE_STRIDE 0x44 -#define PRP_CSC_COEF_012 0x48 -#define PRP_CSC_COEF_345 0x4c -#define PRP_CSC_COEF_678 0x50 -#define PRP_CH1_RZ_HORI_COEF1 0x54 -#define PRP_CH1_RZ_HORI_COEF2 0x58 -#define PRP_CH1_RZ_HORI_VALID 0x5c -#define PRP_CH1_RZ_VERT_COEF1 0x60 -#define PRP_CH1_RZ_VERT_COEF2 0x64 -#define PRP_CH1_RZ_VERT_VALID 0x68 -#define PRP_CH2_RZ_HORI_COEF1 0x6c -#define PRP_CH2_RZ_HORI_COEF2 0x70 -#define PRP_CH2_RZ_HORI_VALID 0x74 -#define PRP_CH2_RZ_VERT_COEF1 0x78 -#define PRP_CH2_RZ_VERT_COEF2 0x7c -#define PRP_CH2_RZ_VERT_VALID 0x80 - -#define PRP_CNTL_CH1EN (1 << 0) -#define PRP_CNTL_CH2EN (1 << 1) -#define PRP_CNTL_CSIEN (1 << 2) -#define PRP_CNTL_DATA_IN_YUV420 (0 << 3) -#define PRP_CNTL_DATA_IN_YUV422 (1 << 3) -#define PRP_CNTL_DATA_IN_RGB16 (2 << 3) -#define PRP_CNTL_DATA_IN_RGB32 (3 << 3) -#define PRP_CNTL_CH1_OUT_RGB8 (0 << 5) -#define PRP_CNTL_CH1_OUT_RGB16 (1 << 5) -#define PRP_CNTL_CH1_OUT_RGB32 (2 << 5) -#define PRP_CNTL_CH1_OUT_YUV422 (3 << 5) -#define PRP_CNTL_CH2_OUT_YUV420 (0 << 7) -#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7) -#define PRP_CNTL_CH2_OUT_YUV444 (2 << 7) -#define PRP_CNTL_CH1_LEN (1 << 9) -#define PRP_CNTL_CH2_LEN (1 << 10) -#define PRP_CNTL_SKIP_FRAME (1 << 11) -#define PRP_CNTL_SWRST (1 << 12) -#define PRP_CNTL_CLKEN (1 << 13) -#define PRP_CNTL_WEN (1 << 14) -#define PRP_CNTL_CH1BYP (1 << 15) -#define PRP_CNTL_IN_TSKIP(x) ((x) << 16) -#define PRP_CNTL_CH1_TSKIP(x) ((x) << 19) -#define PRP_CNTL_CH2_TSKIP(x) ((x) << 22) -#define PRP_CNTL_INPUT_FIFO_LEVEL(x) ((x) << 25) -#define PRP_CNTL_RZ_FIFO_LEVEL(x) ((x) << 27) -#define PRP_CNTL_CH2B1EN (1 << 29) -#define PRP_CNTL_CH2B2EN (1 << 30) -#define PRP_CNTL_CH2FEN (1 << 31) - -/* IRQ Enable and status register */ -#define PRP_INTR_RDERR (1 << 0) -#define PRP_INTR_CH1WERR (1 << 1) -#define PRP_INTR_CH2WERR (1 << 2) -#define PRP_INTR_CH1FC (1 << 3) -#define PRP_INTR_CH2FC (1 << 5) -#define PRP_INTR_LBOVF (1 << 7) -#define PRP_INTR_CH2OVF (1 << 8) - -/* Resizing registers */ -#define PRP_RZ_VALID_TBL_LEN(x) ((x) << 24) -#define PRP_RZ_VALID_BILINEAR (1 << 31) - -#define MAX_VIDEO_MEM 16 - -#define RESIZE_NUM_MIN 1 -#define RESIZE_NUM_MAX 20 -#define BC_COEF 3 -#define SZ_COEF (1 << BC_COEF) - -#define RESIZE_DIR_H 0 -#define RESIZE_DIR_V 1 - -#define RESIZE_ALGO_BILINEAR 0 -#define RESIZE_ALGO_AVERAGING 1 - -struct mx2_prp_cfg { - int channel; - u32 in_fmt; - u32 out_fmt; - u32 src_pixel; - u32 ch1_pixel; - u32 irq_flags; - u32 csicr1; -}; - -/* prp resizing parameters */ -struct emma_prp_resize { - int algo; /* type of algorithm used */ - int len; /* number of coefficients */ - unsigned char s[RESIZE_NUM_MAX]; /* table of coefficients */ -}; - -/* prp configuration for a client-host fmt pair */ -struct mx2_fmt_cfg { - u32 in_fmt; - u32 out_fmt; - struct mx2_prp_cfg cfg; -}; - -struct mx2_buf_internal { - struct list_head queue; - int bufnum; - bool discard; -}; - -/* buffer for one video frame */ -struct mx2_buffer { - /* common v4l buffer stuff -- must be first */ - struct vb2_v4l2_buffer vb; - struct mx2_buf_internal internal; -}; - -enum mx2_camera_type { - IMX27_CAMERA, -}; - -struct mx2_camera_dev { - struct device *dev; - struct soc_camera_host soc_host; - struct clk *clk_emma_ahb, *clk_emma_ipg; - struct clk *clk_csi_ahb, *clk_csi_per; - - void __iomem *base_csi, *base_emma; - - struct mx2_camera_platform_data *pdata; - unsigned long platform_flags; - - struct list_head capture; - struct list_head active_bufs; - struct list_head discard; - - spinlock_t lock; - - int dma; - struct mx2_buffer *active; - struct mx2_buffer *fb1_active; - struct mx2_buffer *fb2_active; - - u32 csicr1; - enum mx2_camera_type devtype; - - struct mx2_buf_internal buf_discard[2]; - void *discard_buffer; - dma_addr_t discard_buffer_dma; - size_t discard_size; - struct mx2_fmt_cfg *emma_prp; - struct emma_prp_resize resizing[2]; - unsigned int s_width, s_height; - u32 frame_count; - struct vb2_alloc_ctx *alloc_ctx; -}; - -static struct platform_device_id mx2_camera_devtype[] = { - { - .name = "imx27-camera", - .driver_data = IMX27_CAMERA, - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(platform, mx2_camera_devtype); - -static struct mx2_buffer *mx2_ibuf_to_buf(struct mx2_buf_internal *int_buf) -{ - return container_of(int_buf, struct mx2_buffer, internal); -} - -static struct mx2_fmt_cfg mx27_emma_prp_table[] = { - /* - * This is a generic configuration which is valid for most - * prp input-output format combinations. - * We set the incoming and outgoing pixelformat to a - * 16 Bit wide format and adjust the bytesperline - * accordingly. With this configuration the inputdata - * will not be changed by the emma and could be any type - * of 16 Bit Pixelformat. - */ - { - .in_fmt = 0, - .out_fmt = 0, - .cfg = { - .channel = 1, - .in_fmt = PRP_CNTL_DATA_IN_RGB16, - .out_fmt = PRP_CNTL_CH1_OUT_RGB16, - .src_pixel = 0x2ca00565, /* RGB565 */ - .ch1_pixel = 0x2ca00565, /* RGB565 */ - .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR | - PRP_INTR_CH1FC | PRP_INTR_LBOVF, - .csicr1 = 0, - } - }, - { - .in_fmt = MEDIA_BUS_FMT_UYVY8_2X8, - .out_fmt = V4L2_PIX_FMT_YUYV, - .cfg = { - .channel = 1, - .in_fmt = PRP_CNTL_DATA_IN_YUV422, - .out_fmt = PRP_CNTL_CH1_OUT_YUV422, - .src_pixel = 0x22000888, /* YUV422 (YUYV) */ - .ch1_pixel = 0x62000888, /* YUV422 (YUYV) */ - .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR | - PRP_INTR_CH1FC | PRP_INTR_LBOVF, - .csicr1 = CSICR1_SWAP16_EN, - } - }, - { - .in_fmt = MEDIA_BUS_FMT_YUYV8_2X8, - .out_fmt = V4L2_PIX_FMT_YUYV, - .cfg = { - .channel = 1, - .in_fmt = PRP_CNTL_DATA_IN_YUV422, - .out_fmt = PRP_CNTL_CH1_OUT_YUV422, - .src_pixel = 0x22000888, /* YUV422 (YUYV) */ - .ch1_pixel = 0x62000888, /* YUV422 (YUYV) */ - .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR | - PRP_INTR_CH1FC | PRP_INTR_LBOVF, - .csicr1 = CSICR1_PACK_DIR, - } - }, - { - .in_fmt = MEDIA_BUS_FMT_YUYV8_2X8, - .out_fmt = V4L2_PIX_FMT_YUV420, - .cfg = { - .channel = 2, - .in_fmt = PRP_CNTL_DATA_IN_YUV422, - .out_fmt = PRP_CNTL_CH2_OUT_YUV420, - .src_pixel = 0x22000888, /* YUV422 (YUYV) */ - .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR | - PRP_INTR_CH2FC | PRP_INTR_LBOVF | - PRP_INTR_CH2OVF, - .csicr1 = CSICR1_PACK_DIR, - } - }, - { - .in_fmt = MEDIA_BUS_FMT_UYVY8_2X8, - .out_fmt = V4L2_PIX_FMT_YUV420, - .cfg = { - .channel = 2, - .in_fmt = PRP_CNTL_DATA_IN_YUV422, - .out_fmt = PRP_CNTL_CH2_OUT_YUV420, - .src_pixel = 0x22000888, /* YUV422 (YUYV) */ - .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR | - PRP_INTR_CH2FC | PRP_INTR_LBOVF | - PRP_INTR_CH2OVF, - .csicr1 = CSICR1_SWAP16_EN, - } - }, -}; - -static struct mx2_fmt_cfg *mx27_emma_prp_get_format(u32 in_fmt, u32 out_fmt) -{ - int i; - - for (i = 1; i < ARRAY_SIZE(mx27_emma_prp_table); i++) - if ((mx27_emma_prp_table[i].in_fmt == in_fmt) && - (mx27_emma_prp_table[i].out_fmt == out_fmt)) { - return &mx27_emma_prp_table[i]; - } - /* If no match return the most generic configuration */ - return &mx27_emma_prp_table[0]; -}; - -static void mx27_update_emma_buf(struct mx2_camera_dev *pcdev, - unsigned long phys, int bufnum) -{ - struct mx2_fmt_cfg *prp = pcdev->emma_prp; - - if (prp->cfg.channel == 1) { - writel(phys, pcdev->base_emma + - PRP_DEST_RGB1_PTR + 4 * bufnum); - } else { - writel(phys, pcdev->base_emma + - PRP_DEST_Y_PTR - 0x14 * bufnum); - if (prp->out_fmt == V4L2_PIX_FMT_YUV420) { - u32 imgsize = pcdev->soc_host.icd->user_height * - pcdev->soc_host.icd->user_width; - - writel(phys + imgsize, pcdev->base_emma + - PRP_DEST_CB_PTR - 0x14 * bufnum); - writel(phys + ((5 * imgsize) / 4), pcdev->base_emma + - PRP_DEST_CR_PTR - 0x14 * bufnum); - } - } -} - -static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) -{ - clk_disable_unprepare(pcdev->clk_csi_ahb); - clk_disable_unprepare(pcdev->clk_csi_per); - writel(0, pcdev->base_csi + CSICR1); - writel(0, pcdev->base_emma + PRP_CNTL); -} - -static int mx2_camera_add_device(struct soc_camera_device *icd) -{ - dev_info(icd->parent, "Camera driver attached to camera %d\n", - icd->devnum); - - return 0; -} - -static void mx2_camera_remove_device(struct soc_camera_device *icd) -{ - dev_info(icd->parent, "Camera driver detached from camera %d\n", - icd->devnum); -} - -/* - * The following two functions absolutely depend on the fact, that - * there can be only one camera on mx2 camera sensor interface - */ -static int mx2_camera_clock_start(struct soc_camera_host *ici) -{ - struct mx2_camera_dev *pcdev = ici->priv; - int ret; - u32 csicr1; - - ret = clk_prepare_enable(pcdev->clk_csi_ahb); - if (ret < 0) - return ret; - - ret = clk_prepare_enable(pcdev->clk_csi_per); - if (ret < 0) - goto exit_csi_ahb; - - csicr1 = CSICR1_MCLKEN | CSICR1_PRP_IF_EN | CSICR1_FCC | - CSICR1_RXFF_LEVEL(0); - - pcdev->csicr1 = csicr1; - writel(pcdev->csicr1, pcdev->base_csi + CSICR1); - - pcdev->frame_count = 0; - - return 0; - -exit_csi_ahb: - clk_disable_unprepare(pcdev->clk_csi_ahb); - - return ret; -} - -static void mx2_camera_clock_stop(struct soc_camera_host *ici) -{ - struct mx2_camera_dev *pcdev = ici->priv; - - mx2_camera_deactivate(pcdev); -} - -/* - * Videobuf operations - */ -static int mx2_videobuf_setup(struct vb2_queue *vq, - unsigned int *count, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) -{ - struct soc_camera_device *icd = soc_camera_from_vb2q(vq); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct mx2_camera_dev *pcdev = ici->priv; - - dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]); - - alloc_ctxs[0] = pcdev->alloc_ctx; - - sizes[0] = icd->sizeimage; - - if (0 == *count) - *count = 32; - if (!*num_planes && - sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024) - *count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0]; - - *num_planes = 1; - - return 0; -} - -static int mx2_videobuf_prepare(struct vb2_buffer *vb) -{ - struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - int ret = 0; - - dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, - vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); - -#ifdef DEBUG - /* - * This can be useful if you want to see if we actually fill - * the buffer with something - */ - memset((void *)vb2_plane_vaddr(vb, 0), - 0xaa, vb2_get_plane_payload(vb, 0)); -#endif - - vb2_set_plane_payload(vb, 0, icd->sizeimage); - if (vb2_plane_vaddr(vb, 0) && - vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { - ret = -EINVAL; - goto out; - } - - return 0; - -out: - return ret; -} - -static void mx2_videobuf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = - to_soc_camera_host(icd->parent); - struct mx2_camera_dev *pcdev = ici->priv; - struct mx2_buffer *buf = container_of(vbuf, struct mx2_buffer, vb); - unsigned long flags; - - dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, - vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); - - spin_lock_irqsave(&pcdev->lock, flags); - - list_add_tail(&buf->internal.queue, &pcdev->capture); - - spin_unlock_irqrestore(&pcdev->lock, flags); -} - -static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, - int bytesperline) -{ - struct soc_camera_host *ici = - to_soc_camera_host(icd->parent); - struct mx2_camera_dev *pcdev = ici->priv; - struct mx2_fmt_cfg *prp = pcdev->emma_prp; - - writel((pcdev->s_width << 16) | pcdev->s_height, - pcdev->base_emma + PRP_SRC_FRAME_SIZE); - writel(prp->cfg.src_pixel, - pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); - if (prp->cfg.channel == 1) { - writel((icd->user_width << 16) | icd->user_height, - pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); - writel(bytesperline, - pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); - writel(prp->cfg.ch1_pixel, - pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); - } else { /* channel 2 */ - writel((icd->user_width << 16) | icd->user_height, - pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE); - } - - /* Enable interrupts */ - writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL); -} - -static void mx2_prp_resize_commit(struct mx2_camera_dev *pcdev) -{ - int dir; - - for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) { - unsigned char *s = pcdev->resizing[dir].s; - int len = pcdev->resizing[dir].len; - unsigned int coeff[2] = {0, 0}; - unsigned int valid = 0; - int i; - - if (len == 0) - continue; - - for (i = RESIZE_NUM_MAX - 1; i >= 0; i--) { - int j; - - j = i > 9 ? 1 : 0; - coeff[j] = (coeff[j] << BC_COEF) | - (s[i] & (SZ_COEF - 1)); - - if (i == 5 || i == 15) - coeff[j] <<= 1; - - valid = (valid << 1) | (s[i] >> BC_COEF); - } - - valid |= PRP_RZ_VALID_TBL_LEN(len); - - if (pcdev->resizing[dir].algo == RESIZE_ALGO_BILINEAR) - valid |= PRP_RZ_VALID_BILINEAR; - - if (pcdev->emma_prp->cfg.channel == 1) { - if (dir == RESIZE_DIR_H) { - writel(coeff[0], pcdev->base_emma + - PRP_CH1_RZ_HORI_COEF1); - writel(coeff[1], pcdev->base_emma + - PRP_CH1_RZ_HORI_COEF2); - writel(valid, pcdev->base_emma + - PRP_CH1_RZ_HORI_VALID); - } else { - writel(coeff[0], pcdev->base_emma + - PRP_CH1_RZ_VERT_COEF1); - writel(coeff[1], pcdev->base_emma + - PRP_CH1_RZ_VERT_COEF2); - writel(valid, pcdev->base_emma + - PRP_CH1_RZ_VERT_VALID); - } - } else { - if (dir == RESIZE_DIR_H) { - writel(coeff[0], pcdev->base_emma + - PRP_CH2_RZ_HORI_COEF1); - writel(coeff[1], pcdev->base_emma + - PRP_CH2_RZ_HORI_COEF2); - writel(valid, pcdev->base_emma + - PRP_CH2_RZ_HORI_VALID); - } else { - writel(coeff[0], pcdev->base_emma + - PRP_CH2_RZ_VERT_COEF1); - writel(coeff[1], pcdev->base_emma + - PRP_CH2_RZ_VERT_COEF2); - writel(valid, pcdev->base_emma + - PRP_CH2_RZ_VERT_VALID); - } - } - } -} - -static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct soc_camera_device *icd = soc_camera_from_vb2q(q); - struct soc_camera_host *ici = - to_soc_camera_host(icd->parent); - struct mx2_camera_dev *pcdev = ici->priv; - struct mx2_fmt_cfg *prp = pcdev->emma_prp; - struct vb2_buffer *vb; - struct mx2_buffer *buf; - unsigned long phys; - int bytesperline; - unsigned long flags; - - if (count < 2) - return -ENOBUFS; - - spin_lock_irqsave(&pcdev->lock, flags); - - buf = list_first_entry(&pcdev->capture, struct mx2_buffer, - internal.queue); - buf->internal.bufnum = 0; - vb = &buf->vb.vb2_buf; - - phys = vb2_dma_contig_plane_dma_addr(vb, 0); - mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum); - list_move_tail(pcdev->capture.next, &pcdev->active_bufs); - - buf = list_first_entry(&pcdev->capture, struct mx2_buffer, - internal.queue); - buf->internal.bufnum = 1; - vb = &buf->vb.vb2_buf; - - phys = vb2_dma_contig_plane_dma_addr(vb, 0); - mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum); - list_move_tail(pcdev->capture.next, &pcdev->active_bufs); - - bytesperline = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - if (bytesperline < 0) { - spin_unlock_irqrestore(&pcdev->lock, flags); - return bytesperline; - } - - /* - * I didn't manage to properly enable/disable the prp - * on a per frame basis during running transfers, - * thus we allocate a buffer here and use it to - * discard frames when no buffer is available. - * Feel free to work on this ;) - */ - pcdev->discard_size = icd->user_height * bytesperline; - pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev, - pcdev->discard_size, - &pcdev->discard_buffer_dma, GFP_ATOMIC); - if (!pcdev->discard_buffer) { - spin_unlock_irqrestore(&pcdev->lock, flags); - return -ENOMEM; - } - - pcdev->buf_discard[0].discard = true; - list_add_tail(&pcdev->buf_discard[0].queue, - &pcdev->discard); - - pcdev->buf_discard[1].discard = true; - list_add_tail(&pcdev->buf_discard[1].queue, - &pcdev->discard); - - mx2_prp_resize_commit(pcdev); - - mx27_camera_emma_buf_init(icd, bytesperline); - - if (prp->cfg.channel == 1) { - writel(PRP_CNTL_CH1EN | - PRP_CNTL_CSIEN | - prp->cfg.in_fmt | - prp->cfg.out_fmt | - PRP_CNTL_CH1_LEN | - PRP_CNTL_CH1BYP | - PRP_CNTL_CH1_TSKIP(0) | - PRP_CNTL_IN_TSKIP(0), - pcdev->base_emma + PRP_CNTL); - } else { - writel(PRP_CNTL_CH2EN | - PRP_CNTL_CSIEN | - prp->cfg.in_fmt | - prp->cfg.out_fmt | - PRP_CNTL_CH2_LEN | - PRP_CNTL_CH2_TSKIP(0) | - PRP_CNTL_IN_TSKIP(0), - pcdev->base_emma + PRP_CNTL); - } - spin_unlock_irqrestore(&pcdev->lock, flags); - - return 0; -} - -static void mx2_stop_streaming(struct vb2_queue *q) -{ - struct soc_camera_device *icd = soc_camera_from_vb2q(q); - struct soc_camera_host *ici = - to_soc_camera_host(icd->parent); - struct mx2_camera_dev *pcdev = ici->priv; - struct mx2_fmt_cfg *prp = pcdev->emma_prp; - unsigned long flags; - void *b; - u32 cntl; - - spin_lock_irqsave(&pcdev->lock, flags); - - cntl = readl(pcdev->base_emma + PRP_CNTL); - if (prp->cfg.channel == 1) { - writel(cntl & ~PRP_CNTL_CH1EN, - pcdev->base_emma + PRP_CNTL); - } else { - writel(cntl & ~PRP_CNTL_CH2EN, - pcdev->base_emma + PRP_CNTL); - } - INIT_LIST_HEAD(&pcdev->capture); - INIT_LIST_HEAD(&pcdev->active_bufs); - INIT_LIST_HEAD(&pcdev->discard); - - b = pcdev->discard_buffer; - pcdev->discard_buffer = NULL; - - spin_unlock_irqrestore(&pcdev->lock, flags); - - dma_free_coherent(ici->v4l2_dev.dev, - pcdev->discard_size, b, pcdev->discard_buffer_dma); -} - -static struct vb2_ops mx2_videobuf_ops = { - .queue_setup = mx2_videobuf_setup, - .buf_prepare = mx2_videobuf_prepare, - .buf_queue = mx2_videobuf_queue, - .start_streaming = mx2_start_streaming, - .stop_streaming = mx2_stop_streaming, -}; - -static int mx2_camera_init_videobuf(struct vb2_queue *q, - struct soc_camera_device *icd) -{ - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR; - q->drv_priv = icd; - q->ops = &mx2_videobuf_ops; - q->mem_ops = &vb2_dma_contig_memops; - q->buf_struct_size = sizeof(struct mx2_buffer); - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - - return vb2_queue_init(q); -} - -#define MX2_BUS_FLAGS (V4L2_MBUS_MASTER | \ - V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ - V4L2_MBUS_VSYNC_ACTIVE_LOW | \ - V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ - V4L2_MBUS_HSYNC_ACTIVE_LOW | \ - V4L2_MBUS_PCLK_SAMPLE_RISING | \ - V4L2_MBUS_PCLK_SAMPLE_FALLING | \ - V4L2_MBUS_DATA_ACTIVE_HIGH | \ - V4L2_MBUS_DATA_ACTIVE_LOW) - -static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev) -{ - int count = 0; - - readl(pcdev->base_emma + PRP_CNTL); - writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL); - while (count++ < 100) { - if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST)) - return 0; - barrier(); - udelay(1); - } - - return -ETIMEDOUT; -} - -static int mx2_camera_set_bus_param(struct soc_camera_device *icd) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct mx2_camera_dev *pcdev = ici->priv; - struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; - unsigned long common_flags; - int ret; - int bytesperline; - u32 csicr1 = pcdev->csicr1; - - ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); - if (!ret) { - common_flags = soc_mbus_config_compatible(&cfg, MX2_BUS_FLAGS); - if (!common_flags) { - dev_warn(icd->parent, - "Flags incompatible: camera 0x%x, host 0x%x\n", - cfg.flags, MX2_BUS_FLAGS); - return -EINVAL; - } - } else if (ret != -ENOIOCTLCMD) { - return ret; - } else { - common_flags = MX2_BUS_FLAGS; - } - - if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && - (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { - if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH) - common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; - else - common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; - } - - if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && - (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { - if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING) - common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; - else - common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; - } - - cfg.flags = common_flags; - ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); - if (ret < 0 && ret != -ENOIOCTLCMD) { - dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", - common_flags, ret); - return ret; - } - - csicr1 = (csicr1 & ~CSICR1_FMT_MASK) | pcdev->emma_prp->cfg.csicr1; - - if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) - csicr1 |= CSICR1_REDGE; - if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) - csicr1 |= CSICR1_SOF_POL; - if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) - csicr1 |= CSICR1_HSYNC_POL; - if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC) - csicr1 |= CSICR1_EXT_VSYNC; - if (pcdev->platform_flags & MX2_CAMERA_CCIR) - csicr1 |= CSICR1_CCIR_EN; - if (pcdev->platform_flags & MX2_CAMERA_CCIR_INTERLACE) - csicr1 |= CSICR1_CCIR_MODE; - if (pcdev->platform_flags & MX2_CAMERA_GATED_CLOCK) - csicr1 |= CSICR1_GCLK_MODE; - if (pcdev->platform_flags & MX2_CAMERA_INV_DATA) - csicr1 |= CSICR1_INV_DATA; - - pcdev->csicr1 = csicr1; - - bytesperline = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - if (bytesperline < 0) - return bytesperline; - - ret = mx27_camera_emma_prp_reset(pcdev); - if (ret) - return ret; - - writel(pcdev->csicr1, pcdev->base_csi + CSICR1); - - return 0; -} - -static int mx2_camera_set_crop(struct soc_camera_device *icd, - const struct v4l2_crop *a) -{ - struct v4l2_crop a_writable = *a; - struct v4l2_rect *rect = &a_writable.c; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_subdev_format fmt = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct v4l2_mbus_framefmt *mf = &fmt.format; - int ret; - - soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); - soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096); - - ret = v4l2_subdev_call(sd, video, s_crop, a); - if (ret < 0) - return ret; - - /* The capture device might have changed its output */ - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); - if (ret < 0) - return ret; - - dev_dbg(icd->parent, "Sensor cropped %dx%d\n", - mf->width, mf->height); - - icd->user_width = mf->width; - icd->user_height = mf->height; - - return ret; -} - -static int mx2_camera_get_formats(struct soc_camera_device *icd, - unsigned int idx, - struct soc_camera_format_xlate *xlate) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_mbus_pixelfmt *fmt; - struct device *dev = icd->parent; - struct v4l2_subdev_mbus_code_enum code = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .index = idx, - }; - int ret, formats = 0; - - ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); - if (ret < 0) - /* no more formats */ - return 0; - - fmt = soc_mbus_get_fmtdesc(code.code); - if (!fmt) { - dev_err(dev, "Invalid format code #%u: %d\n", idx, code.code); - return 0; - } - - if (code.code == MEDIA_BUS_FMT_YUYV8_2X8 || - code.code == MEDIA_BUS_FMT_UYVY8_2X8) { - formats++; - if (xlate) { - /* - * CH2 can output YUV420 which is a standard format in - * soc_mediabus.c - */ - xlate->host_fmt = - soc_mbus_get_fmtdesc(MEDIA_BUS_FMT_YUYV8_1_5X8); - xlate->code = code.code; - dev_dbg(dev, "Providing host format %s for sensor code %d\n", - xlate->host_fmt->name, code.code); - xlate++; - } - } - - if (code.code == MEDIA_BUS_FMT_UYVY8_2X8) { - formats++; - if (xlate) { - xlate->host_fmt = - soc_mbus_get_fmtdesc(MEDIA_BUS_FMT_YUYV8_2X8); - xlate->code = code.code; - dev_dbg(dev, "Providing host format %s for sensor code %d\n", - xlate->host_fmt->name, code.code); - xlate++; - } - } - - /* Generic pass-trough */ - formats++; - if (xlate) { - xlate->host_fmt = fmt; - xlate->code = code.code; - xlate++; - } - return formats; -} - -static int mx2_emmaprp_resize(struct mx2_camera_dev *pcdev, - struct v4l2_mbus_framefmt *mf_in, - struct v4l2_pix_format *pix_out, bool apply) -{ - unsigned int num, den; - unsigned long m; - int i, dir; - - for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) { - struct emma_prp_resize tmprsz; - unsigned char *s = tmprsz.s; - int len = 0; - int in, out; - - if (dir == RESIZE_DIR_H) { - in = mf_in->width; - out = pix_out->width; - } else { - in = mf_in->height; - out = pix_out->height; - } - - if (in < out) - return -EINVAL; - else if (in == out) - continue; - - /* Calculate ratio */ - m = gcd(in, out); - num = in / m; - den = out / m; - if (num > RESIZE_NUM_MAX) - return -EINVAL; - - if ((num >= 2 * den) && (den == 1) && - (num < 9) && (!(num & 0x01))) { - int sum = 0; - int j; - - /* Average scaling for >= 2:1 ratios */ - /* Support can be added for num >=9 and odd values */ - - tmprsz.algo = RESIZE_ALGO_AVERAGING; - len = num; - - for (i = 0; i < (len / 2); i++) - s[i] = 8; - - do { - for (i = 0; i < (len / 2); i++) { - s[i] = s[i] >> 1; - sum = 0; - for (j = 0; j < (len / 2); j++) - sum += s[j]; - if (sum == 4) - break; - } - } while (sum != 4); - - for (i = (len / 2); i < len; i++) - s[i] = s[len - i - 1]; - - s[len - 1] |= SZ_COEF; - } else { - /* bilinear scaling for < 2:1 ratios */ - int v; /* overflow counter */ - int coeff, nxt; /* table output */ - int in_pos_inc = 2 * den; - int out_pos = num; - int out_pos_inc = 2 * num; - int init_carry = num - den; - int carry = init_carry; - - tmprsz.algo = RESIZE_ALGO_BILINEAR; - v = den + in_pos_inc; - do { - coeff = v - out_pos; - out_pos += out_pos_inc; - carry += out_pos_inc; - for (nxt = 0; v < out_pos; nxt++) { - v += in_pos_inc; - carry -= in_pos_inc; - } - - if (len > RESIZE_NUM_MAX) - return -EINVAL; - - coeff = ((coeff << BC_COEF) + - (in_pos_inc >> 1)) / in_pos_inc; - - if (coeff >= (SZ_COEF - 1)) - coeff--; - - coeff |= SZ_COEF; - s[len] = (unsigned char)coeff; - len++; - - for (i = 1; i < nxt; i++) { - if (len >= RESIZE_NUM_MAX) - return -EINVAL; - s[len] = 0; - len++; - } - } while (carry != init_carry); - } - tmprsz.len = len; - if (dir == RESIZE_DIR_H) - mf_in->width = pix_out->width; - else - mf_in->height = pix_out->height; - - if (apply) - memcpy(&pcdev->resizing[dir], &tmprsz, sizeof(tmprsz)); - } - return 0; -} - -static int mx2_camera_set_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct mx2_camera_dev *pcdev = ici->priv; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct v4l2_mbus_framefmt *mf = &format.format; - int ret; - - dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n", - __func__, pix->width, pix->height); - - xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); - if (!xlate) { - dev_warn(icd->parent, "Format %x not found\n", - pix->pixelformat); - return -EINVAL; - } - - mf->width = pix->width; - mf->height = pix->height; - mf->field = pix->field; - mf->colorspace = pix->colorspace; - mf->code = xlate->code; - - ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); - if (ret < 0 && ret != -ENOIOCTLCMD) - return ret; - - /* Store width and height returned by the sensor for resizing */ - pcdev->s_width = mf->width; - pcdev->s_height = mf->height; - dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n", - __func__, pcdev->s_width, pcdev->s_height); - - pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, - xlate->host_fmt->fourcc); - - memset(pcdev->resizing, 0, sizeof(pcdev->resizing)); - if ((mf->width != pix->width || mf->height != pix->height) && - pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { - if (mx2_emmaprp_resize(pcdev, mf, pix, true) < 0) - dev_dbg(icd->parent, "%s: can't resize\n", __func__); - } - - if (mf->code != xlate->code) - return -EINVAL; - - pix->width = mf->width; - pix->height = mf->height; - pix->field = mf->field; - pix->colorspace = mf->colorspace; - icd->current_fmt = xlate; - - dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", - __func__, pix->width, pix->height); - - return 0; -} - -static int mx2_camera_try_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_subdev_pad_config pad_cfg; - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_TRY, - }; - struct v4l2_mbus_framefmt *mf = &format.format; - __u32 pixfmt = pix->pixelformat; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct mx2_camera_dev *pcdev = ici->priv; - struct mx2_fmt_cfg *emma_prp; - int ret; - - dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n", - __func__, pix->width, pix->height); - - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (pixfmt && !xlate) { - dev_warn(icd->parent, "Format %x not found\n", pixfmt); - return -EINVAL; - } - - /* - * limit to MX27 hardware capabilities: width must be a multiple of 8 as - * requested by the CSI. (Table 39-2 in the i.MX27 Reference Manual). - */ - pix->width &= ~0x7; - - /* limit to sensor capabilities */ - mf->width = pix->width; - mf->height = pix->height; - mf->field = pix->field; - mf->colorspace = pix->colorspace; - mf->code = xlate->code; - - ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); - if (ret < 0) - return ret; - - dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n", - __func__, pcdev->s_width, pcdev->s_height); - - /* If the sensor does not support image size try PrP resizing */ - emma_prp = mx27_emma_prp_get_format(xlate->code, - xlate->host_fmt->fourcc); - - if ((mf->width != pix->width || mf->height != pix->height) && - emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { - if (mx2_emmaprp_resize(pcdev, mf, pix, false) < 0) - dev_dbg(icd->parent, "%s: can't resize\n", __func__); - } - - if (mf->field == V4L2_FIELD_ANY) - mf->field = V4L2_FIELD_NONE; - /* - * Driver supports interlaced images provided they have - * both fields so that they can be processed as if they - * were progressive. - */ - if (mf->field != V4L2_FIELD_NONE && !V4L2_FIELD_HAS_BOTH(mf->field)) { - dev_err(icd->parent, "Field type %d unsupported.\n", - mf->field); - return -EINVAL; - } - - pix->width = mf->width; - pix->height = mf->height; - pix->field = mf->field; - pix->colorspace = mf->colorspace; - - dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", - __func__, pix->width, pix->height); - - return 0; -} - -static int mx2_camera_querycap(struct soc_camera_host *ici, - struct v4l2_capability *cap) -{ - /* cap->name is set by the friendly caller:-> */ - strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - - return 0; -} - -static unsigned int mx2_camera_poll(struct file *file, poll_table *pt) -{ - struct soc_camera_device *icd = file->private_data; - - return vb2_poll(&icd->vb2_vidq, file, pt); -} - -static struct soc_camera_host_ops mx2_soc_camera_host_ops = { - .owner = THIS_MODULE, - .add = mx2_camera_add_device, - .remove = mx2_camera_remove_device, - .clock_start = mx2_camera_clock_start, - .clock_stop = mx2_camera_clock_stop, - .set_fmt = mx2_camera_set_fmt, - .set_crop = mx2_camera_set_crop, - .get_formats = mx2_camera_get_formats, - .try_fmt = mx2_camera_try_fmt, - .init_videobuf2 = mx2_camera_init_videobuf, - .poll = mx2_camera_poll, - .querycap = mx2_camera_querycap, - .set_bus_param = mx2_camera_set_bus_param, -}; - -static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, - int bufnum, bool err) -{ -#ifdef DEBUG - struct mx2_fmt_cfg *prp = pcdev->emma_prp; -#endif - struct mx2_buf_internal *ibuf; - struct mx2_buffer *buf; - struct vb2_buffer *vb; - struct vb2_v4l2_buffer *vbuf; - unsigned long phys; - - ibuf = list_first_entry(&pcdev->active_bufs, struct mx2_buf_internal, - queue); - - BUG_ON(ibuf->bufnum != bufnum); - - if (ibuf->discard) { - /* - * Discard buffer must not be returned to user space. - * Just return it to the discard queue. - */ - list_move_tail(pcdev->active_bufs.next, &pcdev->discard); - } else { - buf = mx2_ibuf_to_buf(ibuf); - - vb = &buf->vb.vb2_buf; - vbuf = to_vb2_v4l2_buffer(vb); -#ifdef DEBUG - phys = vb2_dma_contig_plane_dma_addr(vb, 0); - if (prp->cfg.channel == 1) { - if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + - 4 * bufnum) != phys) { - dev_err(pcdev->dev, "%lx != %x\n", phys, - readl(pcdev->base_emma + - PRP_DEST_RGB1_PTR + 4 * bufnum)); - } - } else { - if (readl(pcdev->base_emma + PRP_DEST_Y_PTR - - 0x14 * bufnum) != phys) { - dev_err(pcdev->dev, "%lx != %x\n", phys, - readl(pcdev->base_emma + - PRP_DEST_Y_PTR - 0x14 * bufnum)); - } - } -#endif - dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb, - vb2_plane_vaddr(vb, 0), - vb2_get_plane_payload(vb, 0)); - - list_del_init(&buf->internal.queue); - vb->timestamp = ktime_get_ns(); - vbuf->sequence = pcdev->frame_count; - if (err) - vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); - else - vb2_buffer_done(vb, VB2_BUF_STATE_DONE); - } - - pcdev->frame_count++; - - if (list_empty(&pcdev->capture)) { - if (list_empty(&pcdev->discard)) { - dev_warn(pcdev->dev, "%s: trying to access empty discard list\n", - __func__); - return; - } - - ibuf = list_first_entry(&pcdev->discard, - struct mx2_buf_internal, queue); - ibuf->bufnum = bufnum; - - list_move_tail(pcdev->discard.next, &pcdev->active_bufs); - mx27_update_emma_buf(pcdev, pcdev->discard_buffer_dma, bufnum); - return; - } - - buf = list_first_entry(&pcdev->capture, struct mx2_buffer, - internal.queue); - - buf->internal.bufnum = bufnum; - - list_move_tail(pcdev->capture.next, &pcdev->active_bufs); - - vb = &buf->vb.vb2_buf; - - phys = vb2_dma_contig_plane_dma_addr(vb, 0); - mx27_update_emma_buf(pcdev, phys, bufnum); -} - -static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) -{ - struct mx2_camera_dev *pcdev = data; - unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS); - struct mx2_buf_internal *ibuf; - - spin_lock(&pcdev->lock); - - if (list_empty(&pcdev->active_bufs)) { - dev_warn(pcdev->dev, "%s: called while active list is empty\n", - __func__); - - if (!status) { - spin_unlock(&pcdev->lock); - return IRQ_NONE; - } - } - - if (status & (1 << 7)) { /* overflow */ - u32 cntl = readl(pcdev->base_emma + PRP_CNTL); - writel(cntl & ~(PRP_CNTL_CH1EN | PRP_CNTL_CH2EN), - pcdev->base_emma + PRP_CNTL); - writel(cntl, pcdev->base_emma + PRP_CNTL); - - ibuf = list_first_entry(&pcdev->active_bufs, - struct mx2_buf_internal, queue); - mx27_camera_frame_done_emma(pcdev, - ibuf->bufnum, true); - - status &= ~(1 << 7); - } else if (((status & (3 << 5)) == (3 << 5)) || - ((status & (3 << 3)) == (3 << 3))) { - /* - * Both buffers have triggered, process the one we're expecting - * to first - */ - ibuf = list_first_entry(&pcdev->active_bufs, - struct mx2_buf_internal, queue); - mx27_camera_frame_done_emma(pcdev, ibuf->bufnum, false); - status &= ~(1 << (6 - ibuf->bufnum)); /* mark processed */ - } else if ((status & (1 << 6)) || (status & (1 << 4))) { - mx27_camera_frame_done_emma(pcdev, 0, false); - } else if ((status & (1 << 5)) || (status & (1 << 3))) { - mx27_camera_frame_done_emma(pcdev, 1, false); - } - - spin_unlock(&pcdev->lock); - writel(status, pcdev->base_emma + PRP_INTRSTATUS); - - return IRQ_HANDLED; -} - -static int mx27_camera_emma_init(struct platform_device *pdev) -{ - struct mx2_camera_dev *pcdev = platform_get_drvdata(pdev); - struct resource *res_emma; - int irq_emma; - int err = 0; - - res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1); - irq_emma = platform_get_irq(pdev, 1); - if (!res_emma || !irq_emma) { - dev_err(pcdev->dev, "no EMMA resources\n"); - err = -ENODEV; - goto out; - } - - pcdev->base_emma = devm_ioremap_resource(pcdev->dev, res_emma); - if (IS_ERR(pcdev->base_emma)) { - err = PTR_ERR(pcdev->base_emma); - goto out; - } - - err = devm_request_irq(pcdev->dev, irq_emma, mx27_camera_emma_irq, 0, - MX2_CAM_DRV_NAME, pcdev); - if (err) { - dev_err(pcdev->dev, "Camera EMMA interrupt register failed\n"); - goto out; - } - - pcdev->clk_emma_ipg = devm_clk_get(pcdev->dev, "emma-ipg"); - if (IS_ERR(pcdev->clk_emma_ipg)) { - err = PTR_ERR(pcdev->clk_emma_ipg); - goto out; - } - - clk_prepare_enable(pcdev->clk_emma_ipg); - - pcdev->clk_emma_ahb = devm_clk_get(pcdev->dev, "emma-ahb"); - if (IS_ERR(pcdev->clk_emma_ahb)) { - err = PTR_ERR(pcdev->clk_emma_ahb); - goto exit_clk_emma_ipg; - } - - clk_prepare_enable(pcdev->clk_emma_ahb); - - err = mx27_camera_emma_prp_reset(pcdev); - if (err) - goto exit_clk_emma_ahb; - - return err; - -exit_clk_emma_ahb: - clk_disable_unprepare(pcdev->clk_emma_ahb); -exit_clk_emma_ipg: - clk_disable_unprepare(pcdev->clk_emma_ipg); -out: - return err; -} - -static int mx2_camera_probe(struct platform_device *pdev) -{ - struct mx2_camera_dev *pcdev; - struct resource *res_csi; - int irq_csi; - int err = 0; - - dev_dbg(&pdev->dev, "initialising\n"); - - res_csi = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq_csi = platform_get_irq(pdev, 0); - if (res_csi == NULL || irq_csi < 0) { - dev_err(&pdev->dev, "Missing platform resources data\n"); - err = -ENODEV; - goto exit; - } - - pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL); - if (!pcdev) { - dev_err(&pdev->dev, "Could not allocate pcdev\n"); - err = -ENOMEM; - goto exit; - } - - pcdev->clk_csi_ahb = devm_clk_get(&pdev->dev, "ahb"); - if (IS_ERR(pcdev->clk_csi_ahb)) { - dev_err(&pdev->dev, "Could not get csi ahb clock\n"); - err = PTR_ERR(pcdev->clk_csi_ahb); - goto exit; - } - - pcdev->clk_csi_per = devm_clk_get(&pdev->dev, "per"); - if (IS_ERR(pcdev->clk_csi_per)) { - dev_err(&pdev->dev, "Could not get csi per clock\n"); - err = PTR_ERR(pcdev->clk_csi_per); - goto exit; - } - - pcdev->pdata = pdev->dev.platform_data; - if (pcdev->pdata) { - long rate; - - pcdev->platform_flags = pcdev->pdata->flags; - - rate = clk_round_rate(pcdev->clk_csi_per, - pcdev->pdata->clk * 2); - if (rate <= 0) { - err = -ENODEV; - goto exit; - } - err = clk_set_rate(pcdev->clk_csi_per, rate); - if (err < 0) - goto exit; - } - - INIT_LIST_HEAD(&pcdev->capture); - INIT_LIST_HEAD(&pcdev->active_bufs); - INIT_LIST_HEAD(&pcdev->discard); - spin_lock_init(&pcdev->lock); - - pcdev->base_csi = devm_ioremap_resource(&pdev->dev, res_csi); - if (IS_ERR(pcdev->base_csi)) { - err = PTR_ERR(pcdev->base_csi); - goto exit; - } - - pcdev->dev = &pdev->dev; - platform_set_drvdata(pdev, pcdev); - - err = mx27_camera_emma_init(pdev); - if (err) - goto exit; - - /* - * We're done with drvdata here. Clear the pointer so that - * v4l2 core can start using drvdata on its purpose. - */ - platform_set_drvdata(pdev, NULL); - - pcdev->soc_host.drv_name = MX2_CAM_DRV_NAME, - pcdev->soc_host.ops = &mx2_soc_camera_host_ops, - pcdev->soc_host.priv = pcdev; - pcdev->soc_host.v4l2_dev.dev = &pdev->dev; - pcdev->soc_host.nr = pdev->id; - - pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); - if (IS_ERR(pcdev->alloc_ctx)) { - err = PTR_ERR(pcdev->alloc_ctx); - goto eallocctx; - } - err = soc_camera_host_register(&pcdev->soc_host); - if (err) - goto exit_free_emma; - - dev_info(&pdev->dev, "MX2 Camera (CSI) driver probed, clock frequency: %ld\n", - clk_get_rate(pcdev->clk_csi_per)); - - return 0; - -exit_free_emma: - vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); -eallocctx: - clk_disable_unprepare(pcdev->clk_emma_ipg); - clk_disable_unprepare(pcdev->clk_emma_ahb); -exit: - return err; -} - -static int mx2_camera_remove(struct platform_device *pdev) -{ - struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); - struct mx2_camera_dev *pcdev = container_of(soc_host, - struct mx2_camera_dev, soc_host); - - soc_camera_host_unregister(&pcdev->soc_host); - - vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); - - clk_disable_unprepare(pcdev->clk_emma_ipg); - clk_disable_unprepare(pcdev->clk_emma_ahb); - - dev_info(&pdev->dev, "MX2 Camera driver unloaded\n"); - - return 0; -} - -static struct platform_driver mx2_camera_driver = { - .driver = { - .name = MX2_CAM_DRV_NAME, - }, - .id_table = mx2_camera_devtype, - .remove = mx2_camera_remove, -}; - -module_platform_driver_probe(mx2_camera_driver, mx2_camera_probe); - -MODULE_DESCRIPTION("i.MX27 SoC Camera Host driver"); -MODULE_AUTHOR("Sascha Hauer "); -MODULE_LICENSE("GPL"); -MODULE_VERSION(MX2_CAM_VERSION); diff --git a/drivers/staging/media/mx3/Kconfig b/drivers/staging/media/mx3/Kconfig deleted file mode 100644 index 595d5fe7c..000000000 --- a/drivers/staging/media/mx3/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config VIDEO_MX3 - tristate "i.MX3x Camera Sensor Interface driver" - depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA - depends on MX3_IPU || COMPILE_TEST - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - ---help--- - This is a v4l2 driver for the i.MX3x Camera Sensor Interface - - This driver is deprecated: it should become a stand-alone driver - instead of using the soc-camera framework. - - Unless someone is willing to take this on (unlikely with such - ancient hardware) it is going to be removed from the kernel - soon. diff --git a/drivers/staging/media/mx3/Makefile b/drivers/staging/media/mx3/Makefile deleted file mode 100644 index 6d91dcd80..000000000 --- a/drivers/staging/media/mx3/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# Makefile for i.MX3x Camera Sensor driver - -obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o diff --git a/drivers/staging/media/mx3/TODO b/drivers/staging/media/mx3/TODO deleted file mode 100644 index bc68fa443..000000000 --- a/drivers/staging/media/mx3/TODO +++ /dev/null @@ -1,10 +0,0 @@ -This driver is deprecated: it should become a stand-alone driver instead of -using the soc-camera framework. - -Unless someone is willing to take this on (unlikely with such ancient -hardware) it is going to be removed from the kernel soon. - -Note that trivial patches will not be accepted anymore, only a full conversion. - -If you want to convert this driver, please contact the linux-media mailinglist -(see http://linuxtv.org/lists.php). diff --git a/drivers/staging/media/mx3/mx3_camera.c b/drivers/staging/media/mx3/mx3_camera.c deleted file mode 100644 index aa39e9569..000000000 --- a/drivers/staging/media/mx3/mx3_camera.c +++ /dev/null @@ -1,1264 +0,0 @@ -/* - * V4L2 Driver for i.MX3x camera host - * - * Copyright (C) 2008 - * Guennadi Liakhovetski, DENX Software Engineering, - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#define MX3_CAM_DRV_NAME "mx3-camera" - -/* CMOS Sensor Interface Registers */ -#define CSI_REG_START 0x60 - -#define CSI_SENS_CONF (0x60 - CSI_REG_START) -#define CSI_SENS_FRM_SIZE (0x64 - CSI_REG_START) -#define CSI_ACT_FRM_SIZE (0x68 - CSI_REG_START) -#define CSI_OUT_FRM_CTRL (0x6C - CSI_REG_START) -#define CSI_TST_CTRL (0x70 - CSI_REG_START) -#define CSI_CCIR_CODE_1 (0x74 - CSI_REG_START) -#define CSI_CCIR_CODE_2 (0x78 - CSI_REG_START) -#define CSI_CCIR_CODE_3 (0x7C - CSI_REG_START) -#define CSI_FLASH_STROBE_1 (0x80 - CSI_REG_START) -#define CSI_FLASH_STROBE_2 (0x84 - CSI_REG_START) - -#define CSI_SENS_CONF_VSYNC_POL_SHIFT 0 -#define CSI_SENS_CONF_HSYNC_POL_SHIFT 1 -#define CSI_SENS_CONF_DATA_POL_SHIFT 2 -#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3 -#define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4 -#define CSI_SENS_CONF_SENS_CLKSRC_SHIFT 7 -#define CSI_SENS_CONF_DATA_FMT_SHIFT 8 -#define CSI_SENS_CONF_DATA_WIDTH_SHIFT 10 -#define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15 -#define CSI_SENS_CONF_DIVRATIO_SHIFT 16 - -#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 (0UL << CSI_SENS_CONF_DATA_FMT_SHIFT) -#define CSI_SENS_CONF_DATA_FMT_YUV422 (2UL << CSI_SENS_CONF_DATA_FMT_SHIFT) -#define CSI_SENS_CONF_DATA_FMT_BAYER (3UL << CSI_SENS_CONF_DATA_FMT_SHIFT) - -#define MAX_VIDEO_MEM 16 - -struct mx3_camera_buffer { - /* common v4l buffer stuff -- must be first */ - struct vb2_v4l2_buffer vb; - struct list_head queue; - - /* One descriptot per scatterlist (per frame) */ - struct dma_async_tx_descriptor *txd; - - /* We have to "build" a scatterlist ourselves - one element per frame */ - struct scatterlist sg; -}; - -/** - * struct mx3_camera_dev - i.MX3x camera (CSI) object - * @dev: camera device, to which the coherent buffer is attached - * @icd: currently attached camera sensor - * @clk: pointer to clock - * @base: remapped register base address - * @pdata: platform data - * @platform_flags: platform flags - * @mclk: master clock frequency in Hz - * @capture: list of capture videobuffers - * @lock: protects video buffer lists - * @active: active video buffer - * @idmac_channel: array of pointers to IPU DMAC DMA channels - * @soc_host: embedded soc_host object - */ -struct mx3_camera_dev { - /* - * i.MX3x is only supposed to handle one camera on its Camera Sensor - * Interface. If anyone ever builds hardware to enable more than one - * camera _simultaneously_, they will have to modify this driver too - */ - struct clk *clk; - - void __iomem *base; - - struct mx3_camera_pdata *pdata; - - unsigned long platform_flags; - unsigned long mclk; - u16 width_flags; /* max 15 bits */ - - struct list_head capture; - spinlock_t lock; /* Protects video buffer lists */ - struct mx3_camera_buffer *active; - size_t buf_total; - struct vb2_alloc_ctx *alloc_ctx; - enum v4l2_field field; - int sequence; - - /* IDMAC / dmaengine interface */ - struct idmac_channel *idmac_channel[1]; /* We need one channel */ - - struct soc_camera_host soc_host; -}; - -struct dma_chan_request { - struct mx3_camera_dev *mx3_cam; - enum ipu_channel id; -}; - -static u32 csi_reg_read(struct mx3_camera_dev *mx3, off_t reg) -{ - return __raw_readl(mx3->base + reg); -} - -static void csi_reg_write(struct mx3_camera_dev *mx3, u32 value, off_t reg) -{ - __raw_writel(value, mx3->base + reg); -} - -static struct mx3_camera_buffer *to_mx3_vb(struct vb2_v4l2_buffer *vb) -{ - return container_of(vb, struct mx3_camera_buffer, vb); -} - -/* Called from the IPU IDMAC ISR */ -static void mx3_cam_dma_done(void *arg) -{ - struct idmac_tx_desc *desc = to_tx_desc(arg); - struct dma_chan *chan = desc->txd.chan; - struct idmac_channel *ichannel = to_idmac_chan(chan); - struct mx3_camera_dev *mx3_cam = ichannel->client; - - dev_dbg(chan->device->dev, "callback cookie %d, active DMA %pad\n", - desc->txd.cookie, mx3_cam->active ? &sg_dma_address(&mx3_cam->active->sg) : NULL); - - spin_lock(&mx3_cam->lock); - if (mx3_cam->active) { - struct vb2_v4l2_buffer *vb = &mx3_cam->active->vb; - struct mx3_camera_buffer *buf = to_mx3_vb(vb); - - list_del_init(&buf->queue); - vb->vb2_buf.timestamp = ktime_get_ns(); - vb->field = mx3_cam->field; - vb->sequence = mx3_cam->sequence++; - vb2_buffer_done(&vb->vb2_buf, VB2_BUF_STATE_DONE); - } - - if (list_empty(&mx3_cam->capture)) { - mx3_cam->active = NULL; - spin_unlock(&mx3_cam->lock); - - /* - * stop capture - without further buffers IPU_CHA_BUF0_RDY will - * not get updated - */ - return; - } - - mx3_cam->active = list_entry(mx3_cam->capture.next, - struct mx3_camera_buffer, queue); - spin_unlock(&mx3_cam->lock); -} - -/* - * Videobuf operations - */ - -/* - * Calculate the __buffer__ (not data) size and number of buffers. - */ -static int mx3_videobuf_setup(struct vb2_queue *vq, - unsigned int *count, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) -{ - struct soc_camera_device *icd = soc_camera_from_vb2q(vq); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - - if (!mx3_cam->idmac_channel[0]) - return -EINVAL; - - alloc_ctxs[0] = mx3_cam->alloc_ctx; - - if (!vq->num_buffers) - mx3_cam->sequence = 0; - - if (!*count) - *count = 2; - - /* Called from VIDIOC_REQBUFS or in compatibility mode */ - if (!*num_planes) - sizes[0] = icd->sizeimage; - else if (sizes[0] < icd->sizeimage) - return -EINVAL; - - /* If *num_planes != 0, we have already verified *count. */ - if (sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024) - *count = (MAX_VIDEO_MEM * 1024 * 1024 - mx3_cam->buf_total) / - sizes[0]; - - *num_planes = 1; - - return 0; -} - -static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc) -{ - /* Add more formats as need arises and test possibilities appear... */ - switch (fourcc) { - case V4L2_PIX_FMT_RGB24: - return IPU_PIX_FMT_RGB24; - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_RGB565: - default: - return IPU_PIX_FMT_GENERIC; - } -} - -static void mx3_videobuf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct mx3_camera_buffer *buf = to_mx3_vb(vbuf); - struct scatterlist *sg = &buf->sg; - struct dma_async_tx_descriptor *txd; - struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; - struct idmac_video_param *video = &ichan->params.video; - const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt; - dma_cookie_t cookie; - size_t new_size; - - new_size = icd->sizeimage; - - if (vb2_plane_size(vb, 0) < new_size) { - dev_err(icd->parent, "Buffer #%d too small (%lu < %zu)\n", - vbuf->vb2_buf.index, vb2_plane_size(vb, 0), new_size); - goto error; - } - - if (!buf->txd) { - sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0); - sg_dma_len(sg) = new_size; - - txd = dmaengine_prep_slave_sg( - &ichan->dma_chan, sg, 1, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT); - if (!txd) - goto error; - - txd->callback_param = txd; - txd->callback = mx3_cam_dma_done; - - buf->txd = txd; - } else { - txd = buf->txd; - } - - vb2_set_plane_payload(vb, 0, new_size); - - /* This is the configuration of one sg-element */ - video->out_pixel_fmt = fourcc_to_ipu_pix(host_fmt->fourcc); - - if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) { - /* - * If the IPU DMA channel is configured to transfer generic - * 8-bit data, we have to set up the geometry parameters - * correctly, according to the current pixel format. The DMA - * horizontal parameters in this case are expressed in bytes, - * not in pixels. - */ - video->out_width = icd->bytesperline; - video->out_height = icd->user_height; - video->out_stride = icd->bytesperline; - } else { - /* - * For IPU known formats the pixel unit will be managed - * successfully by the IPU code - */ - video->out_width = icd->user_width; - video->out_height = icd->user_height; - video->out_stride = icd->user_width; - } - -#ifdef DEBUG - /* helps to see what DMA actually has written */ - if (vb2_plane_vaddr(vb, 0)) - memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); -#endif - - spin_lock_irq(&mx3_cam->lock); - list_add_tail(&buf->queue, &mx3_cam->capture); - - if (!mx3_cam->active) - mx3_cam->active = buf; - - spin_unlock_irq(&mx3_cam->lock); - - cookie = txd->tx_submit(txd); - dev_dbg(icd->parent, "Submitted cookie %d DMA %pad\n", - cookie, &sg_dma_address(&buf->sg)); - - if (cookie >= 0) - return; - - spin_lock_irq(&mx3_cam->lock); - - /* Submit error */ - list_del_init(&buf->queue); - - if (mx3_cam->active == buf) - mx3_cam->active = NULL; - - spin_unlock_irq(&mx3_cam->lock); -error: - vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); -} - -static void mx3_videobuf_release(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct mx3_camera_buffer *buf = to_mx3_vb(vbuf); - struct dma_async_tx_descriptor *txd = buf->txd; - unsigned long flags; - - dev_dbg(icd->parent, - "Release%s DMA %pad, queue %sempty\n", - mx3_cam->active == buf ? " active" : "", &sg_dma_address(&buf->sg), - list_empty(&buf->queue) ? "" : "not "); - - spin_lock_irqsave(&mx3_cam->lock, flags); - - if (mx3_cam->active == buf) - mx3_cam->active = NULL; - - /* Doesn't hurt also if the list is empty */ - list_del_init(&buf->queue); - - if (txd) { - buf->txd = NULL; - if (mx3_cam->idmac_channel[0]) - async_tx_ack(txd); - } - - spin_unlock_irqrestore(&mx3_cam->lock, flags); - - mx3_cam->buf_total -= vb2_plane_size(vb, 0); -} - -static int mx3_videobuf_init(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct mx3_camera_buffer *buf = to_mx3_vb(vbuf); - - if (!buf->txd) { - /* This is for locking debugging only */ - INIT_LIST_HEAD(&buf->queue); - sg_init_table(&buf->sg, 1); - - mx3_cam->buf_total += vb2_plane_size(vb, 0); - } - - return 0; -} - -static void mx3_stop_streaming(struct vb2_queue *q) -{ - struct soc_camera_device *icd = soc_camera_from_vb2q(q); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; - struct mx3_camera_buffer *buf, *tmp; - unsigned long flags; - - if (ichan) - dmaengine_pause(&ichan->dma_chan); - - spin_lock_irqsave(&mx3_cam->lock, flags); - - mx3_cam->active = NULL; - - list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) { - list_del_init(&buf->queue); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); - } - - spin_unlock_irqrestore(&mx3_cam->lock, flags); -} - -static struct vb2_ops mx3_videobuf_ops = { - .queue_setup = mx3_videobuf_setup, - .buf_queue = mx3_videobuf_queue, - .buf_cleanup = mx3_videobuf_release, - .buf_init = mx3_videobuf_init, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .stop_streaming = mx3_stop_streaming, -}; - -static int mx3_camera_init_videobuf(struct vb2_queue *q, - struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR; - q->drv_priv = icd; - q->ops = &mx3_videobuf_ops; - q->mem_ops = &vb2_dma_contig_memops; - q->buf_struct_size = sizeof(struct mx3_camera_buffer); - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->lock = &ici->host_lock; - - return vb2_queue_init(q); -} - -/* First part of ipu_csi_init_interface() */ -static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam) -{ - u32 conf; - long rate; - - /* Set default size: ipu_csi_set_window_size() */ - csi_reg_write(mx3_cam, (640 - 1) | ((480 - 1) << 16), CSI_ACT_FRM_SIZE); - /* ...and position to 0:0: ipu_csi_set_window_pos() */ - conf = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000; - csi_reg_write(mx3_cam, conf, CSI_OUT_FRM_CTRL); - - /* We use only gated clock synchronisation mode so far */ - conf = 0 << CSI_SENS_CONF_SENS_PRTCL_SHIFT; - - /* Set generic data, platform-biggest bus-width */ - conf |= CSI_SENS_CONF_DATA_FMT_BAYER; - - if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) - conf |= 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; - else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) - conf |= 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; - else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) - conf |= 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; - else/* if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)*/ - conf |= 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; - - if (mx3_cam->platform_flags & MX3_CAMERA_CLK_SRC) - conf |= 1 << CSI_SENS_CONF_SENS_CLKSRC_SHIFT; - if (mx3_cam->platform_flags & MX3_CAMERA_EXT_VSYNC) - conf |= 1 << CSI_SENS_CONF_EXT_VSYNC_SHIFT; - if (mx3_cam->platform_flags & MX3_CAMERA_DP) - conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; - if (mx3_cam->platform_flags & MX3_CAMERA_PCP) - conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; - if (mx3_cam->platform_flags & MX3_CAMERA_HSP) - conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; - if (mx3_cam->platform_flags & MX3_CAMERA_VSP) - conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; - - /* ipu_csi_init_interface() */ - csi_reg_write(mx3_cam, conf, CSI_SENS_CONF); - - clk_prepare_enable(mx3_cam->clk); - rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk); - dev_dbg(mx3_cam->soc_host.v4l2_dev.dev, "Set SENS_CONF to %x, rate %ld\n", conf, rate); - if (rate) - clk_set_rate(mx3_cam->clk, rate); -} - -static int mx3_camera_add_device(struct soc_camera_device *icd) -{ - dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n", - icd->devnum); - - return 0; -} - -static void mx3_camera_remove_device(struct soc_camera_device *icd) -{ - dev_info(icd->parent, "MX3 Camera driver detached from camera %d\n", - icd->devnum); -} - -/* Called with .host_lock held */ -static int mx3_camera_clock_start(struct soc_camera_host *ici) -{ - struct mx3_camera_dev *mx3_cam = ici->priv; - - mx3_camera_activate(mx3_cam); - - mx3_cam->buf_total = 0; - - return 0; -} - -/* Called with .host_lock held */ -static void mx3_camera_clock_stop(struct soc_camera_host *ici) -{ - struct mx3_camera_dev *mx3_cam = ici->priv; - struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; - - if (*ichan) { - dma_release_channel(&(*ichan)->dma_chan); - *ichan = NULL; - } - - clk_disable_unprepare(mx3_cam->clk); -} - -static int test_platform_param(struct mx3_camera_dev *mx3_cam, - unsigned char buswidth, unsigned long *flags) -{ - /* - * If requested data width is supported by the platform, use it or any - * possible lower value - i.MX31 is smart enough to shift bits - */ - if (buswidth > fls(mx3_cam->width_flags)) - return -EINVAL; - - /* - * Platform specified synchronization and pixel clock polarities are - * only a recommendation and are only used during probing. MX3x - * camera interface only works in master mode, i.e., uses HSYNC and - * VSYNC signals from the sensor - */ - *flags = V4L2_MBUS_MASTER | - V4L2_MBUS_HSYNC_ACTIVE_HIGH | - V4L2_MBUS_HSYNC_ACTIVE_LOW | - V4L2_MBUS_VSYNC_ACTIVE_HIGH | - V4L2_MBUS_VSYNC_ACTIVE_LOW | - V4L2_MBUS_PCLK_SAMPLE_RISING | - V4L2_MBUS_PCLK_SAMPLE_FALLING | - V4L2_MBUS_DATA_ACTIVE_HIGH | - V4L2_MBUS_DATA_ACTIVE_LOW; - - return 0; -} - -static int mx3_camera_try_bus_param(struct soc_camera_device *icd, - const unsigned int depth) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; - unsigned long bus_flags, common_flags; - int ret = test_platform_param(mx3_cam, depth, &bus_flags); - - dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret); - - if (ret < 0) - return ret; - - ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); - if (!ret) { - common_flags = soc_mbus_config_compatible(&cfg, - bus_flags); - if (!common_flags) { - dev_warn(icd->parent, - "Flags incompatible: camera 0x%x, host 0x%lx\n", - cfg.flags, bus_flags); - return -EINVAL; - } - } else if (ret != -ENOIOCTLCMD) { - return ret; - } - - return 0; -} - -static bool chan_filter(struct dma_chan *chan, void *arg) -{ - struct dma_chan_request *rq = arg; - struct mx3_camera_pdata *pdata; - - if (!imx_dma_is_ipu(chan)) - return false; - - if (!rq) - return false; - - pdata = rq->mx3_cam->soc_host.v4l2_dev.dev->platform_data; - - return rq->id == chan->chan_id && - pdata->dma_dev == chan->device->dev; -} - -static const struct soc_mbus_pixelfmt mx3_camera_formats[] = { - { - .fourcc = V4L2_PIX_FMT_SBGGR8, - .name = "Bayer BGGR (sRGB) 8 bit", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_NONE, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, { - .fourcc = V4L2_PIX_FMT_GREY, - .name = "Monochrome 8 bit", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_NONE, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}; - -/* This will be corrected as we get more formats */ -static bool mx3_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) -{ - return fmt->packing == SOC_MBUS_PACKING_NONE || - (fmt->bits_per_sample == 8 && - fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || - (fmt->bits_per_sample > 8 && - fmt->packing == SOC_MBUS_PACKING_EXTEND16); -} - -static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int idx, - struct soc_camera_format_xlate *xlate) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct device *dev = icd->parent; - int formats = 0, ret; - struct v4l2_subdev_mbus_code_enum code = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .index = idx, - }; - const struct soc_mbus_pixelfmt *fmt; - - ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); - if (ret < 0) - /* No more formats */ - return 0; - - fmt = soc_mbus_get_fmtdesc(code.code); - if (!fmt) { - dev_warn(icd->parent, - "Unsupported format code #%u: 0x%x\n", idx, code.code); - return 0; - } - - /* This also checks support for the requested bits-per-sample */ - ret = mx3_camera_try_bus_param(icd, fmt->bits_per_sample); - if (ret < 0) - return 0; - - switch (code.code) { - case MEDIA_BUS_FMT_SBGGR10_1X10: - formats++; - if (xlate) { - xlate->host_fmt = &mx3_camera_formats[0]; - xlate->code = code.code; - xlate++; - dev_dbg(dev, "Providing format %s using code 0x%x\n", - mx3_camera_formats[0].name, code.code); - } - break; - case MEDIA_BUS_FMT_Y10_1X10: - formats++; - if (xlate) { - xlate->host_fmt = &mx3_camera_formats[1]; - xlate->code = code.code; - xlate++; - dev_dbg(dev, "Providing format %s using code 0x%x\n", - mx3_camera_formats[1].name, code.code); - } - break; - default: - if (!mx3_camera_packing_supported(fmt)) - return 0; - } - - /* Generic pass-through */ - formats++; - if (xlate) { - xlate->host_fmt = fmt; - xlate->code = code.code; - dev_dbg(dev, "Providing format %c%c%c%c in pass-through mode\n", - (fmt->fourcc >> (0*8)) & 0xFF, - (fmt->fourcc >> (1*8)) & 0xFF, - (fmt->fourcc >> (2*8)) & 0xFF, - (fmt->fourcc >> (3*8)) & 0xFF); - xlate++; - } - - return formats; -} - -static void configure_geometry(struct mx3_camera_dev *mx3_cam, - unsigned int width, unsigned int height, - const struct soc_mbus_pixelfmt *fmt) -{ - u32 ctrl, width_field, height_field; - - if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) { - /* - * As the CSI will be configured to output BAYER, here - * the width parameter count the number of samples to - * capture to complete the whole image width. - */ - unsigned int num, den; - int ret = soc_mbus_samples_per_pixel(fmt, &num, &den); - BUG_ON(ret < 0); - width = width * num / den; - } - - /* Setup frame size - this cannot be changed on-the-fly... */ - width_field = width - 1; - height_field = height - 1; - csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE); - - csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1); - csi_reg_write(mx3_cam, (height_field << 16) | 0x22, CSI_FLASH_STROBE_2); - - csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_ACT_FRM_SIZE); - - /* ...and position */ - ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000; - /* Sensor does the cropping */ - csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL); -} - -static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam) -{ - dma_cap_mask_t mask; - struct dma_chan *chan; - struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; - /* We have to use IDMAC_IC_7 for Bayer / generic data */ - struct dma_chan_request rq = {.mx3_cam = mx3_cam, - .id = IDMAC_IC_7}; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - dma_cap_set(DMA_PRIVATE, mask); - chan = dma_request_channel(mask, chan_filter, &rq); - if (!chan) - return -EBUSY; - - *ichan = to_idmac_chan(chan); - (*ichan)->client = mx3_cam; - - return 0; -} - -/* - * FIXME: learn to use stride != width, then we can keep stride properly aligned - * and support arbitrary (even) widths. - */ -static inline void stride_align(__u32 *width) -{ - if (ALIGN(*width, 8) < 4096) - *width = ALIGN(*width, 8); - else - *width = *width & ~7; -} - -/* - * As long as we don't implement host-side cropping and scaling, we can use - * default g_crop and cropcap from soc_camera.c - */ -static int mx3_camera_set_crop(struct soc_camera_device *icd, - const struct v4l2_crop *a) -{ - struct v4l2_crop a_writable = *a; - struct v4l2_rect *rect = &a_writable.c; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_subdev_format fmt = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct v4l2_mbus_framefmt *mf = &fmt.format; - int ret; - - soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); - soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096); - - ret = v4l2_subdev_call(sd, video, s_crop, a); - if (ret < 0) - return ret; - - /* The capture device might have changed its output sizes */ - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); - if (ret < 0) - return ret; - - if (mf->code != icd->current_fmt->code) - return -EINVAL; - - if (mf->width & 7) { - /* Ouch! We can only handle 8-byte aligned width... */ - stride_align(&mf->width); - ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &fmt); - if (ret < 0) - return ret; - } - - if (mf->width != icd->user_width || mf->height != icd->user_height) - configure_geometry(mx3_cam, mf->width, mf->height, - icd->current_fmt->host_fmt); - - dev_dbg(icd->parent, "Sensor cropped %dx%d\n", - mf->width, mf->height); - - icd->user_width = mf->width; - icd->user_height = mf->height; - - return ret; -} - -static int mx3_camera_set_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct v4l2_mbus_framefmt *mf = &format.format; - int ret; - - xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); - if (!xlate) { - dev_warn(icd->parent, "Format %x not found\n", - pix->pixelformat); - return -EINVAL; - } - - stride_align(&pix->width); - dev_dbg(icd->parent, "Set format %dx%d\n", pix->width, pix->height); - - /* - * Might have to perform a complete interface initialisation like in - * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider - * mxc_v4l2_s_fmt() - */ - - configure_geometry(mx3_cam, pix->width, pix->height, xlate->host_fmt); - - mf->width = pix->width; - mf->height = pix->height; - mf->field = pix->field; - mf->colorspace = pix->colorspace; - mf->code = xlate->code; - - ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); - if (ret < 0) - return ret; - - if (mf->code != xlate->code) - return -EINVAL; - - if (!mx3_cam->idmac_channel[0]) { - ret = acquire_dma_channel(mx3_cam); - if (ret < 0) - return ret; - } - - pix->width = mf->width; - pix->height = mf->height; - pix->field = mf->field; - mx3_cam->field = mf->field; - pix->colorspace = mf->colorspace; - icd->current_fmt = xlate; - - dev_dbg(icd->parent, "Sensor set %dx%d\n", pix->width, pix->height); - - return ret; -} - -static int mx3_camera_try_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_subdev_pad_config pad_cfg; - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_TRY, - }; - struct v4l2_mbus_framefmt *mf = &format.format; - __u32 pixfmt = pix->pixelformat; - int ret; - - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (pixfmt && !xlate) { - dev_warn(icd->parent, "Format %x not found\n", pixfmt); - return -EINVAL; - } - - /* limit to MX3 hardware capabilities */ - if (pix->height > 4096) - pix->height = 4096; - if (pix->width > 4096) - pix->width = 4096; - - /* limit to sensor capabilities */ - mf->width = pix->width; - mf->height = pix->height; - mf->field = pix->field; - mf->colorspace = pix->colorspace; - mf->code = xlate->code; - - ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); - if (ret < 0) - return ret; - - pix->width = mf->width; - pix->height = mf->height; - pix->colorspace = mf->colorspace; - - switch (mf->field) { - case V4L2_FIELD_ANY: - pix->field = V4L2_FIELD_NONE; - break; - case V4L2_FIELD_NONE: - break; - default: - dev_err(icd->parent, "Field type %d unsupported.\n", - mf->field); - ret = -EINVAL; - } - - return ret; -} - -static int mx3_camera_reqbufs(struct soc_camera_device *icd, - struct v4l2_requestbuffers *p) -{ - return 0; -} - -static unsigned int mx3_camera_poll(struct file *file, poll_table *pt) -{ - struct soc_camera_device *icd = file->private_data; - - return vb2_poll(&icd->vb2_vidq, file, pt); -} - -static int mx3_camera_querycap(struct soc_camera_host *ici, - struct v4l2_capability *cap) -{ - /* cap->name is set by the firendly caller:-> */ - strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - - return 0; -} - -static int mx3_camera_set_bus_param(struct soc_camera_device *icd) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; - u32 pixfmt = icd->current_fmt->host_fmt->fourcc; - unsigned long bus_flags, common_flags; - u32 dw, sens_conf; - const struct soc_mbus_pixelfmt *fmt; - int buswidth; - int ret; - const struct soc_camera_format_xlate *xlate; - struct device *dev = icd->parent; - - fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code); - if (!fmt) - return -EINVAL; - - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (!xlate) { - dev_warn(dev, "Format %x not found\n", pixfmt); - return -EINVAL; - } - - buswidth = fmt->bits_per_sample; - ret = test_platform_param(mx3_cam, buswidth, &bus_flags); - - dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret); - - if (ret < 0) - return ret; - - ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); - if (!ret) { - common_flags = soc_mbus_config_compatible(&cfg, - bus_flags); - if (!common_flags) { - dev_warn(icd->parent, - "Flags incompatible: camera 0x%x, host 0x%lx\n", - cfg.flags, bus_flags); - return -EINVAL; - } - } else if (ret != -ENOIOCTLCMD) { - return ret; - } else { - common_flags = bus_flags; - } - - dev_dbg(dev, "Flags cam: 0x%x host: 0x%lx common: 0x%lx\n", - cfg.flags, bus_flags, common_flags); - - /* Make choices, based on platform preferences */ - if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && - (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { - if (mx3_cam->platform_flags & MX3_CAMERA_HSP) - common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; - else - common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; - } - - if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && - (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { - if (mx3_cam->platform_flags & MX3_CAMERA_VSP) - common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; - else - common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; - } - - if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) && - (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) { - if (mx3_cam->platform_flags & MX3_CAMERA_DP) - common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH; - else - common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW; - } - - if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && - (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { - if (mx3_cam->platform_flags & MX3_CAMERA_PCP) - common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; - else - common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; - } - - cfg.flags = common_flags; - ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); - if (ret < 0 && ret != -ENOIOCTLCMD) { - dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n", - common_flags, ret); - return ret; - } - - /* - * So far only gated clock mode is supported. Add a line - * (3 << CSI_SENS_CONF_SENS_PRTCL_SHIFT) | - * below and select the required mode when supporting other - * synchronisation protocols. - */ - sens_conf = csi_reg_read(mx3_cam, CSI_SENS_CONF) & - ~((1 << CSI_SENS_CONF_VSYNC_POL_SHIFT) | - (1 << CSI_SENS_CONF_HSYNC_POL_SHIFT) | - (1 << CSI_SENS_CONF_DATA_POL_SHIFT) | - (1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT) | - (3 << CSI_SENS_CONF_DATA_FMT_SHIFT) | - (3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT)); - - /* TODO: Support RGB and YUV formats */ - - /* This has been set in mx3_camera_activate(), but we clear it above */ - sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER; - - if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) - sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; - if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; - if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; - if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW) - sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; - - /* Just do what we're asked to do */ - switch (xlate->host_fmt->bits_per_sample) { - case 4: - dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; - break; - case 8: - dw = 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; - break; - case 10: - dw = 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; - break; - default: - /* - * Actually it can only be 15 now, default is just to silence - * compiler warnings - */ - case 15: - dw = 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; - } - - csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF); - - dev_dbg(dev, "Set SENS_CONF to %x\n", sens_conf | dw); - - return 0; -} - -static struct soc_camera_host_ops mx3_soc_camera_host_ops = { - .owner = THIS_MODULE, - .add = mx3_camera_add_device, - .remove = mx3_camera_remove_device, - .clock_start = mx3_camera_clock_start, - .clock_stop = mx3_camera_clock_stop, - .set_crop = mx3_camera_set_crop, - .set_fmt = mx3_camera_set_fmt, - .try_fmt = mx3_camera_try_fmt, - .get_formats = mx3_camera_get_formats, - .init_videobuf2 = mx3_camera_init_videobuf, - .reqbufs = mx3_camera_reqbufs, - .poll = mx3_camera_poll, - .querycap = mx3_camera_querycap, - .set_bus_param = mx3_camera_set_bus_param, -}; - -static int mx3_camera_probe(struct platform_device *pdev) -{ - struct mx3_camera_pdata *pdata = pdev->dev.platform_data; - struct mx3_camera_dev *mx3_cam; - struct resource *res; - void __iomem *base; - int err = 0; - struct soc_camera_host *soc_host; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - if (!pdata) - return -EINVAL; - - mx3_cam = devm_kzalloc(&pdev->dev, sizeof(*mx3_cam), GFP_KERNEL); - if (!mx3_cam) { - dev_err(&pdev->dev, "Could not allocate mx3 camera object\n"); - return -ENOMEM; - } - - mx3_cam->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(mx3_cam->clk)) - return PTR_ERR(mx3_cam->clk); - - mx3_cam->pdata = pdata; - mx3_cam->platform_flags = pdata->flags; - if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_MASK)) { - /* - * Platform hasn't set available data widths. This is bad. - * Warn and use a default. - */ - dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " - "data widths, using default 8 bit\n"); - mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8; - } - if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4) - mx3_cam->width_flags = 1 << 3; - if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) - mx3_cam->width_flags |= 1 << 7; - if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) - mx3_cam->width_flags |= 1 << 9; - if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) - mx3_cam->width_flags |= 1 << 14; - - mx3_cam->mclk = pdata->mclk_10khz * 10000; - if (!mx3_cam->mclk) { - dev_warn(&pdev->dev, - "mclk_10khz == 0! Please, fix your platform data. " - "Using default 20MHz\n"); - mx3_cam->mclk = 20000000; - } - - /* list of video-buffers */ - INIT_LIST_HEAD(&mx3_cam->capture); - spin_lock_init(&mx3_cam->lock); - - mx3_cam->base = base; - - soc_host = &mx3_cam->soc_host; - soc_host->drv_name = MX3_CAM_DRV_NAME; - soc_host->ops = &mx3_soc_camera_host_ops; - soc_host->priv = mx3_cam; - soc_host->v4l2_dev.dev = &pdev->dev; - soc_host->nr = pdev->id; - - mx3_cam->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); - if (IS_ERR(mx3_cam->alloc_ctx)) - return PTR_ERR(mx3_cam->alloc_ctx); - - if (pdata->asd_sizes) { - soc_host->asd = pdata->asd; - soc_host->asd_sizes = pdata->asd_sizes; - } - - err = soc_camera_host_register(soc_host); - if (err) - goto ecamhostreg; - - /* IDMAC interface */ - dmaengine_get(); - - return 0; - -ecamhostreg: - vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx); - return err; -} - -static int mx3_camera_remove(struct platform_device *pdev) -{ - struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); - struct mx3_camera_dev *mx3_cam = container_of(soc_host, - struct mx3_camera_dev, soc_host); - - soc_camera_host_unregister(soc_host); - - /* - * The channel has either not been allocated, - * or should have been released - */ - if (WARN_ON(mx3_cam->idmac_channel[0])) - dma_release_channel(&mx3_cam->idmac_channel[0]->dma_chan); - - vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx); - - dmaengine_put(); - - return 0; -} - -static struct platform_driver mx3_camera_driver = { - .driver = { - .name = MX3_CAM_DRV_NAME, - }, - .probe = mx3_camera_probe, - .remove = mx3_camera_remove, -}; - -module_platform_driver(mx3_camera_driver); - -MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver"); -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION("0.2.3"); -MODULE_ALIAS("platform:" MX3_CAM_DRV_NAME); diff --git a/drivers/staging/media/omap1/Kconfig b/drivers/staging/media/omap1/Kconfig deleted file mode 100644 index 6cfab3a04..000000000 --- a/drivers/staging/media/omap1/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config VIDEO_OMAP1 - tristate "OMAP1 Camera Interface driver" - depends on VIDEO_DEV && SOC_CAMERA - depends on ARCH_OMAP1 - depends on HAS_DMA - select VIDEOBUF_DMA_CONTIG - select VIDEOBUF_DMA_SG - ---help--- - This is a v4l2 driver for the TI OMAP1 camera interface - - This driver is deprecated and will be removed soon unless someone - will start the work to convert this driver to the vb2 framework - and remove the soc-camera dependency. diff --git a/drivers/staging/media/omap1/Makefile b/drivers/staging/media/omap1/Makefile deleted file mode 100644 index 288562260..000000000 --- a/drivers/staging/media/omap1/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# Makefile for OMAP1 driver - -obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o diff --git a/drivers/staging/media/omap1/TODO b/drivers/staging/media/omap1/TODO deleted file mode 100644 index 1025f9f60..000000000 --- a/drivers/staging/media/omap1/TODO +++ /dev/null @@ -1,8 +0,0 @@ -This driver is deprecated and will be removed soon unless someone will start -the work to convert this driver to the vb2 framework and remove the -soc-camera dependency. - -Note that trivial patches will not be accepted anymore, only a full conversion. - -If you want to convert this driver, please contact the linux-media mailinglist -(see http://linuxtv.org/lists.php). diff --git a/drivers/staging/media/omap1/omap1_camera.c b/drivers/staging/media/omap1/omap1_camera.c deleted file mode 100644 index 54b8dd2d2..000000000 --- a/drivers/staging/media/omap1/omap1_camera.c +++ /dev/null @@ -1,1702 +0,0 @@ -/* - * V4L2 SoC Camera driver for OMAP1 Camera Interface - * - * Copyright (C) 2010, Janusz Krzysztofik - * - * Based on V4L2 Driver for i.MXL/i.MXL camera (CSI) host - * Copyright (C) 2008, Paulius Zaleckas - * Copyright (C) 2009, Darius Augulis - * - * Based on PXA SoC camera driver - * Copyright (C) 2006, Sascha Hauer, Pengutronix - * Copyright (C) 2008, Guennadi Liakhovetski - * - * Hardware specific bits initialy based on former work by Matt Callow - * drivers/media/platform/omap/omap1510cam.c - * Copyright (C) 2006 Matt Callow - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - - -#define DRIVER_NAME "omap1-camera" -#define DRIVER_VERSION "0.0.2" - -#define OMAP_DMA_CAMERA_IF_RX 20 - -/* - * --------------------------------------------------------------------------- - * OMAP1 Camera Interface registers - * --------------------------------------------------------------------------- - */ - -#define REG_CTRLCLOCK 0x00 -#define REG_IT_STATUS 0x04 -#define REG_MODE 0x08 -#define REG_STATUS 0x0C -#define REG_CAMDATA 0x10 -#define REG_GPIO 0x14 -#define REG_PEAK_COUNTER 0x18 - -/* CTRLCLOCK bit shifts */ -#define LCLK_EN BIT(7) -#define DPLL_EN BIT(6) -#define MCLK_EN BIT(5) -#define CAMEXCLK_EN BIT(4) -#define POLCLK BIT(3) -#define FOSCMOD_SHIFT 0 -#define FOSCMOD_MASK (0x7 << FOSCMOD_SHIFT) -#define FOSCMOD_12MHz 0x0 -#define FOSCMOD_6MHz 0x2 -#define FOSCMOD_9_6MHz 0x4 -#define FOSCMOD_24MHz 0x5 -#define FOSCMOD_8MHz 0x6 - -/* IT_STATUS bit shifts */ -#define DATA_TRANSFER BIT(5) -#define FIFO_FULL BIT(4) -#define H_DOWN BIT(3) -#define H_UP BIT(2) -#define V_DOWN BIT(1) -#define V_UP BIT(0) - -/* MODE bit shifts */ -#define RAZ_FIFO BIT(18) -#define EN_FIFO_FULL BIT(17) -#define EN_NIRQ BIT(16) -#define THRESHOLD_SHIFT 9 -#define THRESHOLD_MASK (0x7f << THRESHOLD_SHIFT) -#define DMA BIT(8) -#define EN_H_DOWN BIT(7) -#define EN_H_UP BIT(6) -#define EN_V_DOWN BIT(5) -#define EN_V_UP BIT(4) -#define ORDERCAMD BIT(3) - -#define IRQ_MASK (EN_V_UP | EN_V_DOWN | EN_H_UP | EN_H_DOWN | \ - EN_NIRQ | EN_FIFO_FULL) - -/* STATUS bit shifts */ -#define HSTATUS BIT(1) -#define VSTATUS BIT(0) - -/* GPIO bit shifts */ -#define CAM_RST BIT(0) - -/* end of OMAP1 Camera Interface registers */ - - -#define SOCAM_BUS_FLAGS (V4L2_MBUS_MASTER | \ - V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ - V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ - V4L2_MBUS_DATA_ACTIVE_HIGH) - - -#define FIFO_SIZE ((THRESHOLD_MASK >> THRESHOLD_SHIFT) + 1) -#define FIFO_SHIFT __fls(FIFO_SIZE) - -#define DMA_BURST_SHIFT (1 + OMAP_DMA_DATA_BURST_4) -#define DMA_BURST_SIZE (1 << DMA_BURST_SHIFT) - -#define DMA_ELEMENT_SHIFT OMAP_DMA_DATA_TYPE_S32 -#define DMA_ELEMENT_SIZE (1 << DMA_ELEMENT_SHIFT) - -#define DMA_FRAME_SHIFT_CONTIG (FIFO_SHIFT - 1) -#define DMA_FRAME_SHIFT_SG DMA_BURST_SHIFT - -#define DMA_FRAME_SHIFT(x) ((x) == OMAP1_CAM_DMA_CONTIG ? \ - DMA_FRAME_SHIFT_CONTIG : \ - DMA_FRAME_SHIFT_SG) -#define DMA_FRAME_SIZE(x) (1 << DMA_FRAME_SHIFT(x)) -#define DMA_SYNC OMAP_DMA_SYNC_FRAME -#define THRESHOLD_LEVEL DMA_FRAME_SIZE - - -#define MAX_VIDEO_MEM 4 /* arbitrary video memory limit in MB */ - - -/* - * Structures - */ - -/* buffer for one video frame */ -struct omap1_cam_buf { - struct videobuf_buffer vb; - u32 code; - int inwork; - struct scatterlist *sgbuf; - int sgcount; - int bytes_left; - enum videobuf_state result; -}; - -struct omap1_cam_dev { - struct soc_camera_host soc_host; - struct clk *clk; - - unsigned int irq; - void __iomem *base; - - int dma_ch; - - struct omap1_cam_platform_data *pdata; - struct resource *res; - unsigned long pflags; - unsigned long camexclk; - - struct list_head capture; - - /* lock used to protect videobuf */ - spinlock_t lock; - - /* Pointers to DMA buffers */ - struct omap1_cam_buf *active; - struct omap1_cam_buf *ready; - - enum omap1_cam_vb_mode vb_mode; - int (*mmap_mapper)(struct videobuf_queue *q, - struct videobuf_buffer *buf, - struct vm_area_struct *vma); - - u32 reg_cache[0]; -}; - - -static void cam_write(struct omap1_cam_dev *pcdev, u16 reg, u32 val) -{ - pcdev->reg_cache[reg / sizeof(u32)] = val; - __raw_writel(val, pcdev->base + reg); -} - -static u32 cam_read(struct omap1_cam_dev *pcdev, u16 reg, bool from_cache) -{ - return !from_cache ? __raw_readl(pcdev->base + reg) : - pcdev->reg_cache[reg / sizeof(u32)]; -} - -#define CAM_READ(pcdev, reg) \ - cam_read(pcdev, REG_##reg, false) -#define CAM_WRITE(pcdev, reg, val) \ - cam_write(pcdev, REG_##reg, val) -#define CAM_READ_CACHE(pcdev, reg) \ - cam_read(pcdev, REG_##reg, true) - -/* - * Videobuf operations - */ -static int omap1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct soc_camera_device *icd = vq->priv_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct omap1_cam_dev *pcdev = ici->priv; - - *size = icd->sizeimage; - - if (!*count || *count < OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode)) - *count = OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode); - - if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) - *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size; - - dev_dbg(icd->parent, - "%s: count=%d, size=%d\n", __func__, *count, *size); - - return 0; -} - -static void free_buffer(struct videobuf_queue *vq, struct omap1_cam_buf *buf, - enum omap1_cam_vb_mode vb_mode) -{ - struct videobuf_buffer *vb = &buf->vb; - - BUG_ON(in_interrupt()); - - videobuf_waiton(vq, vb, 0, 0); - - if (vb_mode == OMAP1_CAM_DMA_CONTIG) { - videobuf_dma_contig_free(vq, vb); - } else { - struct soc_camera_device *icd = vq->priv_data; - struct device *dev = icd->parent; - struct videobuf_dmabuf *dma = videobuf_to_dma(vb); - - videobuf_dma_unmap(dev, dma); - videobuf_dma_free(dma); - } - - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static int omap1_videobuf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, enum v4l2_field field) -{ - struct soc_camera_device *icd = vq->priv_data; - struct omap1_cam_buf *buf = container_of(vb, struct omap1_cam_buf, vb); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct omap1_cam_dev *pcdev = ici->priv; - int ret; - - WARN_ON(!list_empty(&vb->queue)); - - BUG_ON(NULL == icd->current_fmt); - - buf->inwork = 1; - - if (buf->code != icd->current_fmt->code || vb->field != field || - vb->width != icd->user_width || - vb->height != icd->user_height) { - buf->code = icd->current_fmt->code; - vb->width = icd->user_width; - vb->height = icd->user_height; - vb->field = field; - vb->state = VIDEOBUF_NEEDS_INIT; - } - - vb->size = icd->sizeimage; - - if (vb->baddr && vb->bsize < vb->size) { - ret = -EINVAL; - goto out; - } - - if (vb->state == VIDEOBUF_NEEDS_INIT) { - ret = videobuf_iolock(vq, vb, NULL); - if (ret) - goto fail; - - vb->state = VIDEOBUF_PREPARED; - } - buf->inwork = 0; - - return 0; -fail: - free_buffer(vq, buf, pcdev->vb_mode); -out: - buf->inwork = 0; - return ret; -} - -static void set_dma_dest_params(int dma_ch, struct omap1_cam_buf *buf, - enum omap1_cam_vb_mode vb_mode) -{ - dma_addr_t dma_addr; - unsigned int block_size; - - if (vb_mode == OMAP1_CAM_DMA_CONTIG) { - dma_addr = videobuf_to_dma_contig(&buf->vb); - block_size = buf->vb.size; - } else { - if (WARN_ON(!buf->sgbuf)) { - buf->result = VIDEOBUF_ERROR; - return; - } - dma_addr = sg_dma_address(buf->sgbuf); - if (WARN_ON(!dma_addr)) { - buf->sgbuf = NULL; - buf->result = VIDEOBUF_ERROR; - return; - } - block_size = sg_dma_len(buf->sgbuf); - if (WARN_ON(!block_size)) { - buf->sgbuf = NULL; - buf->result = VIDEOBUF_ERROR; - return; - } - if (unlikely(buf->bytes_left < block_size)) - block_size = buf->bytes_left; - if (WARN_ON(dma_addr & (DMA_FRAME_SIZE(vb_mode) * - DMA_ELEMENT_SIZE - 1))) { - dma_addr = ALIGN(dma_addr, DMA_FRAME_SIZE(vb_mode) * - DMA_ELEMENT_SIZE); - block_size &= ~(DMA_FRAME_SIZE(vb_mode) * - DMA_ELEMENT_SIZE - 1); - } - buf->bytes_left -= block_size; - buf->sgcount++; - } - - omap_set_dma_dest_params(dma_ch, - OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, dma_addr, 0, 0); - omap_set_dma_transfer_params(dma_ch, - OMAP_DMA_DATA_TYPE_S32, DMA_FRAME_SIZE(vb_mode), - block_size >> (DMA_FRAME_SHIFT(vb_mode) + DMA_ELEMENT_SHIFT), - DMA_SYNC, 0, 0); -} - -static struct omap1_cam_buf *prepare_next_vb(struct omap1_cam_dev *pcdev) -{ - struct omap1_cam_buf *buf; - - /* - * If there is already a buffer pointed out by the pcdev->ready, - * (re)use it, otherwise try to fetch and configure a new one. - */ - buf = pcdev->ready; - if (!buf) { - if (list_empty(&pcdev->capture)) - return buf; - buf = list_entry(pcdev->capture.next, - struct omap1_cam_buf, vb.queue); - buf->vb.state = VIDEOBUF_ACTIVE; - pcdev->ready = buf; - list_del_init(&buf->vb.queue); - } - - if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { - /* - * In CONTIG mode, we can safely enter next buffer parameters - * into the DMA programming register set after the DMA - * has already been activated on the previous buffer - */ - set_dma_dest_params(pcdev->dma_ch, buf, pcdev->vb_mode); - } else { - /* - * In SG mode, the above is not safe since there are probably - * a bunch of sgbufs from previous sglist still pending. - * Instead, mark the sglist fresh for the upcoming - * try_next_sgbuf(). - */ - buf->sgbuf = NULL; - } - - return buf; -} - -static struct scatterlist *try_next_sgbuf(int dma_ch, struct omap1_cam_buf *buf) -{ - struct scatterlist *sgbuf; - - if (likely(buf->sgbuf)) { - /* current sglist is active */ - if (unlikely(!buf->bytes_left)) { - /* indicate sglist complete */ - sgbuf = NULL; - } else { - /* process next sgbuf */ - sgbuf = sg_next(buf->sgbuf); - if (WARN_ON(!sgbuf)) { - buf->result = VIDEOBUF_ERROR; - } else if (WARN_ON(!sg_dma_len(sgbuf))) { - sgbuf = NULL; - buf->result = VIDEOBUF_ERROR; - } - } - buf->sgbuf = sgbuf; - } else { - /* sglist is fresh, initialize it before using */ - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - - sgbuf = dma->sglist; - if (!(WARN_ON(!sgbuf))) { - buf->sgbuf = sgbuf; - buf->sgcount = 0; - buf->bytes_left = buf->vb.size; - buf->result = VIDEOBUF_DONE; - } - } - if (sgbuf) - /* - * Put our next sgbuf parameters (address, size) - * into the DMA programming register set. - */ - set_dma_dest_params(dma_ch, buf, OMAP1_CAM_DMA_SG); - - return sgbuf; -} - -static void start_capture(struct omap1_cam_dev *pcdev) -{ - struct omap1_cam_buf *buf = pcdev->active; - u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); - u32 mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN; - - if (WARN_ON(!buf)) - return; - - /* - * Enable start of frame interrupt, which we will use for activating - * our end of frame watchdog when capture actually starts. - */ - mode |= EN_V_UP; - - if (unlikely(ctrlclock & LCLK_EN)) - /* stop pixel clock before FIFO reset */ - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); - /* reset FIFO */ - CAM_WRITE(pcdev, MODE, mode | RAZ_FIFO); - - omap_start_dma(pcdev->dma_ch); - - if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) { - /* - * In SG mode, it's a good moment for fetching next sgbuf - * from the current sglist and, if available, already putting - * its parameters into the DMA programming register set. - */ - try_next_sgbuf(pcdev->dma_ch, buf); - } - - /* (re)enable pixel clock */ - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | LCLK_EN); - /* release FIFO reset */ - CAM_WRITE(pcdev, MODE, mode); -} - -static void suspend_capture(struct omap1_cam_dev *pcdev) -{ - u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); - - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); - omap_stop_dma(pcdev->dma_ch); -} - -static void disable_capture(struct omap1_cam_dev *pcdev) -{ - u32 mode = CAM_READ_CACHE(pcdev, MODE); - - CAM_WRITE(pcdev, MODE, mode & ~(IRQ_MASK | DMA)); -} - -static void omap1_videobuf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct soc_camera_device *icd = vq->priv_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct omap1_cam_dev *pcdev = ici->priv; - struct omap1_cam_buf *buf; - u32 mode; - - list_add_tail(&vb->queue, &pcdev->capture); - vb->state = VIDEOBUF_QUEUED; - - if (pcdev->active) { - /* - * Capture in progress, so don't touch pcdev->ready even if - * empty. Since the transfer of the DMA programming register set - * content to the DMA working register set is done automatically - * by the DMA hardware, this can pretty well happen while we - * are keeping the lock here. Leave fetching it from the queue - * to be done when a next DMA interrupt occures instead. - */ - return; - } - - WARN_ON(pcdev->ready); - - buf = prepare_next_vb(pcdev); - if (WARN_ON(!buf)) - return; - - pcdev->active = buf; - pcdev->ready = NULL; - - dev_dbg(icd->parent, - "%s: capture not active, setup FIFO, start DMA\n", __func__); - mode = CAM_READ_CACHE(pcdev, MODE) & ~THRESHOLD_MASK; - mode |= THRESHOLD_LEVEL(pcdev->vb_mode) << THRESHOLD_SHIFT; - CAM_WRITE(pcdev, MODE, mode | EN_FIFO_FULL | DMA); - - if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) { - /* - * In SG mode, the above prepare_next_vb() didn't actually - * put anything into the DMA programming register set, - * so we have to do it now, before activating DMA. - */ - try_next_sgbuf(pcdev->dma_ch, buf); - } - - start_capture(pcdev); -} - -static void omap1_videobuf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct omap1_cam_buf *buf = - container_of(vb, struct omap1_cam_buf, vb); - struct soc_camera_device *icd = vq->priv_data; - struct device *dev = icd->parent; - struct soc_camera_host *ici = to_soc_camera_host(dev); - struct omap1_cam_dev *pcdev = ici->priv; - - switch (vb->state) { - case VIDEOBUF_DONE: - dev_dbg(dev, "%s (done)\n", __func__); - break; - case VIDEOBUF_ACTIVE: - dev_dbg(dev, "%s (active)\n", __func__); - break; - case VIDEOBUF_QUEUED: - dev_dbg(dev, "%s (queued)\n", __func__); - break; - case VIDEOBUF_PREPARED: - dev_dbg(dev, "%s (prepared)\n", __func__); - break; - default: - dev_dbg(dev, "%s (unknown %d)\n", __func__, vb->state); - break; - } - - free_buffer(vq, buf, pcdev->vb_mode); -} - -static void videobuf_done(struct omap1_cam_dev *pcdev, - enum videobuf_state result) -{ - struct omap1_cam_buf *buf = pcdev->active; - struct videobuf_buffer *vb; - struct device *dev = pcdev->soc_host.icd->parent; - - if (WARN_ON(!buf)) { - suspend_capture(pcdev); - disable_capture(pcdev); - return; - } - - if (result == VIDEOBUF_ERROR) - suspend_capture(pcdev); - - vb = &buf->vb; - if (waitqueue_active(&vb->done)) { - if (!pcdev->ready && result != VIDEOBUF_ERROR) { - /* - * No next buffer has been entered into the DMA - * programming register set on time (could be done only - * while the previous DMA interurpt was processed, not - * later), so the last DMA block, be it a whole buffer - * if in CONTIG or its last sgbuf if in SG mode, is - * about to be reused by the just autoreinitialized DMA - * engine, and overwritten with next frame data. Best we - * can do is stopping the capture as soon as possible, - * hopefully before the next frame start. - */ - suspend_capture(pcdev); - } - vb->state = result; - v4l2_get_timestamp(&vb->ts); - if (result != VIDEOBUF_ERROR) - vb->field_count++; - wake_up(&vb->done); - - /* shift in next buffer */ - buf = pcdev->ready; - pcdev->active = buf; - pcdev->ready = NULL; - - if (!buf) { - /* - * No next buffer was ready on time (see above), so - * indicate error condition to force capture restart or - * stop, depending on next buffer already queued or not. - */ - result = VIDEOBUF_ERROR; - prepare_next_vb(pcdev); - - buf = pcdev->ready; - pcdev->active = buf; - pcdev->ready = NULL; - } - } else if (pcdev->ready) { - /* - * In both CONTIG and SG mode, the DMA engine has possibly - * been already autoreinitialized with the preprogrammed - * pcdev->ready buffer. We can either accept this fact - * and just swap the buffers, or provoke an error condition - * and restart capture. The former seems less intrusive. - */ - dev_dbg(dev, "%s: nobody waiting on videobuf, swap with next\n", - __func__); - pcdev->active = pcdev->ready; - - if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) { - /* - * In SG mode, we have to make sure that the buffer we - * are putting back into the pcdev->ready is marked - * fresh. - */ - buf->sgbuf = NULL; - } - pcdev->ready = buf; - - buf = pcdev->active; - } else { - /* - * No next buffer has been entered into - * the DMA programming register set on time. - */ - if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { - /* - * In CONTIG mode, the DMA engine has already been - * reinitialized with the current buffer. Best we can do - * is not touching it. - */ - dev_dbg(dev, - "%s: nobody waiting on videobuf, reuse it\n", - __func__); - } else { - /* - * In SG mode, the DMA engine has just been - * autoreinitialized with the last sgbuf from the - * current list. Restart capture in order to transfer - * next frame start into the first sgbuf, not the last - * one. - */ - if (result != VIDEOBUF_ERROR) { - suspend_capture(pcdev); - result = VIDEOBUF_ERROR; - } - } - } - - if (!buf) { - dev_dbg(dev, "%s: no more videobufs, stop capture\n", __func__); - disable_capture(pcdev); - return; - } - - if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { - /* - * In CONTIG mode, the current buffer parameters had already - * been entered into the DMA programming register set while the - * buffer was fetched with prepare_next_vb(), they may have also - * been transferred into the runtime set and already active if - * the DMA still running. - */ - } else { - /* In SG mode, extra steps are required */ - if (result == VIDEOBUF_ERROR) - /* make sure we (re)use sglist from start on error */ - buf->sgbuf = NULL; - - /* - * In any case, enter the next sgbuf parameters into the DMA - * programming register set. They will be used either during - * nearest DMA autoreinitialization or, in case of an error, - * on DMA startup below. - */ - try_next_sgbuf(pcdev->dma_ch, buf); - } - - if (result == VIDEOBUF_ERROR) { - dev_dbg(dev, "%s: videobuf error; reset FIFO, restart DMA\n", - __func__); - start_capture(pcdev); - /* - * In SG mode, the above also resulted in the next sgbuf - * parameters being entered into the DMA programming register - * set, making them ready for next DMA autoreinitialization. - */ - } - - /* - * Finally, try fetching next buffer. - * In CONTIG mode, it will also enter it into the DMA programming - * register set, making it ready for next DMA autoreinitialization. - */ - prepare_next_vb(pcdev); -} - -static void dma_isr(int channel, unsigned short status, void *data) -{ - struct omap1_cam_dev *pcdev = data; - struct omap1_cam_buf *buf = pcdev->active; - unsigned long flags; - - spin_lock_irqsave(&pcdev->lock, flags); - - if (WARN_ON(!buf)) { - suspend_capture(pcdev); - disable_capture(pcdev); - goto out; - } - - if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { - /* - * In CONTIG mode, assume we have just managed to collect the - * whole frame, hopefully before our end of frame watchdog is - * triggered. Then, all we have to do is disabling the watchdog - * for this frame, and calling videobuf_done() with success - * indicated. - */ - CAM_WRITE(pcdev, MODE, - CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN); - videobuf_done(pcdev, VIDEOBUF_DONE); - } else { - /* - * In SG mode, we have to process every sgbuf from the current - * sglist, one after another. - */ - if (buf->sgbuf) { - /* - * Current sglist not completed yet, try fetching next - * sgbuf, hopefully putting it into the DMA programming - * register set, making it ready for next DMA - * autoreinitialization. - */ - try_next_sgbuf(pcdev->dma_ch, buf); - if (buf->sgbuf) - goto out; - - /* - * No more sgbufs left in the current sglist. This - * doesn't mean that the whole videobuffer is already - * complete, but only that the last sgbuf from the - * current sglist is about to be filled. It will be - * ready on next DMA interrupt, signalled with the - * buf->sgbuf set back to NULL. - */ - if (buf->result != VIDEOBUF_ERROR) { - /* - * Video frame collected without errors so far, - * we can prepare for collecting a next one - * as soon as DMA gets autoreinitialized - * after the current (last) sgbuf is completed. - */ - buf = prepare_next_vb(pcdev); - if (!buf) - goto out; - - try_next_sgbuf(pcdev->dma_ch, buf); - goto out; - } - } - /* end of videobuf */ - videobuf_done(pcdev, buf->result); - } - -out: - spin_unlock_irqrestore(&pcdev->lock, flags); -} - -static irqreturn_t cam_isr(int irq, void *data) -{ - struct omap1_cam_dev *pcdev = data; - struct device *dev = pcdev->soc_host.icd->parent; - struct omap1_cam_buf *buf = pcdev->active; - u32 it_status; - unsigned long flags; - - it_status = CAM_READ(pcdev, IT_STATUS); - if (!it_status) - return IRQ_NONE; - - spin_lock_irqsave(&pcdev->lock, flags); - - if (WARN_ON(!buf)) { - dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n", - __func__, it_status); - suspend_capture(pcdev); - disable_capture(pcdev); - goto out; - } - - if (unlikely(it_status & FIFO_FULL)) { - dev_warn(dev, "%s: FIFO overflow\n", __func__); - - } else if (it_status & V_DOWN) { - /* end of video frame watchdog */ - if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { - /* - * In CONTIG mode, the watchdog is disabled with - * successful DMA end of block interrupt, and reenabled - * on next frame start. If we get here, there is nothing - * to check, we must be out of sync. - */ - } else { - if (buf->sgcount == 2) { - /* - * If exactly 2 sgbufs from the next sglist have - * been programmed into the DMA engine (the - * first one already transferred into the DMA - * runtime register set, the second one still - * in the programming set), then we are in sync. - */ - goto out; - } - } - dev_notice(dev, "%s: unexpected end of video frame\n", - __func__); - - } else if (it_status & V_UP) { - u32 mode; - - if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { - /* - * In CONTIG mode, we need this interrupt every frame - * in oredr to reenable our end of frame watchdog. - */ - mode = CAM_READ_CACHE(pcdev, MODE); - } else { - /* - * In SG mode, the below enabled end of frame watchdog - * is kept on permanently, so we can turn this one shot - * setup off. - */ - mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_UP; - } - - if (!(mode & EN_V_DOWN)) { - /* (re)enable end of frame watchdog interrupt */ - mode |= EN_V_DOWN; - } - CAM_WRITE(pcdev, MODE, mode); - goto out; - - } else { - dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n", - __func__, it_status); - goto out; - } - - videobuf_done(pcdev, VIDEOBUF_ERROR); -out: - spin_unlock_irqrestore(&pcdev->lock, flags); - return IRQ_HANDLED; -} - -static struct videobuf_queue_ops omap1_videobuf_ops = { - .buf_setup = omap1_videobuf_setup, - .buf_prepare = omap1_videobuf_prepare, - .buf_queue = omap1_videobuf_queue, - .buf_release = omap1_videobuf_release, -}; - - -/* - * SOC Camera host operations - */ - -static void sensor_reset(struct omap1_cam_dev *pcdev, bool reset) -{ - /* apply/release camera sensor reset if requested by platform data */ - if (pcdev->pflags & OMAP1_CAMERA_RST_HIGH) - CAM_WRITE(pcdev, GPIO, reset); - else if (pcdev->pflags & OMAP1_CAMERA_RST_LOW) - CAM_WRITE(pcdev, GPIO, !reset); -} - -static int omap1_cam_add_device(struct soc_camera_device *icd) -{ - dev_dbg(icd->parent, "OMAP1 Camera driver attached to camera %d\n", - icd->devnum); - - return 0; -} - -static void omap1_cam_remove_device(struct soc_camera_device *icd) -{ - dev_dbg(icd->parent, - "OMAP1 Camera driver detached from camera %d\n", icd->devnum); -} - -/* - * The following two functions absolutely depend on the fact, that - * there can be only one camera on OMAP1 camera sensor interface - */ -static int omap1_cam_clock_start(struct soc_camera_host *ici) -{ - struct omap1_cam_dev *pcdev = ici->priv; - u32 ctrlclock; - - clk_enable(pcdev->clk); - - /* setup sensor clock */ - ctrlclock = CAM_READ(pcdev, CTRLCLOCK); - ctrlclock &= ~(CAMEXCLK_EN | MCLK_EN | DPLL_EN); - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); - - ctrlclock &= ~FOSCMOD_MASK; - switch (pcdev->camexclk) { - case 6000000: - ctrlclock |= CAMEXCLK_EN | FOSCMOD_6MHz; - break; - case 8000000: - ctrlclock |= CAMEXCLK_EN | FOSCMOD_8MHz | DPLL_EN; - break; - case 9600000: - ctrlclock |= CAMEXCLK_EN | FOSCMOD_9_6MHz | DPLL_EN; - break; - case 12000000: - ctrlclock |= CAMEXCLK_EN | FOSCMOD_12MHz; - break; - case 24000000: - ctrlclock |= CAMEXCLK_EN | FOSCMOD_24MHz | DPLL_EN; - default: - break; - } - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~DPLL_EN); - - /* enable internal clock */ - ctrlclock |= MCLK_EN; - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); - - sensor_reset(pcdev, false); - - return 0; -} - -static void omap1_cam_clock_stop(struct soc_camera_host *ici) -{ - struct omap1_cam_dev *pcdev = ici->priv; - u32 ctrlclock; - - suspend_capture(pcdev); - disable_capture(pcdev); - - sensor_reset(pcdev, true); - - /* disable and release system clocks */ - ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); - ctrlclock &= ~(MCLK_EN | DPLL_EN | CAMEXCLK_EN); - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); - - ctrlclock = (ctrlclock & ~FOSCMOD_MASK) | FOSCMOD_12MHz; - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | MCLK_EN); - - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~MCLK_EN); - - clk_disable(pcdev->clk); -} - -/* Duplicate standard formats based on host capability of byte swapping */ -static const struct soc_mbus_lookup omap1_cam_formats[] = { -{ - .code = MEDIA_BUS_FMT_UYVY8_2X8, - .fmt = { - .fourcc = V4L2_PIX_FMT_YUYV, - .name = "YUYV", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_VYUY8_2X8, - .fmt = { - .fourcc = V4L2_PIX_FMT_YVYU, - .name = "YVYU", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_YUYV8_2X8, - .fmt = { - .fourcc = V4L2_PIX_FMT_UYVY, - .name = "UYVY", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_YVYU8_2X8, - .fmt = { - .fourcc = V4L2_PIX_FMT_VYUY, - .name = "VYUY", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, - .fmt = { - .fourcc = V4L2_PIX_FMT_RGB555, - .name = "RGB555", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, - .fmt = { - .fourcc = V4L2_PIX_FMT_RGB555X, - .name = "RGB555X", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_RGB565_2X8_BE, - .fmt = { - .fourcc = V4L2_PIX_FMT_RGB565, - .name = "RGB565", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_RGB565_2X8_LE, - .fmt = { - .fourcc = V4L2_PIX_FMT_RGB565X, - .name = "RGB565X", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, -}; - -static int omap1_cam_get_formats(struct soc_camera_device *icd, - unsigned int idx, struct soc_camera_format_xlate *xlate) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct device *dev = icd->parent; - int formats = 0, ret; - struct v4l2_subdev_mbus_code_enum code = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .index = idx, - }; - const struct soc_mbus_pixelfmt *fmt; - - ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); - if (ret < 0) - /* No more formats */ - return 0; - - fmt = soc_mbus_get_fmtdesc(code.code); - if (!fmt) { - dev_warn(dev, "%s: unsupported format code #%d: %d\n", __func__, - idx, code.code); - return 0; - } - - /* Check support for the requested bits-per-sample */ - if (fmt->bits_per_sample != 8) - return 0; - - switch (code.code) { - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_YVYU8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_VYUY8_2X8: - case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE: - case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: - case MEDIA_BUS_FMT_RGB565_2X8_BE: - case MEDIA_BUS_FMT_RGB565_2X8_LE: - formats++; - if (xlate) { - xlate->host_fmt = soc_mbus_find_fmtdesc(code.code, - omap1_cam_formats, - ARRAY_SIZE(omap1_cam_formats)); - xlate->code = code.code; - xlate++; - dev_dbg(dev, - "%s: providing format %s as byte swapped code #%d\n", - __func__, xlate->host_fmt->name, code.code); - } - default: - if (xlate) - dev_dbg(dev, - "%s: providing format %s in pass-through mode\n", - __func__, fmt->name); - } - formats++; - if (xlate) { - xlate->host_fmt = fmt; - xlate->code = code.code; - xlate++; - } - - return formats; -} - -static bool is_dma_aligned(s32 bytes_per_line, unsigned int height, - enum omap1_cam_vb_mode vb_mode) -{ - int size = bytes_per_line * height; - - return IS_ALIGNED(bytes_per_line, DMA_ELEMENT_SIZE) && - IS_ALIGNED(size, DMA_FRAME_SIZE(vb_mode) * DMA_ELEMENT_SIZE); -} - -static int dma_align(int *width, int *height, - const struct soc_mbus_pixelfmt *fmt, - enum omap1_cam_vb_mode vb_mode, bool enlarge) -{ - s32 bytes_per_line = soc_mbus_bytes_per_line(*width, fmt); - - if (bytes_per_line < 0) - return bytes_per_line; - - if (!is_dma_aligned(bytes_per_line, *height, vb_mode)) { - unsigned int pxalign = __fls(bytes_per_line / *width); - unsigned int salign = DMA_FRAME_SHIFT(vb_mode) + - DMA_ELEMENT_SHIFT - pxalign; - unsigned int incr = enlarge << salign; - - v4l_bound_align_image(width, 1, *width + incr, 0, - height, 1, *height + incr, 0, salign); - return 0; - } - return 1; -} - -#define subdev_call_with_sense(pcdev, dev, icd, sd, op, function, args...) \ -({ \ - struct soc_camera_sense sense = { \ - .master_clock = pcdev->camexclk, \ - .pixel_clock_max = 0, \ - }; \ - int __ret; \ - \ - if (pcdev->pdata) \ - sense.pixel_clock_max = pcdev->pdata->lclk_khz_max * 1000; \ - icd->sense = &sense; \ - __ret = v4l2_subdev_call(sd, op, function, ##args); \ - icd->sense = NULL; \ - \ - if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { \ - if (sense.pixel_clock > sense.pixel_clock_max) { \ - dev_err(dev, \ - "%s: pixel clock %lu set by the camera too high!\n", \ - __func__, sense.pixel_clock); \ - __ret = -EINVAL; \ - } \ - } \ - __ret; \ -}) - -static int set_format(struct omap1_cam_dev *pcdev, struct device *dev, - struct soc_camera_device *icd, struct v4l2_subdev *sd, - struct v4l2_subdev_format *format, - const struct soc_camera_format_xlate *xlate) -{ - s32 bytes_per_line; - struct v4l2_mbus_framefmt *mf = &format->format; - int ret = subdev_call_with_sense(pcdev, dev, icd, sd, pad, set_fmt, NULL, format); - - if (ret < 0) { - dev_err(dev, "%s: set_fmt failed\n", __func__); - return ret; - } - - if (mf->code != xlate->code) { - dev_err(dev, "%s: unexpected pixel code change\n", __func__); - return -EINVAL; - } - - bytes_per_line = soc_mbus_bytes_per_line(mf->width, xlate->host_fmt); - if (bytes_per_line < 0) { - dev_err(dev, "%s: soc_mbus_bytes_per_line() failed\n", - __func__); - return bytes_per_line; - } - - if (!is_dma_aligned(bytes_per_line, mf->height, pcdev->vb_mode)) { - dev_err(dev, "%s: resulting geometry %ux%u not DMA aligned\n", - __func__, mf->width, mf->height); - return -EINVAL; - } - return 0; -} - -static int omap1_cam_set_crop(struct soc_camera_device *icd, - const struct v4l2_crop *crop) -{ - const struct v4l2_rect *rect = &crop->c; - const struct soc_camera_format_xlate *xlate = icd->current_fmt; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct device *dev = icd->parent; - struct soc_camera_host *ici = to_soc_camera_host(dev); - struct omap1_cam_dev *pcdev = ici->priv; - struct v4l2_subdev_format fmt = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct v4l2_mbus_framefmt *mf = &fmt.format; - int ret; - - ret = subdev_call_with_sense(pcdev, dev, icd, sd, video, s_crop, crop); - if (ret < 0) { - dev_warn(dev, "%s: failed to crop to %ux%u@%u:%u\n", __func__, - rect->width, rect->height, rect->left, rect->top); - return ret; - } - - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); - if (ret < 0) { - dev_warn(dev, "%s: failed to fetch current format\n", __func__); - return ret; - } - - ret = dma_align(&mf->width, &mf->height, xlate->host_fmt, pcdev->vb_mode, - false); - if (ret < 0) { - dev_err(dev, "%s: failed to align %ux%u %s with DMA\n", - __func__, mf->width, mf->height, - xlate->host_fmt->name); - return ret; - } - - if (!ret) { - /* sensor returned geometry not DMA aligned, trying to fix */ - ret = set_format(pcdev, dev, icd, sd, &fmt, xlate); - if (ret < 0) { - dev_err(dev, "%s: failed to set format\n", __func__); - return ret; - } - } - - icd->user_width = mf->width; - icd->user_height = mf->height; - - return 0; -} - -static int omap1_cam_set_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct device *dev = icd->parent; - struct soc_camera_host *ici = to_soc_camera_host(dev); - struct omap1_cam_dev *pcdev = ici->priv; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct v4l2_mbus_framefmt *mf = &format.format; - int ret; - - xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); - if (!xlate) { - dev_warn(dev, "%s: format %#x not found\n", __func__, - pix->pixelformat); - return -EINVAL; - } - - mf->width = pix->width; - mf->height = pix->height; - mf->field = pix->field; - mf->colorspace = pix->colorspace; - mf->code = xlate->code; - - ret = dma_align(&mf->width, &mf->height, xlate->host_fmt, pcdev->vb_mode, - true); - if (ret < 0) { - dev_err(dev, "%s: failed to align %ux%u %s with DMA\n", - __func__, pix->width, pix->height, - xlate->host_fmt->name); - return ret; - } - - ret = set_format(pcdev, dev, icd, sd, &format, xlate); - if (ret < 0) { - dev_err(dev, "%s: failed to set format\n", __func__); - return ret; - } - - pix->width = mf->width; - pix->height = mf->height; - pix->field = mf->field; - pix->colorspace = mf->colorspace; - icd->current_fmt = xlate; - - return 0; -} - -static int omap1_cam_try_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_subdev_pad_config pad_cfg; - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_TRY, - }; - struct v4l2_mbus_framefmt *mf = &format.format; - int ret; - /* TODO: limit to mx1 hardware capabilities */ - - xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); - if (!xlate) { - dev_warn(icd->parent, "Format %#x not found\n", - pix->pixelformat); - return -EINVAL; - } - - mf->width = pix->width; - mf->height = pix->height; - mf->field = pix->field; - mf->colorspace = pix->colorspace; - mf->code = xlate->code; - - /* limit to sensor capabilities */ - ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); - if (ret < 0) - return ret; - - pix->width = mf->width; - pix->height = mf->height; - pix->field = mf->field; - pix->colorspace = mf->colorspace; - - return 0; -} - -static bool sg_mode; - -/* - * Local mmap_mapper wrapper, - * used for detecting videobuf-dma-contig buffer allocation failures - * and switching to videobuf-dma-sg automatically for future attempts. - */ -static int omap1_cam_mmap_mapper(struct videobuf_queue *q, - struct videobuf_buffer *buf, - struct vm_area_struct *vma) -{ - struct soc_camera_device *icd = q->priv_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct omap1_cam_dev *pcdev = ici->priv; - int ret; - - ret = pcdev->mmap_mapper(q, buf, vma); - - if (ret == -ENOMEM) - sg_mode = true; - - return ret; -} - -static void omap1_cam_init_videobuf(struct videobuf_queue *q, - struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct omap1_cam_dev *pcdev = ici->priv; - - if (!sg_mode) - videobuf_queue_dma_contig_init(q, &omap1_videobuf_ops, - icd->parent, &pcdev->lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, - sizeof(struct omap1_cam_buf), icd, &ici->host_lock); - else - videobuf_queue_sg_init(q, &omap1_videobuf_ops, - icd->parent, &pcdev->lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, - sizeof(struct omap1_cam_buf), icd, &ici->host_lock); - - /* use videobuf mode (auto)selected with the module parameter */ - pcdev->vb_mode = sg_mode ? OMAP1_CAM_DMA_SG : OMAP1_CAM_DMA_CONTIG; - - /* - * Ensure we substitute the videobuf-dma-contig version of the - * mmap_mapper() callback with our own wrapper, used for switching - * automatically to videobuf-dma-sg on buffer allocation failure. - */ - if (!sg_mode && q->int_ops->mmap_mapper != omap1_cam_mmap_mapper) { - pcdev->mmap_mapper = q->int_ops->mmap_mapper; - q->int_ops->mmap_mapper = omap1_cam_mmap_mapper; - } -} - -static int omap1_cam_reqbufs(struct soc_camera_device *icd, - struct v4l2_requestbuffers *p) -{ - int i; - - /* - * This is for locking debugging only. I removed spinlocks and now I - * check whether .prepare is ever called on a linked buffer, or whether - * a dma IRQ can occur for an in-work or unlinked buffer. Until now - * it hadn't triggered - */ - for (i = 0; i < p->count; i++) { - struct omap1_cam_buf *buf = container_of(icd->vb_vidq.bufs[i], - struct omap1_cam_buf, vb); - buf->inwork = 0; - INIT_LIST_HEAD(&buf->vb.queue); - } - - return 0; -} - -static int omap1_cam_querycap(struct soc_camera_host *ici, - struct v4l2_capability *cap) -{ - /* cap->name is set by the friendly caller:-> */ - strlcpy(cap->card, "OMAP1 Camera", sizeof(cap->card)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - - return 0; -} - -static int omap1_cam_set_bus_param(struct soc_camera_device *icd) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct device *dev = icd->parent; - struct soc_camera_host *ici = to_soc_camera_host(dev); - struct omap1_cam_dev *pcdev = ici->priv; - u32 pixfmt = icd->current_fmt->host_fmt->fourcc; - const struct soc_camera_format_xlate *xlate; - const struct soc_mbus_pixelfmt *fmt; - struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; - unsigned long common_flags; - u32 ctrlclock, mode; - int ret; - - ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); - if (!ret) { - common_flags = soc_mbus_config_compatible(&cfg, SOCAM_BUS_FLAGS); - if (!common_flags) { - dev_warn(dev, - "Flags incompatible: camera 0x%x, host 0x%x\n", - cfg.flags, SOCAM_BUS_FLAGS); - return -EINVAL; - } - } else if (ret != -ENOIOCTLCMD) { - return ret; - } else { - common_flags = SOCAM_BUS_FLAGS; - } - - /* Make choices, possibly based on platform configuration */ - if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && - (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { - if (!pcdev->pdata || - pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING) - common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; - else - common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; - } - - cfg.flags = common_flags; - ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); - if (ret < 0 && ret != -ENOIOCTLCMD) { - dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n", - common_flags, ret); - return ret; - } - - ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); - if (ctrlclock & LCLK_EN) - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); - - if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) { - dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n"); - ctrlclock |= POLCLK; - } else { - dev_dbg(dev, "CTRLCLOCK_REG &= ~POLCLK\n"); - ctrlclock &= ~POLCLK; - } - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); - - if (ctrlclock & LCLK_EN) - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); - - /* select bus endianness */ - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - fmt = xlate->host_fmt; - - mode = CAM_READ(pcdev, MODE) & ~(RAZ_FIFO | IRQ_MASK | DMA); - if (fmt->order == SOC_MBUS_ORDER_LE) { - dev_dbg(dev, "MODE_REG &= ~ORDERCAMD\n"); - CAM_WRITE(pcdev, MODE, mode & ~ORDERCAMD); - } else { - dev_dbg(dev, "MODE_REG |= ORDERCAMD\n"); - CAM_WRITE(pcdev, MODE, mode | ORDERCAMD); - } - - return 0; -} - -static unsigned int omap1_cam_poll(struct file *file, poll_table *pt) -{ - struct soc_camera_device *icd = file->private_data; - struct omap1_cam_buf *buf; - - buf = list_entry(icd->vb_vidq.stream.next, struct omap1_cam_buf, - vb.stream); - - poll_wait(file, &buf->vb.done, pt); - - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - return POLLIN | POLLRDNORM; - - return 0; -} - -static struct soc_camera_host_ops omap1_host_ops = { - .owner = THIS_MODULE, - .add = omap1_cam_add_device, - .remove = omap1_cam_remove_device, - .clock_start = omap1_cam_clock_start, - .clock_stop = omap1_cam_clock_stop, - .get_formats = omap1_cam_get_formats, - .set_crop = omap1_cam_set_crop, - .set_fmt = omap1_cam_set_fmt, - .try_fmt = omap1_cam_try_fmt, - .init_videobuf = omap1_cam_init_videobuf, - .reqbufs = omap1_cam_reqbufs, - .querycap = omap1_cam_querycap, - .set_bus_param = omap1_cam_set_bus_param, - .poll = omap1_cam_poll, -}; - -static int omap1_cam_probe(struct platform_device *pdev) -{ - struct omap1_cam_dev *pcdev; - struct resource *res; - struct clk *clk; - void __iomem *base; - unsigned int irq; - int err = 0; - - irq = platform_get_irq(pdev, 0); - if ((int)irq <= 0) { - err = -ENODEV; - goto exit; - } - - clk = devm_clk_get(&pdev->dev, "armper_ck"); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev) + resource_size(res), - GFP_KERNEL); - if (!pcdev) - return -ENOMEM; - - pcdev->clk = clk; - - pcdev->pdata = pdev->dev.platform_data; - if (pcdev->pdata) { - pcdev->pflags = pcdev->pdata->flags; - pcdev->camexclk = pcdev->pdata->camexclk_khz * 1000; - } - - switch (pcdev->camexclk) { - case 6000000: - case 8000000: - case 9600000: - case 12000000: - case 24000000: - break; - default: - /* pcdev->camexclk != 0 => pcdev->pdata != NULL */ - dev_warn(&pdev->dev, - "Incorrect sensor clock frequency %ld kHz, " - "should be one of 0, 6, 8, 9.6, 12 or 24 MHz, " - "please correct your platform data\n", - pcdev->pdata->camexclk_khz); - pcdev->camexclk = 0; - case 0: - dev_info(&pdev->dev, "Not providing sensor clock\n"); - } - - INIT_LIST_HEAD(&pcdev->capture); - spin_lock_init(&pcdev->lock); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - pcdev->irq = irq; - pcdev->base = base; - - sensor_reset(pcdev, true); - - err = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, DRIVER_NAME, - dma_isr, (void *)pcdev, &pcdev->dma_ch); - if (err < 0) { - dev_err(&pdev->dev, "Can't request DMA for OMAP1 Camera\n"); - return -EBUSY; - } - dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_ch); - - /* preconfigure DMA */ - omap_set_dma_src_params(pcdev->dma_ch, OMAP_DMA_PORT_TIPB, - OMAP_DMA_AMODE_CONSTANT, res->start + REG_CAMDATA, - 0, 0); - omap_set_dma_dest_burst_mode(pcdev->dma_ch, OMAP_DMA_DATA_BURST_4); - /* setup DMA autoinitialization */ - omap_dma_link_lch(pcdev->dma_ch, pcdev->dma_ch); - - err = devm_request_irq(&pdev->dev, pcdev->irq, cam_isr, 0, DRIVER_NAME, - pcdev); - if (err) { - dev_err(&pdev->dev, "Camera interrupt register failed\n"); - goto exit_free_dma; - } - - pcdev->soc_host.drv_name = DRIVER_NAME; - pcdev->soc_host.ops = &omap1_host_ops; - pcdev->soc_host.priv = pcdev; - pcdev->soc_host.v4l2_dev.dev = &pdev->dev; - pcdev->soc_host.nr = pdev->id; - - err = soc_camera_host_register(&pcdev->soc_host); - if (err) - return err; - - dev_info(&pdev->dev, "OMAP1 Camera Interface driver loaded\n"); - - return 0; - -exit_free_dma: - omap_free_dma(pcdev->dma_ch); -exit: - return err; -} - -static int omap1_cam_remove(struct platform_device *pdev) -{ - struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); - struct omap1_cam_dev *pcdev = container_of(soc_host, - struct omap1_cam_dev, soc_host); - - omap_free_dma(pcdev->dma_ch); - - soc_camera_host_unregister(soc_host); - - dev_info(&pdev->dev, "OMAP1 Camera Interface driver unloaded\n"); - - return 0; -} - -static struct platform_driver omap1_cam_driver = { - .driver = { - .name = DRIVER_NAME, - }, - .probe = omap1_cam_probe, - .remove = omap1_cam_remove, -}; - -module_platform_driver(omap1_cam_driver); - -module_param(sg_mode, bool, 0644); -MODULE_PARM_DESC(sg_mode, "videobuf mode, 0: dma-contig (default), 1: dma-sg"); - -MODULE_DESCRIPTION("OMAP1 Camera Interface driver"); -MODULE_AUTHOR("Janusz Krzysztofik "); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION(DRIVER_VERSION); -MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/staging/media/timb/Kconfig b/drivers/staging/media/timb/Kconfig deleted file mode 100644 index e413fecc1..000000000 --- a/drivers/staging/media/timb/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config VIDEO_TIMBERDALE - tristate "Support for timberdale Video In/LogiWIN" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && HAS_DMA - depends on (MFD_TIMBERDALE && TIMB_DMA) || COMPILE_TEST - select VIDEO_ADV7180 - select VIDEOBUF_DMA_CONTIG - ---help--- - Add support for the Video In peripherial of the timberdale FPGA. - - This driver is deprecated and will be removed soon unless someone - will start the work to convert this driver to the vb2 framework. diff --git a/drivers/staging/media/timb/Makefile b/drivers/staging/media/timb/Makefile deleted file mode 100644 index 4c989c23a..000000000 --- a/drivers/staging/media/timb/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o diff --git a/drivers/staging/media/timb/timblogiw.c b/drivers/staging/media/timb/timblogiw.c deleted file mode 100644 index 113c9f3c0..000000000 --- a/drivers/staging/media/timb/timblogiw.c +++ /dev/null @@ -1,870 +0,0 @@ -/* - * timblogiw.c timberdale FPGA LogiWin Video In driver - * Copyright (c) 2009-2010 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ - -/* Supports: - * Timberdale FPGA LogiWin Video In - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_NAME "timb-video" - -#define TIMBLOGIWIN_NAME "Timberdale Video-In" -#define TIMBLOGIW_VERSION_CODE 0x04 - -#define TIMBLOGIW_LINES_PER_DESC 44 -#define TIMBLOGIW_MAX_VIDEO_MEM 16 - -#define TIMBLOGIW_HAS_DECODER(lw) (lw->pdata.encoder.module_name) - - -struct timblogiw { - struct video_device video_dev; - struct v4l2_device v4l2_dev; /* mutual exclusion */ - struct mutex lock; - struct device *dev; - struct timb_video_platform_data pdata; - struct v4l2_subdev *sd_enc; /* encoder */ - bool opened; -}; - -struct timblogiw_tvnorm { - v4l2_std_id std; - u16 width; - u16 height; - u8 fps; -}; - -struct timblogiw_fh { - struct videobuf_queue vb_vidq; - struct timblogiw_tvnorm const *cur_norm; - struct list_head capture; - struct dma_chan *chan; - spinlock_t queue_lock; /* mutual exclusion */ - unsigned int frame_count; -}; - -struct timblogiw_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - struct scatterlist sg[16]; - dma_cookie_t cookie; - struct timblogiw_fh *fh; -}; - -static const struct timblogiw_tvnorm timblogiw_tvnorms[] = { - { - .std = V4L2_STD_PAL, - .width = 720, - .height = 576, - .fps = 25 - }, - { - .std = V4L2_STD_NTSC, - .width = 720, - .height = 480, - .fps = 30 - } -}; - -static int timblogiw_bytes_per_line(const struct timblogiw_tvnorm *norm) -{ - return norm->width * 2; -} - - -static int timblogiw_frame_size(const struct timblogiw_tvnorm *norm) -{ - return norm->height * timblogiw_bytes_per_line(norm); -} - -static const struct timblogiw_tvnorm *timblogiw_get_norm(const v4l2_std_id std) -{ - int i; - for (i = 0; i < ARRAY_SIZE(timblogiw_tvnorms); i++) - if (timblogiw_tvnorms[i].std & std) - return timblogiw_tvnorms + i; - - /* default to first element */ - return timblogiw_tvnorms; -} - -static void timblogiw_dma_cb(void *data) -{ - struct timblogiw_buffer *buf = data; - struct timblogiw_fh *fh = buf->fh; - struct videobuf_buffer *vb = &buf->vb; - - spin_lock(&fh->queue_lock); - - /* mark the transfer done */ - buf->cookie = -1; - - fh->frame_count++; - - if (vb->state != VIDEOBUF_ERROR) { - list_del(&vb->queue); - v4l2_get_timestamp(&vb->ts); - vb->field_count = fh->frame_count * 2; - vb->state = VIDEOBUF_DONE; - - wake_up(&vb->done); - } - - if (!list_empty(&fh->capture)) { - vb = list_entry(fh->capture.next, struct videobuf_buffer, - queue); - vb->state = VIDEOBUF_ACTIVE; - } - - spin_unlock(&fh->queue_lock); -} - -static bool timblogiw_dma_filter_fn(struct dma_chan *chan, void *filter_param) -{ - return chan->chan_id == (uintptr_t)filter_param; -} - -/* IOCTL functions */ - -static int timblogiw_g_fmt(struct file *file, void *priv, - struct v4l2_format *format) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw *lw = video_get_drvdata(vdev); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s entry\n", __func__); - - if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - mutex_lock(&lw->lock); - - format->fmt.pix.width = fh->cur_norm->width; - format->fmt.pix.height = fh->cur_norm->height; - format->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; - format->fmt.pix.bytesperline = timblogiw_bytes_per_line(fh->cur_norm); - format->fmt.pix.sizeimage = timblogiw_frame_size(fh->cur_norm); - format->fmt.pix.field = V4L2_FIELD_NONE; - - mutex_unlock(&lw->lock); - - return 0; -} - -static int timblogiw_try_fmt(struct file *file, void *priv, - struct v4l2_format *format) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_pix_format *pix = &format->fmt.pix; - - dev_dbg(&vdev->dev, - "%s - width=%d, height=%d, pixelformat=%d, field=%d\n" - "bytes per line %d, size image: %d, colorspace: %d\n", - __func__, - pix->width, pix->height, pix->pixelformat, pix->field, - pix->bytesperline, pix->sizeimage, pix->colorspace); - - if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (pix->field != V4L2_FIELD_NONE) - return -EINVAL; - - if (pix->pixelformat != V4L2_PIX_FMT_UYVY) - return -EINVAL; - - return 0; -} - -static int timblogiw_s_fmt(struct file *file, void *priv, - struct v4l2_format *format) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw *lw = video_get_drvdata(vdev); - struct timblogiw_fh *fh = priv; - struct v4l2_pix_format *pix = &format->fmt.pix; - int err; - - mutex_lock(&lw->lock); - - err = timblogiw_try_fmt(file, priv, format); - if (err) - goto out; - - if (videobuf_queue_is_busy(&fh->vb_vidq)) { - dev_err(&vdev->dev, "%s queue busy\n", __func__); - err = -EBUSY; - goto out; - } - - pix->width = fh->cur_norm->width; - pix->height = fh->cur_norm->height; - -out: - mutex_unlock(&lw->lock); - return err; -} - -static int timblogiw_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct video_device *vdev = video_devdata(file); - - dev_dbg(&vdev->dev, "%s: Entry\n", __func__); - strncpy(cap->card, TIMBLOGIWIN_NAME, sizeof(cap->card)-1); - strncpy(cap->driver, DRIVER_NAME, sizeof(cap->driver) - 1); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", vdev->name); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - - return 0; -} - -static int timblogiw_enum_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - struct video_device *vdev = video_devdata(file); - - dev_dbg(&vdev->dev, "%s, index: %d\n", __func__, fmt->index); - - if (fmt->index != 0) - return -EINVAL; - memset(fmt, 0, sizeof(*fmt)); - fmt->index = 0; - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strncpy(fmt->description, "4:2:2, packed, YUYV", - sizeof(fmt->description)-1); - fmt->pixelformat = V4L2_PIX_FMT_UYVY; - - return 0; -} - -static int timblogiw_g_parm(struct file *file, void *priv, - struct v4l2_streamparm *sp) -{ - struct timblogiw_fh *fh = priv; - struct v4l2_captureparm *cp = &sp->parm.capture; - - cp->capability = V4L2_CAP_TIMEPERFRAME; - cp->timeperframe.numerator = 1; - cp->timeperframe.denominator = fh->cur_norm->fps; - - return 0; -} - -static int timblogiw_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - return videobuf_reqbufs(&fh->vb_vidq, rb); -} - -static int timblogiw_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - return videobuf_querybuf(&fh->vb_vidq, b); -} - -static int timblogiw_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - return videobuf_qbuf(&fh->vb_vidq, b); -} - -static int timblogiw_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK); -} - -static int timblogiw_g_std(struct file *file, void *priv, v4l2_std_id *std) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - *std = fh->cur_norm->std; - return 0; -} - -static int timblogiw_s_std(struct file *file, void *priv, v4l2_std_id std) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw *lw = video_get_drvdata(vdev); - struct timblogiw_fh *fh = priv; - int err = 0; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - mutex_lock(&lw->lock); - - if (TIMBLOGIW_HAS_DECODER(lw)) - err = v4l2_subdev_call(lw->sd_enc, video, s_std, std); - - if (!err) - fh->cur_norm = timblogiw_get_norm(std); - - mutex_unlock(&lw->lock); - - return err; -} - -static int timblogiw_enuminput(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct video_device *vdev = video_devdata(file); - int i; - - dev_dbg(&vdev->dev, "%s: Entry\n", __func__); - - if (inp->index != 0) - return -EINVAL; - - inp->index = 0; - - strncpy(inp->name, "Timb input 1", sizeof(inp->name) - 1); - inp->type = V4L2_INPUT_TYPE_CAMERA; - - inp->std = 0; - for (i = 0; i < ARRAY_SIZE(timblogiw_tvnorms); i++) - inp->std |= timblogiw_tvnorms[i].std; - - return 0; -} - -static int timblogiw_g_input(struct file *file, void *priv, - unsigned int *input) -{ - struct video_device *vdev = video_devdata(file); - - dev_dbg(&vdev->dev, "%s: Entry\n", __func__); - - *input = 0; - - return 0; -} - -static int timblogiw_s_input(struct file *file, void *priv, unsigned int input) -{ - struct video_device *vdev = video_devdata(file); - - dev_dbg(&vdev->dev, "%s: Entry\n", __func__); - - if (input != 0) - return -EINVAL; - return 0; -} - -static int timblogiw_streamon(struct file *file, void *priv, enum v4l2_buf_type type) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_dbg(&vdev->dev, "%s - No capture device\n", __func__); - return -EINVAL; - } - - fh->frame_count = 0; - return videobuf_streamon(&fh->vb_vidq); -} - -static int timblogiw_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s entry\n", __func__); - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - return videobuf_streamoff(&fh->vb_vidq); -} - -static int timblogiw_querystd(struct file *file, void *priv, v4l2_std_id *std) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw *lw = video_get_drvdata(vdev); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s entry\n", __func__); - - if (TIMBLOGIW_HAS_DECODER(lw)) - return v4l2_subdev_call(lw->sd_enc, video, querystd, std); - else { - *std = fh->cur_norm->std; - return 0; - } -} - -static int timblogiw_enum_framesizes(struct file *file, void *priv, - struct v4l2_frmsizeenum *fsize) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s - index: %d, format: %d\n", __func__, - fsize->index, fsize->pixel_format); - - if ((fsize->index != 0) || - (fsize->pixel_format != V4L2_PIX_FMT_UYVY)) - return -EINVAL; - - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = fh->cur_norm->width; - fsize->discrete.height = fh->cur_norm->height; - - return 0; -} - -/* Video buffer functions */ - -static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct timblogiw_fh *fh = vq->priv_data; - - *size = timblogiw_frame_size(fh->cur_norm); - - if (!*count) - *count = 32; - - while (*size * *count > TIMBLOGIW_MAX_VIDEO_MEM * 1024 * 1024) - (*count)--; - - return 0; -} - -static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct timblogiw_fh *fh = vq->priv_data; - struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer, - vb); - unsigned int data_size = timblogiw_frame_size(fh->cur_norm); - int err = 0; - - if (vb->baddr && vb->bsize < data_size) - /* User provided buffer, but it is too small */ - return -ENOMEM; - - vb->size = data_size; - vb->width = fh->cur_norm->width; - vb->height = fh->cur_norm->height; - vb->field = field; - - if (vb->state == VIDEOBUF_NEEDS_INIT) { - int i; - unsigned int size; - unsigned int bytes_per_desc = TIMBLOGIW_LINES_PER_DESC * - timblogiw_bytes_per_line(fh->cur_norm); - dma_addr_t addr; - - sg_init_table(buf->sg, ARRAY_SIZE(buf->sg)); - - err = videobuf_iolock(vq, vb, NULL); - if (err) - goto err; - - addr = videobuf_to_dma_contig(vb); - for (i = 0, size = 0; size < data_size; i++) { - sg_dma_address(buf->sg + i) = addr + size; - size += bytes_per_desc; - sg_dma_len(buf->sg + i) = (size > data_size) ? - (bytes_per_desc - (size - data_size)) : - bytes_per_desc; - } - - vb->state = VIDEOBUF_PREPARED; - buf->cookie = -1; - buf->fh = fh; - } - - return 0; - -err: - videobuf_dma_contig_free(vq, vb); - vb->state = VIDEOBUF_NEEDS_INIT; - return err; -} - -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct timblogiw_fh *fh = vq->priv_data; - struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer, - vb); - struct dma_async_tx_descriptor *desc; - int sg_elems; - int bytes_per_desc = TIMBLOGIW_LINES_PER_DESC * - timblogiw_bytes_per_line(fh->cur_norm); - - sg_elems = timblogiw_frame_size(fh->cur_norm) / bytes_per_desc; - sg_elems += - (timblogiw_frame_size(fh->cur_norm) % bytes_per_desc) ? 1 : 0; - - if (list_empty(&fh->capture)) - vb->state = VIDEOBUF_ACTIVE; - else - vb->state = VIDEOBUF_QUEUED; - - list_add_tail(&vb->queue, &fh->capture); - - spin_unlock_irq(&fh->queue_lock); - - desc = dmaengine_prep_slave_sg(fh->chan, - buf->sg, sg_elems, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT); - if (!desc) { - spin_lock_irq(&fh->queue_lock); - list_del_init(&vb->queue); - vb->state = VIDEOBUF_PREPARED; - return; - } - - desc->callback_param = buf; - desc->callback = timblogiw_dma_cb; - - buf->cookie = desc->tx_submit(desc); - - spin_lock_irq(&fh->queue_lock); -} - -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct timblogiw_fh *fh = vq->priv_data; - struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer, - vb); - - videobuf_waiton(vq, vb, 0, 0); - if (buf->cookie >= 0) - dma_sync_wait(fh->chan, buf->cookie); - - videobuf_dma_contig_free(vq, vb); - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static struct videobuf_queue_ops timblogiw_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* Device Operations functions */ - -static int timblogiw_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw *lw = video_get_drvdata(vdev); - struct timblogiw_fh *fh; - v4l2_std_id std; - dma_cap_mask_t mask; - int err = 0; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - mutex_lock(&lw->lock); - if (lw->opened) { - err = -EBUSY; - goto out; - } - - if (TIMBLOGIW_HAS_DECODER(lw) && !lw->sd_enc) { - struct i2c_adapter *adapt; - - /* find the video decoder */ - adapt = i2c_get_adapter(lw->pdata.i2c_adapter); - if (!adapt) { - dev_err(&vdev->dev, "No I2C bus #%d\n", - lw->pdata.i2c_adapter); - err = -ENODEV; - goto out; - } - - /* now find the encoder */ - lw->sd_enc = v4l2_i2c_new_subdev_board(&lw->v4l2_dev, adapt, - lw->pdata.encoder.info, NULL); - - i2c_put_adapter(adapt); - - if (!lw->sd_enc) { - dev_err(&vdev->dev, "Failed to get encoder: %s\n", - lw->pdata.encoder.module_name); - err = -ENODEV; - goto out; - } - } - - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (!fh) { - err = -ENOMEM; - goto out; - } - - fh->cur_norm = timblogiw_tvnorms; - timblogiw_querystd(file, fh, &std); - fh->cur_norm = timblogiw_get_norm(std); - - INIT_LIST_HEAD(&fh->capture); - spin_lock_init(&fh->queue_lock); - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - dma_cap_set(DMA_PRIVATE, mask); - - /* find the DMA channel */ - fh->chan = dma_request_channel(mask, timblogiw_dma_filter_fn, - (void *)(uintptr_t)lw->pdata.dma_channel); - if (!fh->chan) { - dev_err(&vdev->dev, "Failed to get DMA channel\n"); - kfree(fh); - err = -ENODEV; - goto out; - } - - file->private_data = fh; - videobuf_queue_dma_contig_init(&fh->vb_vidq, - &timblogiw_video_qops, lw->dev, &fh->queue_lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, - sizeof(struct timblogiw_buffer), fh, NULL); - - lw->opened = true; -out: - mutex_unlock(&lw->lock); - - return err; -} - -static int timblogiw_close(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw *lw = video_get_drvdata(vdev); - struct timblogiw_fh *fh = file->private_data; - - dev_dbg(&vdev->dev, "%s: Entry\n", __func__); - - videobuf_stop(&fh->vb_vidq); - videobuf_mmap_free(&fh->vb_vidq); - - dma_release_channel(fh->chan); - - kfree(fh); - - mutex_lock(&lw->lock); - lw->opened = false; - mutex_unlock(&lw->lock); - return 0; -} - -static ssize_t timblogiw_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = file->private_data; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, - file->f_flags & O_NONBLOCK); -} - -static unsigned int timblogiw_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = file->private_data; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - return videobuf_poll_stream(file, &fh->vb_vidq, wait); -} - -static int timblogiw_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = file->private_data; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - return videobuf_mmap_mapper(&fh->vb_vidq, vma); -} - -/* Platform device functions */ - -static struct v4l2_ioctl_ops timblogiw_ioctl_ops = { - .vidioc_querycap = timblogiw_querycap, - .vidioc_enum_fmt_vid_cap = timblogiw_enum_fmt, - .vidioc_g_fmt_vid_cap = timblogiw_g_fmt, - .vidioc_try_fmt_vid_cap = timblogiw_try_fmt, - .vidioc_s_fmt_vid_cap = timblogiw_s_fmt, - .vidioc_g_parm = timblogiw_g_parm, - .vidioc_reqbufs = timblogiw_reqbufs, - .vidioc_querybuf = timblogiw_querybuf, - .vidioc_qbuf = timblogiw_qbuf, - .vidioc_dqbuf = timblogiw_dqbuf, - .vidioc_g_std = timblogiw_g_std, - .vidioc_s_std = timblogiw_s_std, - .vidioc_enum_input = timblogiw_enuminput, - .vidioc_g_input = timblogiw_g_input, - .vidioc_s_input = timblogiw_s_input, - .vidioc_streamon = timblogiw_streamon, - .vidioc_streamoff = timblogiw_streamoff, - .vidioc_querystd = timblogiw_querystd, - .vidioc_enum_framesizes = timblogiw_enum_framesizes, -}; - -static struct v4l2_file_operations timblogiw_fops = { - .owner = THIS_MODULE, - .open = timblogiw_open, - .release = timblogiw_close, - .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .mmap = timblogiw_mmap, - .read = timblogiw_read, - .poll = timblogiw_poll, -}; - -static struct video_device timblogiw_template = { - .name = TIMBLOGIWIN_NAME, - .fops = &timblogiw_fops, - .ioctl_ops = &timblogiw_ioctl_ops, - .release = video_device_release_empty, - .minor = -1, - .tvnorms = V4L2_STD_PAL | V4L2_STD_NTSC -}; - -static int timblogiw_probe(struct platform_device *pdev) -{ - int err; - struct timblogiw *lw = NULL; - struct timb_video_platform_data *pdata = pdev->dev.platform_data; - - if (!pdata) { - dev_err(&pdev->dev, "No platform data\n"); - err = -EINVAL; - goto err; - } - - if (!pdata->encoder.module_name) - dev_info(&pdev->dev, "Running without decoder\n"); - - lw = devm_kzalloc(&pdev->dev, sizeof(*lw), GFP_KERNEL); - if (!lw) { - err = -ENOMEM; - goto err; - } - - if (pdev->dev.parent) - lw->dev = pdev->dev.parent; - else - lw->dev = &pdev->dev; - - memcpy(&lw->pdata, pdata, sizeof(lw->pdata)); - - mutex_init(&lw->lock); - - lw->video_dev = timblogiw_template; - - strlcpy(lw->v4l2_dev.name, DRIVER_NAME, sizeof(lw->v4l2_dev.name)); - err = v4l2_device_register(NULL, &lw->v4l2_dev); - if (err) - goto err; - - lw->video_dev.v4l2_dev = &lw->v4l2_dev; - - platform_set_drvdata(pdev, lw); - video_set_drvdata(&lw->video_dev, lw); - - err = video_register_device(&lw->video_dev, VFL_TYPE_GRABBER, 0); - if (err) { - dev_err(&pdev->dev, "Error reg video: %d\n", err); - goto err_request; - } - - return 0; - -err_request: - v4l2_device_unregister(&lw->v4l2_dev); -err: - dev_err(&pdev->dev, "Failed to register: %d\n", err); - - return err; -} - -static int timblogiw_remove(struct platform_device *pdev) -{ - struct timblogiw *lw = platform_get_drvdata(pdev); - - video_unregister_device(&lw->video_dev); - - v4l2_device_unregister(&lw->v4l2_dev); - - return 0; -} - -static struct platform_driver timblogiw_platform_driver = { - .driver = { - .name = DRIVER_NAME, - }, - .probe = timblogiw_probe, - .remove = timblogiw_remove, -}; - -module_platform_driver(timblogiw_platform_driver); - -MODULE_DESCRIPTION(TIMBLOGIWIN_NAME); -MODULE_AUTHOR("Pelagicore AB "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:"DRIVER_NAME); -- cgit v1.2.3-54-g00ecf